Railsで多対多のアソシエーションで中間テーブルに外部キー以外のカラムにアクセスする方法です。
likesテーブルの外部キーは今回の場合user_id
とproduct_id
です。外部キー以外にもlike_typeをもたせています。
このlike_typeカラムですが、0の場合はunlike,1の場合はlikeとして管理したいと思っています。like_typeはenumで管理しています。
今回は各ユーザーがlikeしたproduct一覧を取得しつつ、likesテーブルのlike_typeカラムもviewで表示したいと思います。

テーブル定義
schema.rb
create_table "likes", force: :cascade do |t|
t.integer "product_id", limit: 4, null: false
t.integer "user_id", limit: 4, null: false
t.integer "like_type", limit: 4, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "name", limit: 255, null: false
t.string "email", limit: 255, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "name", limit: 255, null: false
t.text "description", limit: 65535, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
アソシエーション
models/user.rb
class User < ActiveRecord::Base
has_many :likes
has_many :like_products, through: :likes, source: :product
end
models/product.rb
class Product < ActiveRecord::Base
has_many :likes
has_many :like_users, through: :likes, source: :user
end
models/like.rb
class Like < ActiveRecord::Base
belongs_to :product
belongs_to :user
enum like_type: [ :dislike, :like]
end
ルーティング
今回はユーザーがlikeしたproduct一覧を表示するので以下のようなルーティングを設定しています。
routes.rb
resources :users do
member do
get 'likes'
end
end
controller
controller.rb
def likes
@user = User.find(params[:id])
@products = @user.like_products
end
viewでアクセスする方法
each文をネストしています。子ネストでproduct.likesだけにすると親ネストで取得したproductsのidを持つlikesテーブルのレコードをすべて取得してきてしまいます。
そのためwhereで取得してきたいuserを絞り込んでいます。
index.html.erb
<% @products.each do |product| %>
<% product.likes.where(user_id: @user.id).each do |like| %>
<%= product.name %>
<%= like.like_type %>
<% end %>
<% end %>
もっときれいに書きたい
each文をネストしているし、もっとうまく、きれいに書きたいです。他に良い方法をご存知の方がいらっしゃいましたら教えてください!