【问题标题】:Rails 5, refactoring, optimal query for multiple conditionsRails 5,重构,多条件优化查询
【发布时间】:2016-06-17 20:29:10
【问题描述】:

我有一个最近更新到 Rails 5 的 Rails 应用程序。我有一个看起来像这样的数据模型(简化):Users 可以有很多 AppsUsers 也可以是 Member多个Teams,每个Team也可以有多个Apps。在我的Apps 索引视图/控制器中,我想列出他/她创建的所有用户应用程序,我还想列出属于Teams 的所有应用程序UsersMember的。

我感觉有一种比我当前的实现更好、更高效的方法(可能是 Rails 5 中的新功能)。这是我当前实现的样子:

apps = []
# First get all the team apps where the user is a member, but haven't created the app. 
current_or_guest_user.teams.each do |team|
  team.apps.each do |app|
    unless app.user.eql?(current_or_guest_user)
      apps << app
    end
  end
end
# ... then get all the apps that the user have created. 
current_or_guest_user.apps.each do |app|
  unless apps.include?(app)
    apps << app
  end
end
# Return the apps. 
@apps = apps

那么,有没有一种更清洁、更优化的方法来做我正在做的事情?那看起来怎么样?

编辑

这是我的活动模型关联的样子:

# App.rb
belongs_to :user
belongs_to :team

# User.rb
has_many :apps, dependent: :destroy
has_many :teams
has_many :teams, through: :members

# Team.rb
has_many :apps, dependent: :destroy

编辑 2

我想知道 Rails 5 方法 #or (https://github.com/rails/rails/pull/16052) 是否可以在这个用例中使用,例如:

current_user.apps.or([...]])
# [...] = In not exactly sure what to put here in that case.

【问题讨论】:

  • 可以以格式良好的方式粘贴模型关联吗?
  • @oreoluwa 我现在已经添加了关联。
  • 我认为更优化的方法是使用Arel。我真的不认为 Rails 5 对此有更好的方法。但另一种方式是委托方法,但它可能仍然不够优化。

标签: sql ruby-on-rails ruby rails-activerecord ruby-on-rails-5


【解决方案1】:

我认为下面的代码应该更简洁:

# using a shorter variable name
user = current_or_guest_user

# does the same thing as your first loop over teams
set1 = user.teams.includes(:apps).where("apps.user_id = ?", user.id).map(&:apps)

# does the same thing as the second loop
# (no need to check for duplicates here)
set2 = user.apps

# combine the two queries without adding duplicates
return set1 | set2

抱歉,如果这不能开箱即用,我还没有测试过。

这里有几个概念:

  • includes 将通过关联“预加载”记录。这通过单个查询获取所有关联记录,而不是触发单个 SQL 查询来获取每个记录。
  • where("apps.user_id = ?", user.id) 根据关联记录的 user_id 过滤查询。这里的? 是一个被user.id 替换的变量。

【讨论】:

  • 谢谢,试试看!您认为在这个用例中是否也可以使用新的 Rails 5 #or 方法? github.com/rails/rails/pull/16052
  • 我不明白为什么不这样做。
  • 我不知道or 方法。我一直在使用active_record_union gem
  • 虽然current_user.apps.or([...]) 不完全确定要在[...] 中添加什么,但会很好。将其添加到我原来的问题中。
  • 在这种情况下,您可以将 set1 | set2 替换为 set1.or(set2)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2012-09-12
  • 1970-01-01
相关资源
最近更新 更多