演算子 " << "を使ってデータを保存する
いいね機能の実装中、モデルにインスタンスメソッドを定義してて詰まりました。
備忘録です。
前提
Restaurant
モデルに、いいねみたいな行ったよのマークが欲しい。
どのUser
が、 どのRestaurant
にマークを付けるのかという、
多対多の関連付けを実現するために中間モデルを作成した。
usersモデル
とrestaurantsモデル
の中間モデルをvisits
として設定した。
演算子 "<<"を使ってデータを保存
Active Recordの関連付けについて、Railsガイドより
4.3.1.2 collection<<(object, ...)
collection<<メソッドは、1つ以上のオブジェクトをコレクションに追加します。このとき、追加されるオブジェクトの外部キーは、呼び出し側モデルの主キーに設定されます。
@author.books << @book1
(↑のcollection部分には、has_manyの引数として設定しているモデルが書ける)
<<
を使うと中間モデルにidを追加、保存することができる。ただし、引数で渡すオブジェクトは、インスタンスモデルとして渡す。
def メソッド名(オブジェクト)
中間モデル << オブジェクト
end
実装する
行ったボタン
を作成
①ビューで <%= button_to '行った', restaurant_visits_path(restaurant.id), method: :delete, class: "btn btn-sm btn-secondary" %>
※引数の.id
は、書いても書かなくてもコントローラーで取得するparamsの書き方に関係ないけど、分かりやすいので書いた。
link_toだとhttpメソッドがGetになるので、button_toにした。
②モデルにコントローラーのcreateアクションで使う用のメソッドを書く
has_many :visits, dependent: :destroy
has_many :visited_rst, through: :visits, source: :restaurant
~ 省略 ~
def visit(restaurant)
visited_rst << restaurant
end
visited_rst << restaurant
として追加できるものは、Restaurantのインスタンス
注意: 使うときは、current_user.メソッド名(インスタンスモデル)
となる。
current_user.visited_rstで、user_idに紐づいたrestaurant_id
を取ってこれる。
そのrestaurant_id
カラムにrestaurant
を収納できる。
③コントローラー
最初に、ビューのparamsを使って、Restaurantモデルのインスタンスを取得する。
次に、そのインスタンスモデルを引数としてモデルに書いたメソッドに渡す。
class VisitsController < ApplicationController
def create
@restaurants = Restaurant.find(params[:restaurant_id])
current_user.visit(@restaurants)
redirect_to request.referer
end
paramsの中身は、#<ActionController::Parameters {"authenticity_token"=>"CLDyfA_3HEwZr-32DbARQ2IRH7n2GSq--7Xm1bChbxUGhgYema-lUAqAMco92RrrvLaoNodKGUg2GTLR0EcFMw", "controller"=>"visits", "action"=>"create", "restaurant_id"=>"17"} permitted: false>
になっているので、paramsでとりたいものをrestaurant_id
に指定する
演算子 "<<"を使わないパターン
①モデル
~ 省略 ~
def visit(restaurant)
visits.build(restaurant_id: restaurant)
end
コントローラーからは、restaurant_id(キー)の値(バリュー)
が渡されている。
②コントローラー
class VisitsController < ApplicationController
def create
current_user.visit(params[:restaurant_id]).save
redirect_to request.referer
end
end
おわり
試行錯誤してて、なんで、引数の値は"string型の数字"
が入っているのにエラーにならないのか不思議だったけど、create(buld)メソッドは、キーとバリューのセットで保存されるからかな?となった
visited_rst << restaurant
の場合は、current_user_idがあるところに、restaurant_idを追加した感じで、
visits.build(restaurant_id: restaurant)
の場合は、同時に作る感じかしら。
Discussion