在rails中交叉列表的最快方法?

时间:2014-02-27 20:15:51

标签: ruby-on-rails ruby

我有三个型号。用户,页面和网络。

  • 用户has_many Networks
  • Networks belongs_to Users and Pages
  • Pages has_many Networks。

我正在编写Page#visible_to?(user)方法,并且想知道是否有比我目前更快/更有效/更好的方法。如果任何用户网络也链接到页面,则该方法应返回true。

目前的实施:

def visible_to?(user)
  return true if networks.empty
  user_network_ids = user.networks.pluck(:id)
  !networks.detect { |network| user_network_ids.include?(network.id) }.nil?
end

其他选项包括使用&运算符确定交集,或将此方法放在User上。想法?

3 个答案:

答案 0 :(得分:2)

def visible_to?(user)
  return true if networks.empty?
  (user.networks & networks).size > 0
end

答案 1 :(得分:1)

您应该考虑使用Enumerable#any?

您可以简化

!networks.detect { |network| user_network_ids.include?(network.id) }.nil?

newtworks.any? { |network| user_network_ids.include? network.id }

虽然在这种情况下,(仅在我的深奥意见中)使用集合交叉点进行所有繁重的工作会更好:

def visible_to?(user)
  networks.empty? || (networks.map(&:id) & user.networks.pluck(:id)).any?
end

如果存在重叠或网络为空,则返回true。

答案 2 :(得分:0)

只使用数据库,你可以这样做:

Page.joins(networks: :user).where(pages: {id: page_id}, users: {id: user_id}).any?

它生成此查询:

SELECT COUNT(*) FROM "pages"
  INNER JOIN "networks" ON "networks"."page_id" = "pages"."id"
  INNER JOIN "users" ON "users"."id" = "networks"."user_id"
WHERE "pages"."id" = <<page_id>> AND "users"."id" = <<user_id>>

最快的取决于您的具体情况以及数据的分发方式。例如,如果已经选择了用户的网络和页面的网络,因为您在其他地方也需要它们,并且没有很多要比较的元素,那么执行(user.networks & page.networks).any?可能会更快。只是试验一下,找出最适合你的方法。