Edited at

redirect_to の引数とかのメモ

More than 3 years have passed since last update.


基本


ドキュメントにある使用方法(よくあるusers_controllerがあるとして)

# URLへリダイレクト(アクションはconfig/routes.rbを参照)

redirect_to URL
# indexアクションへリダイレクト
redirect_to action: 'index'
# usersコントローラのindexアクションへリダイレクト
redirect_to controller: 'users', action: 'index'
# usersコントローラーのshowアクションのid=8へリダイレクト
redirect_to controller: 'users', action: 'show', id: 8
# 前ページへリダイレクト
redirect_to :back
# indexアクションへstatusコード404でリダイレクト
redirect_to action: 'index', status: 404
# indexアクションへstatusコード200でリダイレクト(シンボル使用)
redirect_to action: 'index', status: :ok
# indexアクションへオプション(エラーメッセージ)付きでリダイレクト
redirect_to action: 'index', alert: 'ERROR!!'
# indexアクションへオプション(通知用メッセージ)付きでリダイレクト
redirect_to ({:action => 'index'}), :notice => 'message'
# indexアクションへオプション(一時的なメッセージ)付きでリダイレクト
redirect_to action: 'index', flash: {success: 'Yes!! Success'}


redirect_to Modelオブジェクト


こんな感じのroutesの時

$ rake routes(or bundle exec rake routes)


model GET /users/:id(.:format) users#show


これが疑問だった


users_controller.rb

redirect_to @user



以下と挙動が一緒っぽい

redirect_to "/users/#{@user.id}" # 条件付き(後述)

or
redirect_to user_url(id: @user.to_param)
or
redirect_to user_url(id: @user.id)


to_paramsメソッド

Modelオブジェクトのto_paramメソッドは基本idを返す(オーバーライドしてid以外を返すのもよくあるらしい)


注意その1:Modelオブジェクトが返すURL?はuser_url(〇〇)のやつで"/users/#{@user.id}"ではない

上記では redirect_to "/usrs/#{@user.id}" と一緒の挙動するとかある。

しかし、 config/routes.rbresources を使用している場合だけ…っぽい。

resources を使用せずに1つ1つ指定していて、usr_urlがないならできない。

undefined method `user_url' ...

的な感じで怒られる(た)。


注意その2:redirect_toでPOSTはできない

だからRailsチュートリアルではshowメソッドをPOSTにしないで、before_actionで工夫を加えていたのかなぁと解釈


追記

以下のような引数の時で、チュートリアルにもある redirect_back_or(default) を実装したい


app/controller/sessions_controller.rb

#…(略

redirect_to controller: :users, action: :show, id: user.id
#…(略

ソース側の引数を見ると


app/helpers/sessions_helper.rb

# File actionpack/lib/action_controller/metal/redirecting.rb, line 65

def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body

self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
end



パッと分かること


  • 引数はHashが2つ(options, response_status)

  • status_codeは結局2つの引数から抽出している

今まで書いてた括弧なしredirecto 〇〇, 〇〇とかはどういう風にメソッド側では見られてたか、rubyを普段から触ってる人にとっては当たり前かもしれないけど、とりあえず書いた


my_redirect.rb

def my_redirect_to(a = {}, b = {})

p a
p b
end

my_redirect_to action: 'index', status: 404
# 結果
#{:action=>"index", :status=>404}
#{}



これからわかること


  • 括弧で覆われてないサンプルは全部optionsに入ってた

引数がHash1つと思って、以下の様なコードにすると怒られる(た)


怒られる例

redirect_to {controller: :users, action: :show, id: user.id}



怒られない例

redirect_to {controller: :users, action: :show, id: user.id}, {}



結局、 redirect_back_or(default) メソッドの実装はどうなるか


sessions_controller.rb

# 変更前

redirect_to controller: :users, action: :show, id: user.id
# 変更後
redirect_back_or controller: :users, action: :show, id: user.id


app/helpers/sessions_helper.rb

# 変更前

def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end

# 変更後
def redirect_back_or(options = {}, response_status = {})
if session[:return_to]
redirect_to session[:return_to]
else
redirect_to options, response_status
end
session.delete(:return_to)
end


書いてて、「むむむ…」となるコードだった

三項演算子使った方が良かったのか迷うところ


参考