【问题标题】:Null Object Pattern for associations in RailsRails 中关联的空对象模式
【发布时间】:2013-02-27 20:28:08
【问题描述】:

尽管在这里查看了一些关于 Rails 中的空对象的答案,但我似乎无法让它们工作。

class User < ActiveRecord::Base
  has_one :profile
  accepts_nested_attributes_for :profile

  def profile
    self.profile || NullProfile #I have also tried
    @profile || NullProfile #but it didn't work either
  end
end

class NullProfile
  def display #this method exists on the real Profile class
    ""
  end
end

class UsersController < ApplicationController
  def create
    User.new(params)
  end
end

我的问题是,在创建用户时,我为配置文件传递了正确的嵌套属性 (profile_attributes),最终我的新用户得到了一个 NullProfile。

我猜这意味着我的自定义配置文件方法在创建时被调用并返回 NullProfile。如何正确执行此 NullObject,以便仅在读取时发生,而不是在对象的初始创建时发生。

【问题讨论】:

    标签: ruby-on-rails-3 null-object-pattern


    【解决方案1】:

    我正在经历,如果它不存在,我想要一个干净的新对象(如果你这样做,那么object.display 不会出错,也许object.try(:display) 更好)这也是如此,这就是我发现:

    1:别名/alias_method_chain

    def profile_with_no_nill
      profile_without_no_nill || NullProfile
    end
    alias_method_chain :profile, :no_nill
    

    但由于 alias_method_chain 已被弃用,如果您处于领先地位,您将不得不自己手动完成模式...The answer here 似乎提供了更好、更优雅的解决方案

    2(答案的简化/实用版本):

    class User < ActiveRecord::Base
      has_one :profile
      accepts_nested_attributes_for :profile
    
      module ProfileNullObject
        def profile
          super || NullProfile
        end
      end
      include ProfileNullObject
    end
    

    注意:你做这件事的顺序(在链接的答案中解释)


    关于你的尝试:

    什么时候做的

    def profile
      @profile || NullProfile
    end
    

    它不会像预期的那样运行,因为关联是延迟加载的(除非你在搜索中告诉它:include它),所以@profile 为零,这就是你总是得到 NullProfile 的原因

    def profile
      self.profile || NullProfile
    end
    

    它会失败,因为方法正在调用自己,所以它有点像递归方法,你得到SystemStackError: stack level too deep

    【讨论】:

      【解决方案2】:

      我找到了一个比在接受的答案中包含私有模块更简单的选择。

      您可以覆盖读取器方法并使用来自ActiveRecordassociation 方法获取关联的对象。

      class User < ApplicationRecord
        has_one :profile
      
        def profile
          association(:profile).load_target || NullProfile
        end
      end # class User
      

      【讨论】:

        【解决方案3】:

        不要使用 alias_method_chain,而是使用这个:

        def profile
          self[:profile] || NullProfile.new
        end
        

        【讨论】:

          【解决方案4】:

          根据 Rails docs,关联方法被加载到模块中,因此覆盖它们是安全的。

          所以,类似...

          def profile
            super || NullProfile.new
          end
          

          应该适合你。

          【讨论】:

            猜你喜欢
            • 2013-02-20
            • 1970-01-01
            • 2013-09-24
            • 1970-01-01
            • 2015-09-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-28
            相关资源
            最近更新 更多