Null Object Pattern for associations in Rails

*爱你&永不变心* 提交于 2019-12-04 08:48:47
Breno Salgado

I was going exactly through and I wanted a clean new object if it wasn't present(if you're doing this just so object.display doesn't err maybe object.try(:display) is better) this too and this is what I found:

1: alias/alias_method_chain

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

But since alias_method_chain is being deprecated, if you're staying on the edge you would have to do the pattern by yourself manually... The answer here seems to provide the better and more elegant solution

2(Simplified/practical version from the answer):

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

  module ProfileNullObject
    def profile
      super || NullProfile
    end
  end
  include ProfileNullObject
end

note: The order you do this matter(explained in the linked answer)


On what you tried:

When you did

def profile
  @profile || NullProfile
end

It won't behave as expected because the Association is lazily loaded(unless you told it to :include it in the search), so @profile is nil, that's why you're always getting NullProfile

def profile
  self.profile || NullProfile
end

It will fail because the method is calling itself, so it's sort like a recursive method, you get SystemStackError: stack level too deep

I've found a simpler option than including a private module in the accepted answer.

You can override the reader method and fetch the associated object using the association method from ActiveRecord.

class User < ApplicationRecord
  has_one :profile

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

Instead of using alias_method_chain, use this:

def profile
  self[:profile] || NullProfile.new
end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!