30

我正在构建一个应用程序,用户可以在其中创建食谱,查看创建的所有食谱,在会员区查看他们自己的食谱,最后我希望用户将“收藏夹”添加到他们的帐户中。

我是 Rails 的新手,但已经阅读了文档,这是我对后端应该是什么样子的理解。有人可以确认这看起来正确或建议任何错误,如果我做错了什么(可能是这种情况),请提供解释?

所以这是我的代码:

用户模型

has_many :recipes
has_many_favorites, :through => :recipes

配方模型

belongs_to :user
has_many :ingredients #created seperate db for ingredients
has_many :prepererations #created seperate db for prep steps

最喜欢的模特

belongs_to :user
has_many :recipes, :through => :user
#this model has one column for the FK, :user_id

收藏夹控制器

def create
  @favrecipes =current_user.favorites.create(params[:user_id])
end

然后我想要一个按钮来发布到数据库,所以我有这个:

<%= button_to("Add to Favorites" :action => "create", :controller => "favorites" %>

我想我可能在我的路线中遗漏了一些东西,但我不确定。

4

4 回答 4

71

您描述的特定设置混合了几种类型的关联。

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 指南非常全面,在您入门时会为您提供很多帮助。

于 2012-11-05T21:10:43.283 回答
1

感谢您的指导,托马斯!它工作得很好。

只是想补充一点,为了让您最喜欢的方法正常工作,您需要将文本用双引号而不是单引号括起来,以便字符串插值起作用。

redirect_to :back, notice: 'You favorited #{@recipe.name}'

->

redirect_to :back, notice: "You favorited #{@recipe.name}"

https://rubymonk.com/learning/books/1-ruby-primer/chapters/5-strings/lessons/31-string-basics

于 2016-07-23T00:19:53.373 回答
0

这个线程非常有帮助!

谢谢!

不要忘记在表单标签中包含= 。

<% 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 %>
于 2015-02-11T15:17:15.840 回答
0

选择的答案非常好,但是我无法发表评论,而且我确实对上述内容有疑问。你怎么能限制用户拥有一个最喜欢的食谱?使用上述答案,用户可以继续按收藏夹,并且将在数据库中创建许多条目...

于 2016-08-30T20:50:40.133 回答