Reputation: 12157
I have a model with a complicated join:
class Submission < ApplicationRecord
has_many :histories,
->(s) { where(/* A complex query */) },
class_name: 'SubmissionFieldHistory'
end
I'd like that scope query to replace the default conditions that gets generated by ActiveRecord, however it seems to be added to the conditions.
Is there a simple way to say has_many :histories, :but_join_it_how_i_say
?
Upvotes: 0
Views: 154
Reputation: 6603
If by "default conditions", you meant the default SQL condition WHERE HISTORIES_TABLE.submission_id = SOME_SUBMISSION_ID
.
To specify a custom query for has_many
, use unscope
:
class Submission < ApplicationRecord
has_many :histories,
->(s) { unscope(:where).where(/* A complex query */) },
class_name: 'SubmissionFieldHistory'
end
unscope(:where)
above will remove any/all prior WHERE
SQL queries in the chain, of which one of them includes the default WHERE HISTORIES_TABLE.submission_id = SOME_SUBMISSION_ID
, of which is what you want to remove.
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]]
However, because unscope(:where)
removes all prior WHERE
conditions, it also then removes the condition supplied by default_scope
(if you have a default_scope
inside the SubmissionFieldHistory
). In order to also make it work for default_scope
, you can use the more specific unscope(where: SOME_ATTRIBUTE)
instead like below:
app/models/submission_field_history.rb
class SubmissionFieldHistory < ApplicationRecord
# example: (default to not fetching anymore "deleted" records)
default_scope { where(is_deleted: false) }
belongs_to :submission
end
app/models/submission.rb
class Submission < ApplicationRecord
has_many :histories,
->(s) { unscope(where: :submission_id).where(/* A complex query */) },
class_name: 'SubmissionFieldHistory'
submission = Submission.find(1)
submission.histories
# SubmissionFieldHistory Load (5.5ms) SELECT "submission_field_histories".* FROM "submission_field_histories"
# WHERE "submission_field_histories".is_deleted = false
# AND /* A complex query */ LIMIT $1 [["LIMIT", 11]]
Upvotes: 1