我比较新的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",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)>'
为什么?
我想这样做的原因是因为我正在构建基于解析查询字符串的范围,包括连接到各种模型/ etc;用于构造范围的代码比以上复杂得多 – 它使用collection.reflections等.我目前的解决方案适用于此,但是冒犯了我,我不能直接从注释的实例调用关系.
我可以通过将其分为两个问题来解决这个问题:直接使用范围
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,只是返回note.subject如果它有正确的subject_type(否则为nil),但我认为在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,:source_type => Participation end
清洁&简单,只测试了Rails 4.1,但我猜这应该适用于以前的版本.