代码之家  ›  专栏  ›  技术社区  ›  BvuRVKyUVlViVIc7

Rails-最佳实践:如何创建依赖关系

  •  70
  • BvuRVKyUVlViVIc7  · 技术社区  · 16 年前

    你能告诉我建立有一种关系的最佳实践是什么吗?

    如果我有一个用户模型,它必须有一个配置文件…

    我怎么能做到?

    一种解决方案是:

    # user.rb
    class User << ActiveRecord::Base
      after_create :set_default_association
    
      def set_default_association
        self.create_profile
      end
    end
    

    但这看起来不太干净…有什么建议吗?

    6 回复  |  直到 7 年前
        1
  •  118
  •   Larry K    16 年前

    创建has-one关系的最佳实践是使用ActiveRecord回调 before_create 而不是 after_create . 或者使用一个甚至更早的回调来处理子进程中没有通过自己验证步骤的问题(如果有的话)。

    因为:

    • 有了良好的编码,您就有机会在验证失败时向用户显示子记录的验证。
    • 它更干净,并且由ActiveRecord显式支持——AR在保存父记录(在创建时)后自动在子记录中填充外键。然后,AR将子记录保存为创建父记录的一部分。

    如何做到这一点:

    # 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
    
        2
  •  27
  •   sites    12 年前

    您的解决方案绝对是一种很好的方法(至少在您超越它之前),但您可以简化它:

    # user.rb
    class User < ActiveRecord::Base
      has_one      :profile
      after_create :create_profile
    end
    
        3
  •  22
  •   inopinatus    7 年前

    如果这是现有大型数据库中的新关联,我将按如下方式管理转换:

    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。

        4
  •  7
  •   Andrew Vilcsak    15 年前

    可能不是最干净的解决方案,但我们已经有了一个数据库,其中有50万条记录,其中一些记录已经创建了“概要”模型,而有些记录没有创建。我们采用这种方法,可以保证概要模型在任何时候都存在,而无需遍历和追溯生成所有概要模型。

    alias_method :db_profile, :profile
    def profile
      self.profile = Profile.create(:user => self) if self.db_profile.nil?
      self.db_profile
    end
    
        5
  •  4
  •   Brendon Muir    14 年前

    我就是这样做的。不知道这有多标准,但它工作得很好,而且很懒惰,除非有必要建立新的关联,否则它不会产生额外的开销(我很高兴在此基础上得到纠正):

    def profile_with_auto_build
      build_profile unless profile_without_auto_build
      profile_without_auto_build
    end
    
    alias_method_chain :profile, :auto_build
    

    这也意味着协会在你需要的时候就在那里。我想另一种选择是在初始化后挂接,但这似乎增加了相当多的开销,因为每次初始化对象时都会运行它,有时您可能不在乎访问关联。检查它的存在似乎是浪费。

        6
  •  1
  •   linjunhalida    14 年前

    这里有一块宝石:

    https://github.com/jqr/has_one_autocreate

    看起来现在有点旧了。(不适用于轨道3)

    推荐文章