如果将相应的关联添加到Contact
,则可以在after_commit
回调中访问它们:
class Student < ApplicationRecord
belongs_to :contact
accepts_nested_attributes_for :contact
end
class Teacher < ApplicationRecord
belongs_to :contact
accepts_nested_attributes_for :contact
end
class Contact < ApplicationRecord
has_one :teacher
has_one :student
after_commit do
p teacher || student
end
end
>> Teacher.create(contact_attributes: { name: 'teacher' })
...
# after_commit START
#<Teacher id: 1, contact_id: 1>
# after_commit END
=> #<Teacher:0x00007fd28056a9f0 id: 1, contact_id: 1>
需要注意的一点是,如果老师不在场,它会影响数据库:
>> Student.create(contact_attributes: { name: 'student' });
...
# after_commit START
Teacher Load (0.4ms) SELECT "teachers".* FROM "teachers" WHERE "teachers"."contact_id" = $1 LIMIT $2 [["contact_id", 2], ["LIMIT", 1]]
#<Student id: 1, contact_id: 2>
# after_commit END
=> #<Student:0x00007fd2837bd9c0 id: 1, contact_id: 2>
切换到多态关系也是一种解决方案:
class Student < ApplicationRecord
has_one :contact, as: :contactable
accepts_nested_attributes_for :contact
end
class Teacher < ApplicationRecord
has_one :contact, as: :contactable
accepts_nested_attributes_for :contact
end
# NOTE: to add plymorphic relationship add this to contact migration:
# t.references :contactable, polymorphic: true
class Contact < ApplicationRecord
belongs_to :contactable, polymorphic: true
after_commit do
p contactable
end
end
>> Student.create(contact_attributes: { name: 'student' })
...
# after_commit START
#<Student id: 1>
# after_commit END
=> #<Student:0x00007f4a85c0d1c8 id: 1>
>> Teacher.create(contact_attributes: { name: 'teacher' })
...
# after_commit START
#<Teacher id: 1>
# after_commit END
=> #<Teacher:0x00007f4a884e2a08 id: 1>
Update
如果将回调设置为Student
和Teacher
,则无论上述设置如何,都可以访问所有内容.
多态性:
class Teacher < ApplicationRecord
has_one :contact, as: :contactable
accepts_nested_attributes_for :contact
after_commit do
p self
p contact
p contact.previous_changes
end
end
>> Teacher.create(contact_attributes: { name: 'teacher' })
...
# after_commit START
#<Teacher id: 1>
#<Contact id: 1, name: "teacher", contactable_type: "Teacher", contactable_id: 1>
{"id"=>[nil, 1], "name"=>[nil, "teacher"], "contactable_type"=>[nil, "Teacher"], "contactable_id"=>[nil, 1]}
# after_commit END
=> #<Teacher:0x00007fbf1bdd2db8 id: 1>
属于\u:
class Teacher < ApplicationRecord
belongs_to :contact
accepts_nested_attributes_for :contact
after_commit do
p self
p contact
p contact.previous_changes
end
end
>> Teacher.create(contact_attributes: { name: 'teacher' })
...
# after_commit START
#<Teacher id: 1, contact_id: 1>
#<Contact id: 1, name: "teacher">
{"id"=>[nil, 1], "name"=>[nil, "teacher"]}
# after_commit END
=> #<Teacher:0x00007f9f2ce6a730 id: 1, contact_id: 1>
如果Contact
中必须有after_commit
,则必须明确告诉Contact
更新来自Teacher
或Student
:
class Teacher < ApplicationRecord
belongs_to :contact
accepts_nested_attributes_for :contact
# NOTE: before saving, let contact know it's about to be updated
# by Teacher.
before_save do
contact.updated_from = :teacher
end
end
class Contact < ApplicationRecord
# NOTE: just a temporary attribute
attr_accessor :updated_from
after_commit do
print 'Updated from: '
p self.updated_from
end
end
>> Teacher.create(contact_attributes: { name: 'teacher' })
...
# after_commit START
Updated from: :teacher
# after_commit END
=> #<Teacher:0x00007fd6a40459c0 id: 1, contact_id: 1>
或在教师中没有before_save
个回调:
>> Teacher.create(contact_attributes: { name: 'teacher', updated_from: 'teacher' })
...
Updated from: "teacher"
或重写contact_attributes=
方法:
class Teacher < ApplicationRecord
belongs_to :contact
accepts_nested_attributes_for :contact
def contact_attributes= attributes
attributes[:updated_from] = :teacher
super
end
end