您能告诉我创建has_one关系的最佳实践是什么吗?
fe,如果我有一个用户模型,并且必须有一个配置文件...
我该怎么办呢?
一种解决方案是:
# user.rb
class User << ActiveRecord::Base
after_create :set_default_association
def set_default_association
self.create_profile
end
end
但这似乎并不干净……有什么建议吗?
您能告诉我创建has_one关系的最佳实践是什么吗?
fe,如果我有一个用户模型,并且必须有一个配置文件...
我该怎么办呢?
一种解决方案是:
# user.rb
class User << ActiveRecord::Base
after_create :set_default_association
def set_default_association
self.create_profile
end
end
但这似乎并不干净……有什么建议吗?
Answers:
创建has_one关系的最佳实践是使用ActiveRecord回调before_create
而不是after_create
。或者使用更早的回调并处理子代未通过其自己的验证步骤的问题(如果有)。
因为:
怎么做:
# in your User model...
has_one :profile
before_create :build_default_profile
private
def build_default_profile
# build default profile instance. Will use default params.
# The foreign key to the owning User model is set automatically
build_profile
true # Always return true in callbacks as the normal 'continue' state
# Assumes that the default_profile can **always** be created.
# or
# Check the validation of the profile. If it is not valid, then
# return false from the callback. Best to use a before_validation
# if doing this. View code should check the errors of the child.
# Or add the child's errors to the User model's error array of the :base
# error item
end
user
中before_create
呢?
如果这是现有大型数据库中的新关联,则将按以下方式管理过渡:
class User < ActiveRecord::Base
has_one :profile
before_create :build_associations
def profile
super || build_profile(avatar: "anon.jpg")
end
private
def build_associations
profile || true
end
end
以便现有用户记录在需要时获得一个配置文件,并使用它创建新的配置文件。这还将默认属性放在一个位置,并且可以在Rails 4及更高版本中与accepts_nested_attributes_for一起正常使用。
可能不是最干净的解决方案,但我们已经有一个拥有50万条记录的数据库,其中一些已经创建了“个人档案”模型,而有些则没有。我们采用了这种方法,该方法可确保在任何时候都存在Profile模型,而无需经历并追溯生成所有Profile模型。
alias_method :db_profile, :profile
def profile
self.profile = Profile.create(:user => self) if self.db_profile.nil?
self.db_profile
end
这是我的方法。不确定这是什么标准,但是它工作得很好,并且很懒惰,除非有必要建立新的关联,否则它不会产生额外的开销(我很乐意对此进行纠正):
def profile_with_auto_build
build_profile unless profile_without_auto_build
profile_without_auto_build
end
alias_method_chain :profile, :auto_build
这也意味着该关联会在您需要时立即存在。我猜是替代方法是挂在after_initialize上,但这似乎增加了相当大的开销,因为每次初始化对象时都会运行它,并且有时您不需要访问该关联。检查它的存在似乎是浪费。
has_one :profile, :autosave => true