如何在ActiveRecord中设置has_one默认值?

时间:2010-09-18 17:28:46

标签: ruby-on-rails ruby activerecord

我有这样的事情:

class User < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

user = User.new
user.profile.something #=> ERROR

在这种情况下,设置默认配置文件对象的正确方法是什么?我试过这个:

class User < ActiveRecord::Base
  default_scope :include => :profile
  has_one :profile

  def after_initialize
    self.profile ||= Profile.new(:user => self)
  end
end

...但是会产生N + 1个查询。有什么想法吗?

更新

这就是我现在拥有的,工作正常,仍在寻找更好的东西:

class User < ActiveRecord::Base
  default_scope :include => :profile
  has_one :profile, :autosave => true

  def after_initialize
    self.profile = Profile.new(:user => self) if new_record?
  end
end

这样,只要您最终create您的用户,您就会拥有个人资料。否则,唯一的情况是new_record?

4 个答案:

答案 0 :(得分:3)

如果不存在,您可以编写自己的User#个人资料,为您构建一个:

class User < ActiveRecord::Base
  has_one :profile

  def profile_with_default
    profile_without_default || build_profile
  end
  alias_method_chain :profile, :default
end

答案 1 :(得分:1)

我认为你的答案很好。我的解决方案略有不同:

class User < ActiveRecord::Base
  default_scope :include => :profile
  has_one :profile
  alias_method :my_profile, :profile

  def my_profile
    self.profile = Profile.create(:user => self) unless self.profile
    self.profile
  end
end

不可

  • 在请求时创建配置文件,而不是在实例化时创建

不太好

  • 你必须使用my_profile(或者你想称之为)
  • 必须在每次个人资料调用中进行unless self.profile检查

答案 2 :(得分:0)

正确的答案取决于你的意图,因为没有直接解决这类问题。

在实例化对象之后调用after_initialize回调,因此对于这种逻辑来说它并不是一个好地方。

也许您应该尝试使用before_create / after_create代替?这些回调仅在对象创建时调用。

另外,不要使用Profile.new,而是使用以下方法之一:

self.build_profile(...)
self.create_profile(...)

在第二种情况下,模型正在保存。您可以将带有模型属性的哈希传递给两个方法(不要传递:user,因为它是自动设置的。)

答案 3 :(得分:0)

This是一个很好的答案:

class User < ActiveRecord::Base
 has_one :preference_set

 def preference_set
   super || build_preference_set
  end
end