假设Student belongs_to :contactTeacher也是belongs_to :contact.假设first_nameContact中,StudentTeacher的名字是throughContactaccepts_nested_attributes_for :contact.

after_commit回调中,如果first_name发生变化,我想看看它是来自Student还是来自Teacher.我不知道该怎么做,也不知道这是否可能.在Studentafter_commit之内,previous_changes没有first_name.只有在Contactafter_commit秒时才出现.所以在Contactafter_commit里面,我想看看它是起源于Student还是Teacher.

我该怎么做?有类似于destroyed_by_association的东西吗?当我在文档中搜索"by\u association"时,我没有看到任何其他内容,在Active Record Autosave Association中也没有看到任何其他内容.

注意:Contact有可能同时具有StudentandTeacher,因此这并不是简单地说,如果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" = $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

如果将回调设置为StudentTeacher,则无论上述设置如何,都可以访问所有内容.

多态性:

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更新来自TeacherStudent:

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

Ruby-on-rails相关问答推荐

带有rails 7.1的Lightbox2未初始化

我使用rbenv安装Ruby,但我在使用";gem";->;错误:执行gem时遇到此错误.(Errno::EACCES)权限被拒绝

关于关联 has_many 的多级/三重嵌套形式

如何从 New Relic 交易中获取 TraceId?

您如何测试方法调用块内调用的方法,以及使用 rspec 在块内传递给该方法调用的内容

无效的单表继承类型:Rails

有没有一种简单的方法可以让 pow 为 https 服务?

Ruby on Rails 有没有好的管理生成器?

Rails 模型方法 self.与普通

Rails cron 与时俱进,设置环境

在 Nokogiri 中获取属性值以提取链接 URL

从 Rails 模型内部访问翻译文件 (i18n)

在 rake 任务期间关闭观察者的简单方法?

Rails Active Admin css 与 Twitter Bootstrap css 冲突

如何对这个哈希数组进行分组?

你如何覆盖 form_for 助手中的类名?

在 Devise on Rails beta 3 中创建管理员用户

:javascript haml 标签中的内联Ruby ?

扩展 Devise SessionsController 以使用 JSON 进行身份验证

未捕获的 ReferenceError:未定义 ReactDOM