【发布时间】:2014-02-18 10:31:57
【问题描述】:
我对 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 使用getter,如果它有正确的subject_type,则返回note.subject(否则为零),但我认为在Rails 中一定有更好的方法?
【问题讨论】:
-
有点神秘的
{notes: {subject_type: "Volunteer"}}子句有notes:,否则它会查询不存在的volunteers.subject_type列,这使它查询notes.subjects_type。我已经确定了等效的{'notes.subject_type': "Volunteer"}语法;它还提醒我notes应该是复数表名,而不是(有时是单数)关联名称...
标签: ruby-on-rails ruby-on-rails-3 polymorphic-associations