Rails中关联的空对象模式

Ric*_*ard 5 null-object-pattern ruby-on-rails-3

尽管在这里看到一些关于轨道中的Null对象的答案,我似乎无法让它们工作.

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
Run Code Online (Sandbox Code Playgroud)

我的问题是在用户创建时,我为配置文件传递了适当的嵌套属性(profile_attributes),最后我的新用户使用了NullProfile.

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

Bre*_*ado 3

我正在经历,如果它不存在,我想要一个干净的新对象(如果你这样做只是为了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
Run Code Online (Sandbox Code Playgroud)

但由于 alias_method_chain 已被弃用,如果您处于边缘,您将不得不自己手动执行该模式...这里的答案似乎提供了更好、更优雅的解决方案

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

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

  module ProfileNullObject
    def profile
      super || NullProfile
    end
  end
  include ProfileNullObject
end
Run Code Online (Sandbox Code Playgroud)

注意:您执行此操作的顺序(在链接的答案中进行了解释)


关于你尝试过的:

当你这样做的时候

def profile
  @profile || NullProfile
end
Run Code Online (Sandbox Code Playgroud)

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

def profile
  self.profile || NullProfile
end
Run Code Online (Sandbox Code Playgroud)

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