Railsでモデル名とコントローラ名が異なる時にparamsで渡すパラメータ値
コントローラー名とモデル名が異なる時のルートパスでつまずいたので、忘れないようにメモ。
前提条件
コントローラー名①: UsersController
コントローラー名②: DatasController
モデル①: HouseModel (has_many :datasets)
モデル②: DatasetModel (belongs_to :house)
各houseデータは複数のdatasetでーたを持っているため、Datasetモデルはhouse_idで繋がっている。
まずやってみたこと
今回は複数のuserが各々dataを持っており、各userページでdataを表示させるのが目標。
そのためコントローラーをネストさせる必要がある。
config/routes.rb
Rails.application.routes.draw do root "users#index" resources :users, only: [:index] do resources :datas, only: [:index] end end
DBに作成したモデルはベースとなるcsvファイルがあったので、UserテーブルではなくHouseテーブルとなってる。
index.html.hamlでは一覧を表示したかったので、モデルから全データを取得しておく。
app/controllers/users_controller
class UsersController < ApplicationController def index @houses = House.all end end
続いてdataの方に飛ばすためのcontrollerを設定
app/controllers/datas_controller
class DatasController < ApplicationController before_action :set_house, only: [:index] def index end private def set_house @house = House.find(params[:id]) end end
一覧を表示させるようにhamlファイルを作成。
今回は一覧表示が目標なので、表形式の表示をさせるためtableを使用する。
名前を押したらユーザーのデータを表示するようにしたいので、link_toは名前のところに設定。
app/views/users/index.html.haml
%table %thead %tr %th No. %th Family Name %tbody - @houses.each do |house| %tr %td =house.id %td = link_to user_datas_path(id: house.id) do =house.Lastname
さて、これでサーバーを立ち上げて確認しようとするとerror...
間違い箇所
エラーの中身を読み解いてみると間違えてた場所がわかった。
= link_to user_datas_path(id: house.id) do
ここでid:は無くて、user_idじゃね?って出てきた。
というわけでさっそく変更
= link_to user_datas_path(user_id: house.id) do
paramsで受け取る方も合わせて変更する必要があるので修正
app/controllers/datas_controller
class DatasController < ApplicationController before_action :set_house, only: [:index] def index end private def set_house @house = House.find(params[:user_id]) end end
とりあえず流れた!
コードの読みやすさを考える
うーん…Houseモデルを使ってるのにuser_idの値を入れるっていうのが非常にわかりづらい…
というわけで結局UsersControllerをHousesControllerに名前を変えることに。
config/routes.rb
Rails.application.routes.draw do root "houses#index" resources :houses, only: [:index] do resources :datas, only: [:index] end end
app/views/houses/index.html.haml
%table %thead %tr %th No. %th Family Name %tbody - @houses.each do |house| %tr %td =house.id %td = link_to house_datas_path(house_id: house.id) do =house.Lastname
app/controllers/datas_controller
class DatasController < ApplicationController before_action :set_house, only: [:index] def index end private def set_house @house = House.find(params[:house_id]) end end
これで
- モデル名とコントローラ名が一致してわかりやすい
- paramsで渡す値が'house_id'となって、Datasetテーブルのカラム名とも一致してわかりやすい
といいことづくめに。
まとめ
モデル名とコントローラ名は同じものにしておいた方が、データのやり取りをするときわかりやすい。
実際のurlの見栄えを考えて別名にすることもあるので、そういう時は今回のような対応をすればOK!