【问题标题】:which rails query/chain is better?哪个rails查询/链更好?
【发布时间】:2015-11-16 21:01:07
【问题描述】:

我有一个带有以下模型的 rails 应用程序。我有给定用户的assigned_tasks 和executed_tasks。我想知道哪个选项更适合为给定用户获取所有任务(执行和分配)。

task.rb

belongs_to :assigner, class_name: "User"
belongs_to :executor, class_name: "User"

用户.rb

has_many :assigned_tasks, class_name: "Task", foreign_key: "assigner_id", dependent: :destroy
has_many :executed_tasks, class_name: "Task", foreign_key: "executor_id", dependent: :destroy

解决方案 1

task.rb

scope :completed, -> { where.not(completed_at: nil) }
scope :uncompleted, -> { where(completed_at: nil) }

用户.rb

def tasks_uncompleted
  tasks_uncompleted = assigned_tasks.uncompleted.order("deadline DESC")
  tasks_uncompleted += executed_tasks.uncompleted.order("deadline DESC")
  tasks_uncompleted.sort_by { |h| h[:deadline] }.reverse!
end

tasks_controller:

@tasks = current_user.tasks_uncompleted.paginate(page: params[:page], per_page: 12)

解决方案 2:

task.rb

scope :completed, -> { where.not(completed_at: nil) }
scope :uncompleted, -> { where(completed_at: nil) }
scope :alltasks, -> (u) { where('executor_id = ? OR assigner_id = ?', u.id, u.id) }

tasks_controller

@tasks = Task.alltasks(current_user).uncompleted.order("deadline DESC").paginate(page: params[:page], per_page: 12)

【问题讨论】:

  • 第二个要好得多,虽然Task.alltasks(current_user) 很臭。在User 上拥有一个all_tasks 关系来实现同样的事情会更干净,例如current_user.all_tasks.uncompleted....
  • +1 表示第二个选项,-1 表示解决方案 #2,Task#alltasks 可能应该是 Task.for_user(current_user) ...
  • @MrYoshiji,你认为问题只是第二个的命名?
  • 是的,但正如乔丹所说,在您的控制器和其他可以使用current_user 的地方,您应该使用类似current_user.all_tasks.uncompleted 的东西,其中User#all_tasks 是在User 模型返回中定义的范围分配或创建的任务(就像乔丹在他的回答中发布的那样)。 --- 编辑:实际上@Jordan 在他的回答中总结了所有内容,我会按照他的建议去做。

标签: sql ruby-on-rails activerecord chaining


【解决方案1】:

您应该在 User 上定义一个关联,该关联将返回与 executor_idassigner_id 关联的所有任务:

class User < ActiveRecord::Base
  has_many :assigned_and_executed_tasks,
           ->(user) { where('executor_id = ? OR assigner_id = ?', user, user) },
           class_name: 'Task',
           source: :tasks
end

user = User.find(123)
user.assigned_and_executed_tasks
# => SELECT tasks.* FROM tasks WHERE executor_id = 123 OR assigner_id = 123;

然后你可以像在“解决方案 2”中那样做,但不是不幸的Task.alltasks(current_user),你可以只做current_user.assigned_and_executed_tasks(当然你可以给它一个更短的名字,但描述性的名字比简短的名字更好):

@tasks = current_user.assigned_and_executed_tasks
           .uncompleted
           .order("deadline DESC")
           .paginate(page: params[:page], per_page: 12)

【讨论】:

  • 我还需要在其他页面上分别执行executed_tasks 和assigned_tasks。如果我把第三个关联也放在那里,也不会引起问题。不要把事情弄得有点乱?
  • 拥有第三个关联不会导致任何问题,也不会产生任何开销。它通过提高代码的可读性并让您删除 Task.alltasks 范围,从而使您的代码整体上不那么混乱,它的作用完全相同,但在错误的位置。
  • 拥有 3 个关联实际上是有道理的:“get me the Tasks where User X is assigned”; “给我用户 X 是执行者的任务”; “给我所有与用户 X 相关的任务”。你不需要更少,你不需要更多,就这 3 个。
  • 如果我使用你所说的,我会得到未初始化的常量 User::AssignedAndExecutedTask 错误(它在控制台中也不起作用)。我不应该在任务模型中做点什么吗?
  • 我认为您需要添加class_name: 'Task' 选项。我已经更新了我的答案。
【解决方案2】:

解决方案 2 将是从数据库中检索记录的更有效方法。在大多数 Rails 应用程序中,对数据库的调用是导致瓶颈的常见原因,在解决方案 2 中,您调用一次数据库以检索所有记录,但在解决方案 1 中,您对数据库进行两次调用以检索相同的信息。

就我个人而言,我也认为这个解决方案更具可读性、易于测试和可维护性,因此解决方案 2 在许多方面都比速度更好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多