はじめに
Rails初学者の私がアソシエーションによってテーブルを関連付けた後、
アクションメソッドへパラメーターを受け渡せずに非常に苦労したので記事にしてみます。
ゴールはPlace(カフェ)にメニュー(menus)の情報を持たせて画面上に出力することです。
※初投稿のため理解しがたい部分、間違っている部分等あるかもしれません。
なるべく正しい情報を記述したいと努力していますがご了承いただければと思います。
コメントでご意見等いただけましたら嬉しいです!
ひとまずPlaceとMenuのカラムを確認
irb(main):005:0> Place.column_names
=> ["id", "name", "message", "created_at", "updated_at", "user_id"]
irb(main):006:0> Menu.column_names
=> ["id", "title", "price", "message", "created_at", "updated_at", "place_id"]
上記の通りとなります。
ログインしているUserがお気に入りのカフェを投稿→そのカフェに対してメニューの情報も追加することができる。
という機能です。
アソシエーションによるテーブルの結合
class Place < ApplicationRecord
belongs_to :user
has_many :menus
end
Railsでは命名規則が重要なのでこの単数形と複数形の記述を間違えないように注意。
(1人の)userに対して(1つの)place、(1つの)placeに対して(複数の)menusを持ちます。
belongs_to (〜に属する) has_many (たくさん持っている)・・・わかりやすいですね!
class Menu < ApplicationRecord
belongs_to :place
end
menu.rbの方はこんな感じ。
とりあえずこれでテーブル間の紐付けは完了しました。
[1] pry(#<PlacesController>)> @place
=> #<Place:0x00007f9d1e88cc10
id: 3,
name: "hoge Coffee",
message: "自宅から最寄りのカフェで落ち着いた雰囲気がとても素敵です。",
created_at: Thu, 18 Jun 2020 00:05:20 UTC +00:00,
updated_at: Thu, 18 Jun 2020 13:14:42 UTC +00:00,
user_id: 1>
[2] pry(#<PlacesController>)> params
=> <ActionController::Parameters {"controller"=>"places", "action"=>"show", "id"=>"3"} permitted: false>
views/places/show.html.erb
からメニューの登録を行いたいのでパラメーターを確認します。
こちらが今回メニューを登録したいカフェの情報になります。
<%= link_to 'メニューを登録', new_menu_path(id: @place.id) %>
メニューの登録をするためにmenus_controllerのnewアクションへ。
この時に_pathヘルパーへ引数を渡しておかないとmenus_controllerのnewアクションでplaceを検索できません。
class MenusController < ApplicationController
def new
@menu = Menu.new
@place = Place.find_by(id: params[:id])
end
(略)
入力フォーム↓
<%= form_with model:@menu, local: true do |f| %>
<h2>メニューを登録</h2>
<p>料理の名前 : <%= f.text_field :title %></p>
<p>Price : <%= f.text_field :price %></p>
<%= f.hidden_field :place_id, :value => @place.id %>
<%= f.submit '登録する' %>
<% end %>
place_idは入力するようなものではないのでhidden_fieldで渡された値を受け取りしてあげます。
createアクションでのplace_idを受け取り方ですがメニューを登録する際の入力フォームで受け取ります。
def create
# 入力フォームで受けとったパラメーターをここで受け取る
@menu = Menu.create(
title: menus_params[:title],
price: menus_params[:price],
place_id: menus_params[:place_id]
)
# ここでちゃんと受け取れているか確認入れてみます
binding.pry
end
(中略)
private
def menus_params
params.require(:menu).permit(:title, :price, :place_id)
end
(略)
確認のためフォームに入力してみます。
結果・・・
[1] pry(#<MenusController>)> menus_params
=> <ActionController::Parameters {"title"=>"アイスコーヒー", "price"=>"280", "place_id"=>"3"} permitted: true>
ちゃんとplace_idを受け取ることができました。
これでちゃんと1対多の関係性(placeに対してmenus)を持ったパラメーターの受け取りができます。
<% @place.menus.each do |menu| %>
<p><%= menu.title %> <%= menu.price %></p>
<% end %>
登録したメニューはこんな感じで出力できます。
[1] pry(#<PlacesController>)> @place.menus
(略)
=> [#<Menu:0x00007ffda376a4c8
id: 37,
title: "チョコレートケーキ",
price: 250,
created_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
updated_at: Thu, 18 Jun 2020 01:36:00 UTC +00:00,
place_id: 3>,
#<Menu:0x00007ffda3773eb0
id: 44,
title: "アイスコーヒー",
price: 280,
created_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
updated_at: Fri, 19 Jun 2020 00:24:50 UTC +00:00,
place_id: 3>]
アソシエーションで紐付けされているので@place.menus
で登録したメニューを確認できます。