小ネタです。
Rails の ActiveRecord で has_one 関連を使う場合、参照先が存在しないことがあります。
class Account < ApplicationRecord
def some_method
end
end
class Supplier < ApplicationRecord
has_one :account
end
Supplier.find(id).account # Account or nil
こうなると場合によってインターフェイスが合わなくなるため、メソッドチェーンをつなげるためにはあの目障りなボッチ演算子(&.
)のお世話になる必要が出ます。
Supplier.find(id).account&.some_method
これを解決する典型的な方法としては、参照先レコードが存在しない場合は nil
の代わりに Account
のダミーオブジェクト・いわゆるNullObjectを返すことでインターフェイスを保つ方法があります。
具体的には関連名と同じメソッドを定義するだけです。
class Supplier < ApplicationRecord
has_one :account
def account
# 参照先レコードが存在しない場合は has_one で自動定義される build_association を呼び出す。
super || build_account
end
end
これで憎きボッチ演算子が駆逐できました。
Supplier.find(id).account.some_method # .account は必ず Account のインスタンスなのでボッチ演算子は不要
更にActiveRecordのメソッドだってチェーンできるようになります。便利ですね。
Supplier.find(id).account.update(name: 'hoge') # insert or updateを自動判別
ここまでくるといいとこ尽くめですが、1点注意があります。
レコードが存在するかどうかの判定方法が変わります。 .nil?
, .present?
が使えません。(必ず true
になる。)
.new_record?
, .persisted?
, .id.nil?
などで判断する必要があります。
ただ、NullObjectパターンを使っていてレコードの存在を確認する必要があるということは、NullObjectパターンが適していないことが考えられますので、その場合は諦めたほうが良いかもしれません。