我遇到了一个奇怪的问题,阅读回调RoR指南没有给我答案。
class User < ActiveRecord::Base
...
has_many :company_users, dependent: :destroy
has_many :companies, through: :company_users
has_many :user_teams, dependent: :destroy
has_many :teams, through: :user_teams
before_create :check_company!
after_create :check_team
def check_company!
return if self.companies.present?
domain = self.email_domain
company = Company.find_using_domain(domain)
if company.present?
assign_company(company)
else
create_and_assign_company(domain)
end
end
def check_team
self.companies.each do |company|
#do stuff
end
end
...
end
after_create:check_team回调面临问题,因为行
self.companies.each do |company|
这里,即使创建了公司和用户并且用户与之关联,self.companies也会返回一个空数组[]。我知道我可以通过使它成为before_create回调来解决它。但我很困惑!
为什么after_create回调在提交后无法访问自己的关联?
解决方案:请在接受的答案中阅读我的评论,以了解问题的原因和解决方案。
答案 0 :(得分:1)
在before_create
内部回调中,记录的id
尚未可用,因为它在...之前创建...所以它还没有在数据库中持久存在id
。这意味着关联的company_user
记录尚未具有user_id
值,正是因为此时user.id
仍为nil
。但是,Rails让你不必担心这个&#34;鸡蛋和鸡蛋&#34;问题,只要你做得正确:
我重新创建了您的设置(Company
,User
和CompanyUser
模型),以下内容适合您的情况(经过测试的工作):
class User < ApplicationRecord
has_many :company_users, dependent: :destroy
has_many :companies, through: :company_users
before_create :check_company!
after_create :check_team
def check_company!
# use `exists?` instead of `present?` because `exists?` is a lot faster and efficient as it generates with a `LIMIT 1` SQL.
return if companies.exists?
## when assigning an already persisted Company record:
example_company = Company.first
# 1) WORKS
companies << example_company
# 2) WORKS
company_users.build(company: example_company)
## when assigning and creating a new Company record:
# 1) WORKS (this company record will be automatically saved/created after this user record is saved in the DB)
companies.build(name: 'ahaasdfwer') # or... self.companies.new(name: 'ahaasdfwer')
# 2) DOES NOT WORK, because you'll receive an error `ActiveRecord::RecordNotSaved: You cannot call create unless the parent is saved`
companies.create(name: 'ahaasdfwer')
end
def check_team
puts companies.count
# => 1 if "worked"
puts companies.first.persisted?
# => true if "worked"
end
end