包括所有对象的关联模型(在索引操作中)

时间:2014-05-29 21:54:14

标签: ruby-on-rails associations rating

我正在尝试为我的应用程序开发评级,其中用户可以为评论设置特定评级。我已按照以下tutorial进行操作。

以下是我的协会:

class Rating < ActiveRecord::Base
  belongs_to :comment
  belongs_to :user
end

class Comment < ActiveRecord::Base
  has_many :ratings
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :ratings
  has_many :comments
end

我的问题是,在我的评论控制器的索引操作中,我需要包含用户为该评论所做的评级。在本教程中,只显示了如何选择特定评级:

@rating = Rating.where(comment_id: @comment.id, user_id: @current_user.id).first 

unless @rating 
  @rating = Rating.create(comment_id: @comment.id, user_id: @current_user.id, score: 0) 
end

但是,我会有几个等级,因为在我的控制器中我有:

def index
  @comments = @page.comments #Here each comment should have the associated rating for the current_user, or a newly created rating if it does not exist.
end

1 个答案:

答案 0 :(得分:1)

您想要找到评级的user_id与当前用户匹配的评论评级。

<%= comment.ratings.where(user_id: current_user.id).first %>

然而,这种逻辑在视图中非常麻烦,更好的策略是在Rating中定义范围,该范围返回特定用户所做的所有评级。

class Rating
  scope :by_user, lambda { |user| where(user_id: user.id) }
end

class Comment
  # this will return either the rating created by the given user, or nil
  def rating_by_user(user)
    ratings.by_user(user).first 
  end
end

现在,在您看来,您可以访问当前用户创建的评论的评分:

<% @comments.each do |comment| %>
  <%= comment.rating_by_user(current_user) %>
<% end %>

如果您想在索引页面中急切加载所有评级,您可以执行以下操作:

def index
  @comments = page.comments.includes(:ratings)
end

然后,您可以通过以下方式找到正确的评级:

<% @comments.each do |comment| %>
  <%= comment.ratings.find { |r| r.user_id == current_user.id } %>
<% end %>

这将返回正确的评级,而不会产生任何额外的SQL查询,代价是加载每条评论的每个相关评级。


我不知道ActiveRecord中的一种方法是急切加载has_many关系的子集。请参阅this相关的StackOverflow问题,以及包含有关预先加载的详细信息的this博文。