查找用户是否已经标记了一个对象
Finding if a user has already flagged an object
我目前设置了一个实例,其中 Review
有很多 Flag
(通过多态性),User
有很多标志。到目前为止一切正常,但我现在想在视图中显示一条消息,如果用户标记了特定评论,Flag Submitted 而不是 link标记它。
现在,我首先收集属于评论的所有标记,然后使用 any?
确定其中是否有当前用户的 ID。我想知道是否有 faster/more 有效的方法来做到这一点?是查找链让我全面了解它。
注意: 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>
我认为这会起作用:
<% if user_signed_in? && flaggable.flags.exists?(owner: current_user) %>
any?
是一种数组方法,它循环检查是否有任何条件 return 对于当前持有的数组中的每个元素为真 in-memory.
请注意,flaggable.flags
是一个扩展数组 class 的 ActiveRecord::Relation 对象,因此您可以为此使用任何数组方法。但是,一旦你调用任何Array方法,所有flaggable.flags
将被存储in-memory,这是到那时,只有到那时才会发生检查匹配条件的循环。
exists?
是一种类似于 where
和 find
方法的 ActiveRecord 方法,其中检查 return 中的每一行是否有任何条件为真90=] 在数据库中,它不是 in-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。它目前只是还在内存中存储数据库查询。
在第 2 行,@users
添加了条件 age should be 20
,因此查询现在变成类似于 @users = users-who-are-admin-and-age-is-20
。这仍然是一个存储在内存中的查询。仍然没有数据库访问发生。
在第 3 行,从 @users
调用了 .each
。通过调用此数组方法,@users
即 ActiveRecord::Relation
现在连接并查询数据库,然后 returns 用户数组现在可用于循环,正如您在 .each
方法。 (您会注意到从 3 开始的行是视图文件中的代码)
在第 6 行,从 @users
调用了 .any?
。因为 @users
仍然是 ActiveRecord::Relation
但已经访问了数据库并且数组已经在内存中(因为第 3 行),所以 .any?
将不再访问数据库,并将就像数组 class 的普通 .any?
方法一样。你会发现,如果 DB 中有数百万条 User 记录,那么 @users
将占用大量内存,这不是很好。使用存储 in-memory partial-by-partial 的 .find_each
会更好,但缺点是会调用更多数据库。
附带说明一下,请注意使用 .joins
而不是 .includes
。 .joins
return 是一个数组对象,而 .includes
return 是一个 ActiveRecord::Relation。两者都有自己的 use-cases.
我目前设置了一个实例,其中 Review
有很多 Flag
(通过多态性),User
有很多标志。到目前为止一切正常,但我现在想在视图中显示一条消息,如果用户标记了特定评论,Flag Submitted 而不是 link标记它。
现在,我首先收集属于评论的所有标记,然后使用 any?
确定其中是否有当前用户的 ID。我想知道是否有 faster/more 有效的方法来做到这一点?是查找链让我全面了解它。
注意: 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>
我认为这会起作用:
<% if user_signed_in? && flaggable.flags.exists?(owner: current_user) %>
any?
是一种数组方法,它循环检查是否有任何条件 return 对于当前持有的数组中的每个元素为真 in-memory.
请注意,flaggable.flags
是一个扩展数组 class 的 ActiveRecord::Relation 对象,因此您可以为此使用任何数组方法。但是,一旦你调用任何Array方法,所有flaggable.flags
将被存储in-memory,这是到那时,只有到那时才会发生检查匹配条件的循环。
exists?
是一种类似于where
和find
方法的 ActiveRecord 方法,其中检查 return 中的每一行是否有任何条件为真90=] 在数据库中,它不是 in-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。它目前只是还在内存中存储数据库查询。在第 2 行,
@users
添加了条件age should be 20
,因此查询现在变成类似于@users = users-who-are-admin-and-age-is-20
。这仍然是一个存储在内存中的查询。仍然没有数据库访问发生。在第 3 行,从
@users
调用了.each
。通过调用此数组方法,@users
即ActiveRecord::Relation
现在连接并查询数据库,然后 returns 用户数组现在可用于循环,正如您在.each
方法。 (您会注意到从 3 开始的行是视图文件中的代码)在第 6 行,从
@users
调用了.any?
。因为@users
仍然是ActiveRecord::Relation
但已经访问了数据库并且数组已经在内存中(因为第 3 行),所以.any?
将不再访问数据库,并将就像数组 class 的普通.any?
方法一样。你会发现,如果 DB 中有数百万条 User 记录,那么@users
将占用大量内存,这不是很好。使用存储 in-memory partial-by-partial 的.find_each
会更好,但缺点是会调用更多数据库。
附带说明一下,请注意使用 .joins
而不是 .includes
。 .joins
return 是一个数组对象,而 .includes
return 是一个 ActiveRecord::Relation。两者都有自己的 use-cases.