5

尽管在这里查看了一些关于 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 以便仅在读取时发生,而不是在对象的初始创建时发生。

4

4 回答 4

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

但是由于 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

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


根据您的尝试:

当你做了

def profile
  @profile || NullProfile
end

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

def profile
  self.profile || NullProfile
end

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

于 2013-03-19T18:57:25.783 回答
2

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

您可以覆盖 reader 方法并使用associationfrom 的方法获取关联的对象ActiveRecord

class User < ApplicationRecord
  has_one :profile

  def profile
    association(:profile).load_target || NullProfile
  end
end # class User
于 2016-11-21T10:39:48.183 回答
1

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

def profile
  self[:profile] || NullProfile.new
end
于 2014-04-28T16:36:54.670 回答
0

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

所以,像...

def profile
  super || NullProfile.new
end

应该为你工作。

于 2021-04-03T02:55:22.773 回答