【问题标题】:Is it possible to remove the "default" WHERE rule for an ActiveRecord relation?是否可以删除 ActiveRecord 关系的“默认”WHERE 规则?
【发布时间】:2018-06-08 09:23:58
【问题描述】:

短版:

有没有办法在 Rails 5.0 中“取消范围”ActiveRecord belongs_to(或其他)关联?


加长版:

我正在开发一个 Rails 项目,其中每个“工作”都分配给一个“部门”以用于组织目的。在大多数情况下,可以根据作业详细信息自动推断部门,但在少数情况下,必须手动将作业分配给不同的部门。

为了解决这个问题,我在 Job 表中添加了一个 department_id 列,目的是让事情按如下方式工作:

  • 如果department_id 不为NULL,则照常将作业加入部门。
  • 否则,回退到“推断”的作业/部门联接逻辑。

根据Rails documentation,这是可能的:

有时您可能希望自定义 属于。这种定制可以通过范围块来实现。为了 示例:

class Book < ApplicationRecord
  belongs_to :author, -> { where active: true },
                        dependent: :destroy
end

您可以在范围内使用任何标准查询方法 块。

因此,我尝试如下定义关系(为演示目的而简化):

belongs_to :department, -> { unscoped.where(id: 7) }

...想法是.unscoped 将删除默认的where departments.id = [jobs.department_id] 逻辑,从而允许我定义自定义规则。

但是,这实际上并没有取消它的范围;生成的 SQL 是:

SELECT  `departments`.*
FROM `departments`
WHERE `departments`.`id` = 11 AND `departments`.`id` = 7
LIMIT 1

我的猜测是在执行自定义查询块之后应用了默认的 WHERE 逻辑,这意味着 .unscoped 没有任何效果。


其他一些事情:

  • 我知道只要创建新作业,我就可以简单地将department_id 设置为“预期”值。但是,这将有几个缺点:
    • 我需要追溯设置数据库中每个现有作业的department_id(这可能需要相当长的时间)。
    • 如果将特定类型的工作重新分配给不同的“默认”部门,则任何现有工作仍将分配给“上一个”部门。
    • 同样,如果要更新工作的详细信息以使其属于不同部门的权限,则用户需要手动重新分配它。
  • 我知道我可以在 Job 模型上定义一个方法 - 或自定义范围 - 而不是在此处使用 belongs_to,但就这个问题而言,假设我绝对必须通过 ActiveRecord 关系来执行此操作。

【问题讨论】:

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


    【解决方案1】:

    我认为你在这方面有点倒退。如果你有一个 department_id,让 rails 成为 rails,department 方法应该返回它。然后也有

    def assumed_department
      return department || guessed_department
    end
    
    def guessed_department
      <your logic for guessing>
    end
    

    如果您有一堆已经使用“部门”的代码,就像我使用假定的部门一样,那么您将需要删除部门 ID 并添加分配部门 ID

    belongs_to assigned_department, class: 'Department' # check the belongs_to docs
    

    然后您的 department 方法将返回 assigned_department || guessed_department 等等……

    但大多数情况下,如果您有关系,那么您应该让您的数据库成为数据库并添加关系并始终分配它。

    【讨论】:

    • 查看我的问题的最后一部分:“我知道我可以在 Job 模型上定义一个方法 - 或自定义范围 - 而不是在此处使用 belongs_to,但出于此目的问题假设我绝对必须通过 ActiveRecord 关系来做到这一点。”
    • 另外,关于“添加关系并始终分配它。” - 请参阅原帖中说明的原因,了解我不想这样做的原因。
    【解决方案2】:

    您正在与框架和数据库作斗争。

    我需要追溯设置每个现有工作的部门 ID 在数据库中(这可能需要相当长的时间)。

    是的。去做吧。

    如果特定类型的工作被重新分配给不同的“默认” 部门,任何现有的工作将仍然分配给“以前的” 部门。

    那么也许你想要一个 has 并且属于许多表之间的 - job_category 或类似的。然后,您可以更改它指向的作业以及引用它的所有内容。

    类似地,如果要更新作业的详细信息,使其 属于不同部门的职权范围,用户需要 手动重新分配它。

    是的 - 所以添加一个之前/之后的回调,它会看到标准已更新,然后分配适当的工作/类别。

    【讨论】:

    • 您的两个回答让我觉得您误解了我的要求。我的问题是“有没有办法在 Rails 5.0 中“取消范围”ActiveRecord belongs_to(或其他)关联?”(包含 Job/Department 位以提供一些背景信息来说明我可能想要的原因这样做),而不是“我如何在 Rails 中实现这个特定场景?”。
    • 是的:google.com/search?q=ruby+metaprogramming 你要问的是“我可以让 Rails 的行为不像 Rails”。完全有可能。您可能想查看 Rails 的其他一些 ORM 后端 - mongoid 等。看看他们如何破解 ORM 来做他们想做的事——尽管这对于你想做的事情来说可能仍然过于严格。我所有的建议都是如何使用框架来做你想做的事。我的任何建议都不会是如何与框架抗争,以使其按照你想要的方式做你想做的事情。
    猜你喜欢
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    相关资源
    最近更新 更多