查找用户是否已标记对象

时间:2016-01-04 15:13:54

标签: ruby-on-rails associations enumeration

我目前正在设置一个实例,其中Review有很多Flag s(通过多态),而User有很多标记。到目前为止一切正常,但我现在想要在视图中如果用户标记了特定评论,则显示消息,标记已提交而不是标记它的链接。

现在我通过首先收集属于评论的所有标志,然后使用any?确定其中是否有任何一个拥有当前用户的ID来做到这一点。我想知道这样做是否有更快/更有效的方法?它是一个查找链,让我全面地保持原样。

注意: flaggable是一个局部变量,在本例中代表@review

<%= render "flag", flaggable: @review %>
class Review < ActiveRecord::Base
  has_many :flags, as: :flaggable, dependent: :destroy
end

class Flag < ActiveRecord::Base
  belongs_to :flaggable, polymorphic: true
  belongs_to :owner, class_name: "User", foreign_key: :user_id
end

class User < ActiveRecord::Base
  has_many :flags
end
<div>
  <% if user_signed_in? && flaggable.flags.any? { |r| r.user_id == current_user.id } %>
    <p>Flag Submitted</p>
  <% else %>
    <%= link_to "Flag", [:new, flaggable, :flag], remote: true %>
  <% end %>
...
</div>

1 个答案:

答案 0 :(得分:1)

我认为这会奏效:

<% if user_signed_in? && flaggable.flags.exists?(owner: current_user) %>
  • any?是一个Array方法,循环检查当前保存在内存中的Array中的每个元素是否会返回true。

请注意flaggable.flags是一个扩展Array类的ActiveRecord :: Relation对象,因此您可以使用任何Array方法。但是,一旦调用任何Array方法,所有flaggable.flags都将存储在内存中,到那时为止,只有在那时才会进行检查匹配条件的循环。

  • exists?是一种类似于wherefind方法的ActiveRecord方法,其中检查数据库中表中的每一行是否有任何条件将返回true -memory,更适合搜索,因此效率更高。

更新:(进一步解释)

假设你有这个代码

1 @users = User.where(is_admin: true)
2 @users = @users.where(age: 20)
3 <% @users.each do |user| %>
4   <%= user.name %>
5 <% end %>
6 <%= 'THERE IS A SANTA USER' if @users.any?{|user| user.name == 'Santa'} %>
  • 在第1行,@users是一个ActiveRecord :: Relation,它尚未访问该数据库。它目前仍然只是将DB Query存储在内存中。

  • 在第2行,@users添加了age should be 20条件,因此查询现在变为@users = users-who-are-admin-and-age-is-20。这仍然是存储在内存中的查询。仍然没有发生数据库访问。

  • 在第3行,.each调用@users。通过调用此数组方法,@users现在ActiveRecord::Relation连接并查询数据库,数据库然后返回一个现在可用于循环的用户数组,如您在.each方法中所期望的那样。 (您会注意到从3开始的行是视图文件中的代码)

  • 在第6行,.any?调用@users。因为,@users仍然是ActiveRecord::Relation但已经访问过数据库并且数组已经在内存中(因为第3行),那么.any?将不再访问数据库,并且只是表现得像Array类的普通.any?方法。然后您将意识到,如果数据库中有数百万个用户记录,那么@users将占用大量内存,这不是很好。最好使用.find_each存储内存中的部分数据,以及更多数据库调用的缺点。

另外,请注意使用.joins而不是.includes.joins返回一个Array对象,而.includes返回一个ActiveRecord :: Relation。两者都有自己的用例。