Ruby on Rails 遷移元によって条件を変更させる2パターン


プログラミングスクールのチーム開発でECサイトを作成している際、
どこのリンク先から遷移したかでインスタンス変数を変えたい・・・
というような場面がありました。
その時に2パターンの方法があったので、備忘録として残します。

【環境】
Ruby: 2.5.7
Rails: 5.2.4
使用した中で関係するgem:devise(顧客、管理者を作成)

前提条件

  • 管理者側のページで注文一覧を表示する際、下記のように設定したい。
    • トップページから遷移 => 本日作成された注文一覧
    • 顧客の詳細ページから遷移 => その顧客の注文一覧
    • ヘッダーの注文一覧ボタンから遷移 => 全ての注文一覧

テーブル

schema.rb
create_table "orders", force: :cascade do |t|
   t.integer "user_id", null: false
   (略)
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

create_table "users", force: :cascade do |t|
   (略)
  end

モデル(アソシエーション)

user.rb
has_many :orders, dependent: :destroy
order.rb
belongs_to :user

ルート

namespace :admins do
    get '', to: 'products#top'
    resources :users, only: [:index, :show, :edit , :update]
    resources :orders, only: [:index, :show, :update]
end

実装パターン①:遷移元をコントローラで取得する

参考にした記事:Railsで遷移元のコントローラーとアクションを取得する

admins/orders_controller.rb
def index
 path = Rails.application.routes.recognize_path(request.referer)

 # path[:controller]で遷移元コントローラーを、path[:action]でアクションを取得
 if path[:controller] == "admins/products" && path[:action] == "top"
   @orders = Order.where(created_at: Date.today)
  elsif  path[:controller] == "admins/users" && path[:action] == "show"
    @orders = Order.where(user_id: path[:id])
  else 
   @orders = Order.all
  end
end

これで、3パターンの変数を持たせることができました。
ただ、この内容だと【トップ画面からヘッダーの注文履歴ボタンを押した】際、
トップ画面から遷移したと判断されてしまいます。
そのため、最終的には下記の方法で実装を行いました。

実装パターン②:リンク元にパラメーターを付ける

遷移元のリンクページには下記の通りパラメータを持たせました。

admins/products/top.html.erb
 <%= link_to "本日の注文件数", admins_orders_path(order_sort: 0) %>
admins/users/show.html.erb
 <%= link_to "注文一覧", admins_orders_path(order_sort: 1) %>

そしてコントローラ側では、持ってきたパラメーターで変数を振り分け

admins/orders_controller.rb
def index
 case params[:order_sort]
 when "0"
   @orders = Order.where(created_at: Date.today)
 when "1"
   @user = User.find(params[:user_id])
   @orders = @user.orders
 else
   @orders = Order.all
 end
end

これによって①の問題は解消されました。

まとめ

  • ①の方法であればコントローラ側で一目見れば分岐条件がわかりやすいと思うが、状況に応じた実装が求められる。
  • ①の方法を応用すれば、updateやdestroyアクションのリダイレクト先などを分岐させることも可能。