読者です 読者をやめる 読者になる 読者になる

Ruby on RailsにおけるController

こんにちは、south37です。焼き肉ブログをはてなグループからはてなブロググループに移行しました。
はてなブロググループはメンバーが自分のはてなブログを登録する形式の様で、その為に僕の完全なる三日坊主だったこのブログが再び息を吹きかえす事となりました。
個人的には、三日坊主がばれちゃうのが恥ずかしいですね。。。

controllerについて

とりあえず今回は、表題にもありますrailsのcontrollerについて説明していきたいと思います。controllerはviewに渡す変数をmodelから受け取ったりviewに渡したりして、何かと調整をしてくれる奴です。

controllerを書く時はscriptを書くのと割と似た感覚になるので、書いてて楽しいっちゃ楽しいです。
railsのcontrollerはurlと対応した名前を持つメソッドを定義し、メソッドの中身として処理を書いていきます(厳密に言えばurlと必ずしも対応させる必要は無いです。そのへんはroutingの話になります)。
とりあえず、以前iPhoneアプリ用にWebAPI的なものを作った際のコードを載せてみます。

class UsersController < ApplicationController
  # GET /users/rank/:id
  def rank
    user = User.find_by_foursq_id params[:id]
    if user
      superior_users = User.find(:all, :conditions => ["area > :area", { :area => user.area }])
      @rank = superior_users.length + 1
      @users_num = User.all.length
    else
      @rank = nil
      @users_num = nil
    end

    render json: { type: :rank, rank_info: { rank: @rank, users_num: @users_num  }}
  end

  # GET /user/update/:id/:name/:area
  def update
    user = User.find_by_foursq_id params[:id]
    user_params = { foursq_id: params[:id], name: params[:name], area: params[:area] }
    
    if ( (user && user.update_attributes(user_params)) || User.new(user_params).save )
      redirect_to action: 'rank', id: params[:id]
    else
      render json: [] 
    end
  end
end

UserControllerという名前のクラスに、メソッドとしてrankやupdateが定義されています。これらのメソッド内の処理は、http://~/users/rank/2やhttp://~/users/update/2/tarou/333にGETでアクセスした際に呼ばれます。メソッドとして定義されていますが、イメージ的には特定のurlを叩かれた時の処理を書いていく、みたいな感じになります。

まずは上のrankについて見ていきましょう。名前の通り、これはあるユーザーのrankを返すWebAPIになります。じつはfoursquareのWebAPIをちょこちょこ使ったiPhoneアプリを作っていた為、foursquareにおけるユーザーidというものを取得することが出来ました。そこでfoursquareのユーザーidをfoursq_idとしてusersテーブルに保存しておき、find_by_foursq_idというメソッドでfoursq_idが渡されたパラメータと一致するuserを取得する事にしました。params[:id]というのがurlとして渡されたfoursq_idです。

尚、find_by_foursq_idというメソッドは本来は定義されていないのですが、rubyのメタプログラミングの力のおかげでちゃんと望む動作をしてくれます。すなわち、find_by_~というメソッドを呼び出すと、その裏では「~」をキーとしてselect文のSQLを発行してくれる訳です。railsでは基本的にはSQLを使わず、modelのメソッドを呼び出すことで裏でSQLが発行されるというのも大きな特徴になります。(尚、このようなRDBとmodelオブジェクトを対応させるようなツールをORMといいます。Object-relational mappingの略称です)

SQLを発行してuserが見つかった場合、userモデルが返ってきます。その後、userのareaが全userの中で何番目に大きなものなのかや全user数を調べ、インスタンス変数に代入しています。その際、findメソッドやallメソッドを使っています。findはいわゆるSELECT文を発行するメソッドで、第一引数の:allで条件に一致する全てを取得するということ、第二引数の:conditionsの部分でWHERE句を指定しています。:conditions中のコードは、areaカラムの値がuser.areaよりも大きいもの、という条件を意味します。何となく感じてもらえれば嬉しいです。

userがnilの時はインスタンス変数にも適当な値を入れて、最後にrender :jsonしています。WebAPIなんでjsonで応答が返るようにしている訳ですが、render :htmlしてやればレンダリングされたviewが返ってきます。通常のWebサイトを作るのであればrender :htmlしてやる事になります。renderメソッドには:jsonをkeyとし、rubyのhash(or array)をvalueとしたものを引数として渡している訳ですが、この場合には適切なjsonを作って返してくれます。また、:jsonのvalueとしてmodelオブジェクトなんかを渡すと、属性がkeyとvalueになったjsonを返してくれたりもします。この辺の心地よさもrailsの魅力の一つです。

rankについてはそんなもんで、updateについても雰囲気を味わってもらえたらいいです。今日はこの辺までです。