尽管在这里看到一些关于轨道中的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
我的问题是在用户创建时,我为配置文件传递了正确的嵌套属性(profile_attributes),最后我的新用户使用了NullProfile。
我猜这意味着我的自定义配置文件方法在创建时被调用并返回NullProfile。我如何正确地执行此NullObject,以便这只在读取时发生,而不是在对象的初始创建时发生。
答案 0 :(得分:3)
我完全准备好了,如果它不存在我想要一个干净的新对象(如果你这样做那么object.display
不错,也许object.try(:display)
更好)这也是这就是我发现的:
1:alias / 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是nil,这就是为什么你总是得到NullProfile
def profile
self.profile || NullProfile
end
它会失败,因为该方法正在调用自身,因此它类似于递归方法,您得到SystemStackError: stack level too deep
答案 1 :(得分:1)
不使用alias_method_chain,请使用:
def profile
self[:profile] || NullProfile.new
end
答案 2 :(得分:1)
我找到了一个比接受答案中包含私人模块更简单的选项。
您可以使用association
中的ActiveRecord
方法覆盖reader方法并获取关联的对象。
class User < ApplicationRecord
has_one :profile
def profile
association(:profile).load_target || NullProfile
end
end # class User
答案 3 :(得分:0)