こんにちは、鈴木です。
こんなコードを書いてみました。
1 2 3 |
def take_params {:page => params[:page]} end |
よくある商品検索ページを想像していただきたいのですが、「財布」で検索して(いま財布が欲しいんです)、商品一覧が表示されました。
検索にヒットした商品が多いので、商品一覧はページングされています。
794 ページでやっと良さそうな商品を発見したのでクリックして詳細ページを確認します。
他の商品も見たいので「一覧に戻る」リンクを押したら商品一覧の 1 ページに戻ってしまった。
本当は 794 ページを表示していたあの頃に戻りたかったのに、ということがあると思います。
794 ページを表示していたあの頃に戻りたい
おそらく View は以下のように実装されているのかと思います。
1 2 3 4 5 |
# 商品一覧から商品詳細へのリンク. <%= link_to('商品詳細', item_path(item)) %> # 商品詳細から商品一覧へのリンク. <%= link_to('一覧に戻る', items_path) %> |
表示するページ番号が /items?page=794 のように指定されるとすると、以下のように params[:page] をリンク先に引き継いであげる必要があります。
1 2 3 4 5 |
# 商品一覧から商品詳細へのリンク. <%= link_to('商品詳細', item_path(item, :page => params[:page])) %> # 商品詳細から商品一覧へのリンク. <%= link_to('一覧に戻る', items_path(:page => params[:page])) %> |
これで詳細ページから一覧ページに戻ったときに、以前見ていた794ページが表示されるようになります。
とはいえ、急激に面倒くさくなった感があります。
メソッドに切り出してみる
そこで冒頭で紹介した take_params というメソッドです。
take_params を使うと、次のように書くことができます。
1 2 3 4 5 |
# 商品一覧から商品詳細へのリンク. <%= link_to('商品詳細', item_path(item, take_params)) %> # 商品詳細から商品一覧へのリンク. <%= link_to('一覧に戻る', items_path(take_params)) %> |
メソッドにしただけじゃないか、と思われるかもしれませんが、メソッドにしているからこそ変更に強くなります。
例えば、「ページあたりの表示件数 (params[:per_page]) もパラメータで指定されるんだった!」と後から気付いたとします。
そのときは、take_params を以下のように修正するだけで済みます。
1 2 3 4 |
def take_params {:page => params[:page], :per_page => params[:per_page]} end |
「検索条件 (params[:search]) もパラメータで指定されるんだった!」というときは、こうなります。
1 2 3 4 5 |
def take_params {:page => params[:page], :per_page => params[:per_page], :search => params[:search]} end |
メソッドに切り出したことで、変更があっても簡単に対応出来ました。
まとめ
冒頭で紹介した take_params はぱっと見て分かりやすくするためにシンプルな作りにしました。
このままでは若干機能不足ですので、もう少し改良を行いました。
最終的には、take_params 自体を改良し、フォーム(POST)で画面遷移する場合も考慮して take_params_hidden_field_tags というメソッドも作成しました。
take_params は ApplicationController で定義し、View でも使えるように「helper_method :take_params」としています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
class ApplicationController < ActionController::Base # # take_params が params から取り出すキーのデフォルト. # def default_take_param_keys %w(page per_page) end # # 遷移先に引き継ぐパラメータ. # # ==== 詳細 # 以下のようにリンク時のパラメータとして使用されることを想定している. # # link_to('ユーザ一覧', users_path(take_params)) # link_to('ユーザ詳細', user_path(@user, take_params)) # # ==== 引数 # 呼び出し形式は以下の通り. # # (1) take_params # params から default_take_param_keys が返す名前のパラメータを取り出す. # # (2) take_params(:key1, :key2) # params から :key1, :key2 を取り出す. # # (3) take_params(:additional_key1 => 1, :additional_key2 => 2) # params から default_take_param_keys が返す名前のパラメータを取り出す. # その結果に {:additional_key1 => 1, :additional_key2 => 2} をマージする. # # (4) take_params(:key1, :key2, :additional_key1 => 1, :additional_key2 => 2) # params から :key1, :key2 を取り出す. # その結果に {:additional_key1 => 1, :additional_key2 => 2} をマージする. # # ==== 戻り値 # 遷移先に引き継ぐパラメータを保持する Hash. # def take_params(*param_keys) overwrites = param_keys.extract_options! param_keys = default_take_param_keys if param_keys.blank? params.dup.extract!(*param_keys).update(overwrites) end helper_method :take_params end |
デフォルトで引き継ぐパラメータは default_take_param_keys メソッドに分けました(オーバーライドして変更できるようにするためです)。
また、take_params メソッドは、引き継ぐパラメータの名前を明示的に指定することや、追加のパラメータを指定できるように改良しました。
take_params_hidden_field_tags はフォーム(POST)で画面遷移する場合に使用するメソッドで、ApplicationHelper に定義しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
module ApplicationHelper # # 遷移先に引き継ぐパラメータ. # # ==== 詳細 # take_params(*param_keys) の結果を含む <input type="hidden"> を返す. # Ex. '<input type="hidden" ... /><input type="hidden" ... /> ...' # def take_params_hidden_field_tags(*param_keys) tags = take_params(*param_keys).map do |key, value| hidden_field_tag(key, value) end tags.join.html_safe end end |
take_params_hidden_field_tags は take_params の戻り値を単純に <input type="hidden" ... /> に変換します。
使い方は以下のようになります。
1 2 3 4 5 |
<%= form_for(...) do |form| %> ... <%= take_params_hidden_field_tags %> <%= form.submit %> <% end %> |
ベストなやり方かどうかは分かりませんが、このような方法もある、ということをお伝えしました。
Enjoy Rails!