第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) と短くするために、随分とがんばったものです。お疲れ様!
