has_many中的作用域可以完全替换默认联接吗?

时间:2019-03-01 13:38:16

标签: ruby-on-rails activerecord

我有一个带有复杂联接的模型:

class Submission < ApplicationRecord
  has_many :histories,
           ->(s) { where(/* A complex query */) },
           class_name: 'SubmissionFieldHistory'
end

我希望该范围查询替换由ActiveRecord生成的默认条件,但是似乎将添加到条件中。

有一种简单的说法has_many :histories, :but_join_it_how_i_say吗?

1 个答案:

答案 0 :(得分:1)

假设:

如果使用“默认条件”,则表示默认SQL条件WHERE HISTORIES_TABLE.submission_id = SOME_SUBMISSION_ID

解决方案1:

要为has_many指定自定义查询,请使用unscope

class Submission < ApplicationRecord
  has_many :histories,
    ->(s) { unscope(:where).where(/* A complex query */) },
    class_name: 'SubmissionFieldHistory'
end
上面的

unscope(:where)将删除链中的任何/所有先前的WHERE SQL查询,其中之一包括默认的WHERE HISTORIES_TABLE.submission_id = SOME_SUBMISSION_ID,这是您想要的删除。

用法:

submission = Submission.find(1)
submission.histories
# SubmissionFieldHistory Load (5.5ms)  SELECT  "submission_field_histories".* FROM "submission_field_histories"
#   WHERE /* A complex query */ LIMIT $1  [["LIMIT", 11]]

解决方案2:

但是,由于unscope(:where)删除了所有先前的WHERE条件,因此它也会同时删除default_scope提供的条件(如果您在{{1}中有default_scope }。为了也使其适用于SubmissionFieldHistory,您可以使用更具体的default_scope,如下所示:

app / models / submission_field_history.rb

unscope(where: SOME_ATTRIBUTE)

app / models / submission.rb

class SubmissionFieldHistory < ApplicationRecord
  # example: (default to not fetching anymore "deleted" records)
  default_scope { where(is_deleted: false) }

  belongs_to :submission
end

用法:

class Submission < ApplicationRecord
  has_many :histories,
    ->(s) { unscope(where: :submission_id).where(/* A complex query */) },
    class_name: 'SubmissionFieldHistory'