【问题标题】:How do you set a has_one default value in ActiveRecord?如何在 ActiveRecord 中设置 has_one 默认值?
【发布时间】:2016-02-22 03:46:53
【问题描述】:

我有这样的事情:

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?

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    您可以编写自己的 User#profile,如果它不存在,它将为您构建一个:

    class User < ActiveRecord::Base
      has_one :profile
    
      def profile_with_default
        profile_without_default || build_profile
      end
      alias_method_chain :profile, :default
    end
    

    【讨论】:

      【解决方案2】:

      This 是一个很好的答案:

      class User < ActiveRecord::Base
       has_one :preference_set
      
       def preference_set
         super || build_preference_set
        end
      end
      

      【讨论】:

        【解决方案3】:

        我认为你的回答很好。我有一个稍微不同的解决方案:

        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 检查

        【讨论】:

        • 谢谢,但我不喜欢这样的别名方法,它使子类化和包含模块更难管理。
        【解决方案4】:

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

        after_initialize 回调是在对象实例化之后调用的,所以它不是这种逻辑的好地方。

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

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

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

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

        【讨论】:

        • 我正在考虑这些,但实际上对于我的具体情况,配置文件类取决于子类:class Admin &lt; User,因此build_profile 必须构建"#{self.class.name}Profile".constantize.new。我正在为 Group、RealEstate 和 User 使用这个东西。
        猜你喜欢
        • 2010-09-24
        • 1970-01-01
        • 1970-01-01
        • 2010-11-14
        • 2021-09-22
        • 2020-01-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多