LoginSignup
529
504

More than 5 years have passed since last update.

redirect_to の引数とかのメモ

Last updated at Posted at 2014-06-05

基本

ドキュメントにある使用方法(よくある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

書いてて、「むむむ…」となるコードだった
三項演算子使った方が良かったのか迷うところ

参考

529
504
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
529
504