您描述的特定设置混合了几种类型的关联。
A) 用户和配方
首先,我们有一个 User 模型,然后是一个 Recipe 模型。每个配方属于一个用户,因此我们有一个 User :has_many recipes,Recipe 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。我们在这里建立的关联是一个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) 控制器动作
关于如何实现控制器动作和路由,可能有几种方法。我非常喜欢 Ryan Bates 在Railscast #364 on ActiveRecord Reputation System 中展示的那个。下面描述的解决方案部分是按照那里的上下投票机制构建的。
在我们的 Routes 文件中,我们在名为 favorite 的食谱上添加了一个成员路由。它应该响应发布请求。这将为我们的视图添加一个 favorite_recipe_path(@recipe) url helper。
# 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 指南非常全面,在您入门时会为您提供很多帮助。