2012年12月5日水曜日

rubymotionとrailsの連携を試行錯誤した話

この記事はRubyMotion Advent Calendar 2012の5日目記事です。

rubymotionメリットのひとつに、サーバサイド(Rails)とクライアントサイドが同じ言語でかけることがあると思いますが、
思いの外Railsとどう連携していくかの情報が少ないような気がします。
なので他の人の参考になればと、個人的に試行錯誤したことを残しておこうと思います。

ちなみに、one minutesというアプリを、rubymotionで作りましたので、よければダウンロードしてください。

試行錯誤1、babble-wrapで都度処理を書く

先述のone minutesでは、表示させるニュース情報をサーバからjsonで取得するだけの単純作業なので、以下の様な感じで実装しました。

BW::HTTP.get(SERVER_URL) do |response|
  if response.ok?
    @data = BW::JSON.parse(response.body.to_str)
  else
    App.alert(response.error_message)
  end
end

実装はかなり楽でしたが、複数情報を取得したい先がある場合や、postを行うときには、かなり面倒なことになってしまいました。
それが↓です。

試行錯誤2、babble-wrapで都度処理を書く(その2)

ソーシャルアプリを作ろうとした際の実装です。
アプリ概要は、facebookみたいなものなので、記事の投稿、投稿に対するコメント、投稿に対するいいね、それぞれを表示させるタイムラインの実装が必要でした。
それが下記コード群です。

#記事読み込み
BubbleWrap::HTTP.get("#{SERVER_URL}/entries.json?page=#{@page}") do |response|
  if response.ok?
    json = BubbleWrap::JSON.parse(response.body.to_str)
    unless json.count == 0
      @table_dates << json
      self.tableView.reloadData
      @page += 1
      @readMoreButton.enabled = true
      @readMoreButton.hidden = false if @page
    else
      @page = nil
      @readMoreButton.hidden = true
    end
  else
    App.alert(response.error_message)
   end
end
#記事投稿
  BubbleWrap::HTTP.post("#{SERVER_URL}/entries.json", {payload: data})
#コメント
 BubbleWrap::HTTP.post("#{SERVER_URL}/comments.json", {payload: data}) do |response|
    if response.ok?
      App.alert("コメントしました")
    elsif response.status_code.to_s =~ /40\d/
     App.alert("comment failed")
    else
     App.alert(response.error_message)
   end
 end
#いいね
BubbleWrap::HTTP.post("#{SERVER_URL}/likes.json", {payload: data}) do |response|
   if response.ok?
      App.alert("likeしました")
    else
     App.alert(response.error_message)
   end
 end

企画自体が没になったため、コレ以上コードは書いていないのですが、
重複が多く、メンテナンス性も非常に悪いものができてしまいました。

で、このあとECアプリを作ることになりました。
これまでの経験を踏まえ、もう少しRailsライクに実装したいと感じるように。

具体的には、
1.new、find、save、allなどで情報が取得や保存ができるように
2.バリデーションエラーは、その内容までも分かるように
3.ネットワークエラーなどがでたら、バリデーションエラーなどとは別に判別できるように

という理想を掲げ、作ってみた現実(ライブラリ)はこちら。
https://github.com/face-do/motion-rails-model

初めて作ったライブラリでもあり、非常にできはよくないのですが、それでも一応の理想は実現できました。
(といっても、babble-wrapのさらにwrapperライブラリだったりしますが。。。)

使い方としては、最初にアクセスしたいURLやbasic認証の情報を入力


    RM::Model.set_url("#{URL}/api/")
    RM::Model.set_username("username")
    RM::Model.set_password("password")

その後モデル用のクラスを作り、ライブラリを継承。

class Orders < RM::Model
  attr_accessor :name
 
  def attributes_update(json)
    @name = json['name']
    super
  end
end

これで、

order = Orders.new
order.name = "hogehoge"
order.save do |x|
  if x.ok?
    App.alert("保存しました。")
  end
end

とかすると、
railsに対して
/api/orders.json?name=hogehoge
のpostメソッドを実行するし、

Orders.find(1) do |x|
  if x.ok?
    @order = x.body
  end
end

で、
/api/orders/1.json
のgetをしたりします。

またgetしてきた、Objectに対してsaveをすると、
/api/orders/1.json
に対してputをするようになってます。

これを作った後、メタプログラミングrubyを読みまして、
もう少し抽象化ができそうな気がしているので、機会を見て修正していく予定です。