Assoziation für polymorph gehört zu einem bestimmten Typ
Ich bin relativ neu in Rails. Ich möchte einem Modell, das die polymorphe Assoziation verwendet, eine Assoziation hinzufügen, aber nur Modelle eines bestimmten Typs zurückgeben, z.
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
Ich habe eine Vielzahl von Kombinationen aus dem Lesen der Assoziationen auf ApiDock ausprobiert, aber nichts scheint genau das zu tun, was ich will. Hier ist das Beste, was ich bisher habe:
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
Und ich möchte, dass es diesen Test besteht:
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
Der erste Test ist erfolgreich, aber Sie können die Relation nicht direkt aufrufen:
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)>'
Warum?Der Grund, warum ich das so machen möchte, ist, dass ich einen Bereich konstruiere, der auf dem Parsen einer Abfragezeichenfolge basiert, einschließlich des Verbindens mit verschiedenen Modellen / etc .; Der Code, der zum Erstellen des Gültigkeitsbereichs verwendet wird, ist erheblich komplexer als der oben beschriebene - er verwendetcollection.reflections
usw. Meine aktuelle Lösung funktioniert dafür, aber es beleidigt mich, dass ich die Relationen nicht direkt von einer Instanz von Note aus aufrufen kann.
Ich könnte es lösen, indem ich es in zwei Punkte aufspalte: direktes Verwenden von Bereichen
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}) }
und dann nur mit einem Getter fürnote.volunteer
/note.participation
das kommt gerade zurücknote.subject
wenn es das recht hatsubject_type
(nil sonst) aber ich dachte bei Rails muss es einen besseren weg geben?