説明する特定の設定では、いくつかのタイプの関連付けが混在しています。
A)ユーザーとレシピ
最初にユーザーモデルがあり、次にレシピモデルがあります。各レシピは1人のユーザーに属しているため、User:has_manyレシピ、レシピbelongs_to:userアソシエーションがあります。この関係は、レシピのuser_idフィールドに保存されます。
$ rails g model Recipe user_id:integer ...
$ rails g model User ...
class Recipe < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :recipes
end
B)FavoriteRecipe
次に、ユーザーがお気に入りのレシピにマークを付けることができるようにするストーリーを実装する方法を決定する必要があります。
これは、:user_id列と:recipe_id列を持つ結合モデル(FavoriteRecipeと呼びましょう)を使用して実行できます。ここで構築しているアソシエーションは、has_many:throughアソシエーションです。
A User
- has_many :favorite_recipes
- has_many :favorites, through: :favorite_recipes, source: :recipe
A Recipe
- has_many :favorite_recipes
- has_many :favorited_by, through: :favorite_recipes, source: :user
# returns the users that favorite a recipe
このお気に入りのhas_manyをモデルに関連付けることで、最終結果が得られます。
$ rails g model FavoriteRecipe recipe_id:integer user_id:integer
# Join model connecting user and favorites
class FavoriteRecipe < ActiveRecord::Base
belongs_to :recipe
belongs_to :user
end
---
class User < ActiveRecord::Base
has_many :recipes
# Favorite recipes of user
has_many :favorite_recipes # just the 'relationships'
has_many :favorites, through: :favorite_recipes, source: :recipe # the actual recipes a user favorites
end
class Recipe < ActiveRecord::Base
belongs_to :user
# Favorited by users
has_many :favorite_recipes # just the 'relationships'
has_many :favorited_by, through: :favorite_recipes, source: :user # the actual users favoriting a recipe
end
C)協会との交流
##
# Association "A"
# Find recipes the current_user created
current_user.recipes
# Create recipe for current_user
current_user.recipes.create!(...)
# Load user that created a recipe
@recipe = Recipe.find(1)
@recipe.user
##
# Association "B"
# Find favorites for current_user
current_user.favorites
# Find which users favorite @recipe
@recipe = Recipe.find(1)
@recipe.favorited_by # Retrieves users that have favorited this recipe
# Add an existing recipe to current_user's favorites
@recipe = Recipe.find(1)
current_user.favorites << @recipe
# Remove a recipe from current_user's favorites
@recipe = Recipe.find(1)
current_user.favorites.delete(@recipe) # (Validate)
D)コントローラーのアクション
コントローラのアクションとルーティングを実装する方法には、いくつかのアプローチがあります。ActiveRecordレピュテーションシステムのRailscast#364に示されているRyanBatesによるものがとても気に入っています。以下で説明するソリューションの一部は、そこでの投票の上下メカニズムに沿って構成されています。
ルートファイルで、お気に入りと呼ばれるレシピにメンバールートを追加します。投稿リクエストに応答する必要があります。これにより、ビューにfavorite_recipe_path(@recipe)URLヘルパーが追加されます。
# config/routes.rb
resources :recipes do
put :favorite, on: :member
end
RecipesControllerで、対応するお気に入りのアクションを追加できるようになりました。そこでは、ユーザーが何をしたいのか、賛成か反対かを判断する必要があります。このために、eg typeと呼ばれるリクエストパラメータを導入できます。これは、後でリンクヘルパーにも渡す必要があります。
class RecipesController < ...
# Add and remove favorite recipes
# for current_user
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << @recipe
redirect_to :back, notice: 'You favorited #{@recipe.name}'
elsif type == "unfavorite"
current_user.favorites.delete(@recipe)
redirect_to :back, notice: 'Unfavorited #{@recipe.name}'
else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end
end
次に、ビューで、お気に入りのレシピとお気に入りのレシピへのそれぞれのリンクを追加できます。
<% if current_user %>
<%= link_to "favorite", favorite_recipe_path(@recipe, type: "favorite"), method: :put %>
<%= link_to "unfavorite", favorite_recipe_path(@recipe, type: "unfavorite"), method: :put %>
<% end %>
それでおしまい。ユーザーがレシピの横にある「お気に入り」リンクをクリックすると、このレシピがcurrent_userのお気に入りに追加されます。
お役に立てば幸いです。ご不明な点がございましたら、お気軽にお問い合わせください。
アソシエーションに関するRailsガイドは非常に包括的であり、開始するときに大いに役立ちます。