您如何查看 Rails 中哪个关联模型触发了回调?
How can you see what associated model triggered a callback in Rails?
假设 Student
belongs_to :contact
和 Teacher
也 belongs_to :contact
。假设 first_name
在 Contact
中,并且 Student
和 Teacher
有一个名字 通过 和 Contact
并且有accepts_nested_attributes_for :contact
.
在 after_commit
回调中,如果 first_name
发生变化,我想看看它是来自 Student
还是来自 Teacher
。我不确定如何做到这一点,或者它是否可能。在 Student
的 after_commit
中,previous_changes
没有 first_name
。它只出现在 Contact
的 after_commit
中。所以在 Contact
的 after_commit
里面,我想看看它是来自 Student
还是来自 Teacher
.
我该怎么做?有没有类似destroyed_by_association
? When I search for "by_association" in the docs I don't see anything else, nor do I see anything else in Active Record Autosave Association.
的东西
注意:Contact
可能同时具有 Student
和 和 Teacher
,所以它不像简单地说,如果 Contact
没有 Student
,它一定来自 Teacher
.
如果您将相应的关联添加到 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" = LIMIT [["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>
更新
如果将回调放在 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>
Belongs_to:
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
假设 Student
belongs_to :contact
和 Teacher
也 belongs_to :contact
。假设 first_name
在 Contact
中,并且 Student
和 Teacher
有一个名字 通过 和 Contact
并且有accepts_nested_attributes_for :contact
.
在 after_commit
回调中,如果 first_name
发生变化,我想看看它是来自 Student
还是来自 Teacher
。我不确定如何做到这一点,或者它是否可能。在 Student
的 after_commit
中,previous_changes
没有 first_name
。它只出现在 Contact
的 after_commit
中。所以在 Contact
的 after_commit
里面,我想看看它是来自 Student
还是来自 Teacher
.
我该怎么做?有没有类似destroyed_by_association
? When I search for "by_association" in the docs I don't see anything else, nor do I see anything else in Active Record Autosave Association.
注意:Contact
可能同时具有 Student
和 和 Teacher
,所以它不像简单地说,如果 Contact
没有 Student
,它一定来自 Teacher
.
如果您将相应的关联添加到 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" = LIMIT [["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>
更新
如果将回调放在 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>
Belongs_to:
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