第6回 redirect_to と url_for
2008/02/24
今回は、redirect_to
メソッドと url_for
メソッドについて。REST と関係のある話です。
まず、単純な User
モデルのための scaffold を作ります。
ruby script/generate scaffold user name:string
app/controllers/users_controller.rb
の create
アクションは次のようになります。
# POST /users # POST /users.xml def create @user = User.new(params[:user]) respond_to do |format| if @user.save flash[:notice] = 'User was successfully created.' format.html { redirect_to(@user) } format.xml { render :xml => @user, :status => :created, :location => @user } else format.html { render :action => "new" } format.xml { render :xml => @user.errors, :status => :unprocessable_entity } end end end
format.html { redirect_to(@user) }
の行に注目してください。redirect_to
の引数に ActiveRecord オブジェクトが渡されています。Rails 1.2.x ではこのような書き方はできませんでした。同じことをするなら format.html { redirect_to user_url(@user) }
と書く必要がありました。これは進歩ですね。
Rails のソースコードを見てみることにしましょう。
まずは、Rails 1.2.6 (actionpack-1.13.6) のコードから。
def redirect_to(options = {}, *parameters_for_method_reference) #:doc: case options when %r{^\w+://.*} # (省略) when String # (省略) when :back # (省略) else if parameters_for_method_reference.empty? redirect_to(url_for(options)) response.redirected_to = options else # (省略) end end end
引数に ActiveRecord オブジェクトを渡した場合、redirect_to(url_for(options))
が実行されます。しかし、Rails 1.2.6 の url_for
メソッドは ActiveRecord オブジェクトを処理できません。
続いて、Rails 2.0.2 (actionpack-2.0.2) のコード。
def redirect_to(options = {}, response_status = {}) #:doc: # (省略) case options when %r{^\w+://.*} # (省略) when String # (省略) when :back # (省略) when Hash # (省略) else redirect_to(url_for(options), :status=>status) end end
引数に ActiveRecord オブジェクトを渡した場合、最後の redirect_to(url_for(options), :status=>status)
が実行されます。url_for
メソッドで URL を作っています。
では、url_for
メソッドを見てみましょう。
def url_for(options = nil) #:doc: case options || {} when String options when Hash @url.rewrite(rewrite_options(options)) else polymorphic_url(options) end end
引数 options
に ActiveRecord オブジェクトを渡したわけですから、else 節の polymorphic_url(options)
が実行されます。
このメソッドが定義されているのは、polymorphic_routes.rb
です。
def polymorphic_url(record_or_hash_or_array, options = {}) # (省略) named_route = build_named_route_call(record_or_hash_or_array, namespace, inflection, options) send!(named_route, *args) end
下から3行目の build_named_route_call
メソッドは、'user_url' という文字列を返します。redirect_to user_url(@user)
を redirect_to(@user)
と短くするために、随分とがんばったものです。お疲れ様!