特定类型的多态相关者的关联 [英] Association for polymorphic belongs_to of a particular type
问题描述
我对Rails比较陌生.我想向使用多态关联的模型添加关联,但仅返回特定类型的模型,例如:
class Note < ActiveRecord::Base
# The true polymorphic association
belongs_to :subject, polymorphic: true
# Same as subject but where subject_type is 'Volunteer'
belongs_to :volunteer, source_association: :subject
# Same as subject but where subject_type is 'Participation'
belongs_to :participation, source_association: :subject
end
通过阅读有关ApiDock上的关联的信息,我尝试了各种各样的组合,但是似乎没有任何事情可以完全满足我的要求.这是我到目前为止最好的:
class Note < ActiveRecord::Base
belongs_to :subject, polymorphic: true
belongs_to :volunteer, class_name: "Volunteer", foreign_key: :subject_id, conditions: {notes: {subject_type: "Volunteer"}}
belongs_to :participation, class_name: "Participation", foreign_key: :subject_id, conditions: {notes: {subject_type: "Participation"}}
end
我希望它通过此测试:
describe Note do
context 'on volunteer' do
let!(:volunteer) { create(:volunteer) }
let!(:note) { create(:note, subject: volunteer) }
let!(:unrelated_note) { create(:note) }
it 'narrows note scope to volunteer' do
scoped = Note.scoped
scoped = scoped.joins(:volunteer).where(volunteers: {id: volunteer.id})
expect(scoped.count).to be 1
expect(scoped.first.id).to eq note.id
end
it 'allows access to the volunteer' do
expect(note.volunteer).to eq volunteer
end
it 'does not return participation' do
expect(note.participation).to be_nil
end
end
end
第一个测试通过,但是您不能直接调用该关系:
1) Note on volunteer allows access to the volunteer
Failure/Error: expect(note.reload.volunteer).to eq volunteer
ActiveRecord::StatementInvalid:
PG::Error: ERROR: missing FROM-clause entry for table "notes"
LINE 1: ...."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."s...
^
: SELECT "volunteers".* FROM "volunteers" WHERE "volunteers"."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."subject_type" = 'Volunteer' LIMIT 1
# ./spec/models/note_spec.rb:10:in `block (3 levels) in <top (required)>'
为什么?
之所以要这样做是因为我基于解析查询字符串(包括加入各种模型/等)来构造作用域;用于构造作用域的代码比上面的代码复杂得多-它使用collection.reflections
等.我当前的解决方案适用于此,但是它冒犯了我,我无法直接从Note实例中调用这些关系.>
我可以将其分为两个问题来解决:直接使用范围
scope :scoped_by_volunteer_id, lambda { |volunteer_id| where({subject_type: 'Volunteer', subject_id: volunteer_id}) }
scope :scoped_by_participation_id, lambda { |participation_id| where({subject_type: 'Participation', subject_id: participation_id}) }
然后使用note.volunteer
/note.participation
的吸气剂,如果它具有正确的subject_type
,则仅返回note.subject
(否则为零),但是我在Rails中发现必须有更好的方法吗?
我遇到了类似的问题.最后,我通过使用如下所示的自引用关联来淘汰了最佳,最可靠的解决方案.
class Note < ActiveRecord::Base
# The true polymorphic association
belongs_to :subject, polymorphic: true
# The trick to solve this problem
has_one :self_ref, :class_name => self, :foreign_key => :id
has_one :volunteer, :through => :self_ref, :source => :subject, :source_type => Volunteer
has_one :participation, :through => :self_ref, :source => :subject, :source_type => Participation
end
清洁&简单,仅在Rails 4.1上进行了测试,但我想它应该可以在以前的版本中使用.
I'm relatively new to Rails. I would like to add an association to a model that uses the polymorphic association, but returns only models of a particular type, e.g.:
class Note < ActiveRecord::Base
# The true polymorphic association
belongs_to :subject, polymorphic: true
# Same as subject but where subject_type is 'Volunteer'
belongs_to :volunteer, source_association: :subject
# Same as subject but where subject_type is 'Participation'
belongs_to :participation, source_association: :subject
end
I've tried a vast array of combinations from reading about the associations on ApiDock but nothing seems to do exactly what I want. Here's the best I have so far:
class Note < ActiveRecord::Base
belongs_to :subject, polymorphic: true
belongs_to :volunteer, class_name: "Volunteer", foreign_key: :subject_id, conditions: {notes: {subject_type: "Volunteer"}}
belongs_to :participation, class_name: "Participation", foreign_key: :subject_id, conditions: {notes: {subject_type: "Participation"}}
end
And I want it to pass this test:
describe Note do
context 'on volunteer' do
let!(:volunteer) { create(:volunteer) }
let!(:note) { create(:note, subject: volunteer) }
let!(:unrelated_note) { create(:note) }
it 'narrows note scope to volunteer' do
scoped = Note.scoped
scoped = scoped.joins(:volunteer).where(volunteers: {id: volunteer.id})
expect(scoped.count).to be 1
expect(scoped.first.id).to eq note.id
end
it 'allows access to the volunteer' do
expect(note.volunteer).to eq volunteer
end
it 'does not return participation' do
expect(note.participation).to be_nil
end
end
end
The first test passes, but you can't call the relation directly:
1) Note on volunteer allows access to the volunteer
Failure/Error: expect(note.reload.volunteer).to eq volunteer
ActiveRecord::StatementInvalid:
PG::Error: ERROR: missing FROM-clause entry for table "notes"
LINE 1: ...."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."s...
^
: SELECT "volunteers".* FROM "volunteers" WHERE "volunteers"."deleted" = 'f' AND "volunteers"."id" = 7798 AND "notes"."subject_type" = 'Volunteer' LIMIT 1
# ./spec/models/note_spec.rb:10:in `block (3 levels) in <top (required)>'
Why?
The reason I want to do it this way is because I'm constructing a scope based on parsing a query string including joining to various models/etc; the code used to construct the scope is considerably more complex than that above - it uses collection.reflections
, etc. My current solution works for this, but it offends me I can't call the relations directly from an instance of Note.
I could solve it by splitting it into two issues: using scopes directly
scope :scoped_by_volunteer_id, lambda { |volunteer_id| where({subject_type: 'Volunteer', subject_id: volunteer_id}) }
scope :scoped_by_participation_id, lambda { |participation_id| where({subject_type: 'Participation', subject_id: participation_id}) }
and then just using a getter for note.volunteer
/note.participation
that just returns note.subject
if it has the right subject_type
(nil otherwise) but I figured in Rails there must be a better way?
I had bump into the similar problem. and I finally ironed out the best and most robust solution by using a self reference association like below.
class Note < ActiveRecord::Base
# The true polymorphic association
belongs_to :subject, polymorphic: true
# The trick to solve this problem
has_one :self_ref, :class_name => self, :foreign_key => :id
has_one :volunteer, :through => :self_ref, :source => :subject, :source_type => Volunteer
has_one :participation, :through => :self_ref, :source => :subject, :source_type => Participation
end
Clean & simple, only tested on Rails 4.1, but I guess it should work for previous versions.
这篇关于特定类型的多态相关者的关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!