web-dev-qa-db-ja.com

rails関係のデフォルトのゲッターをオーバーライドする(belongs_to)

だから私はActiveRecordオブジェクトの属性のデフォルトのgetterをオーバーライドする方法を知っています

def custom_getter
  return self[:custom_getter] || some_default_value
end

同じことを達成しようとしていますが、所属団体に所属しています。例えば。

class Foo < AR
  belongs_to :bar

  def bar
    return self[:bar] || Bar.last
  end
end

class Bar < AR
  has_one :foo
end

私が言ったら:

f = Foo.last

メソッドf.barその関連付けがまだ存在しない場合、nilではなく、最後のバーを返します。

ただし、これは機能しません。その理由は、self [:bar]は常に未定義であるためです。それは実際にはself [:bar_id]です。

私は次のような素朴なことをすることができます:

def bar
  if self[:bar_id]
    return Bar.find(self[:bar_id])
  else
    return Bar.last
  end
end

ただし、Barがすでにフェッチされている場合でも、これは常にdb呼び出しを行います。これは確かに理想的ではありません。

誰かが、belongs_to属性が1度だけロードされ、設定されていない場合はデフォルト値を持つような関係を持つ方法について洞察がありますか?.

48
brad

alias_methodはあなたの友達です。

alias_method :original_bar, :bar
def bar
  self.original_bar || Bar.last
end

これが機能する方法は、デフォルトの「バー」メソッドを「元のバー」としてエイリアスし、独自のバージョンの「バー」を実装することです。 original_barの呼び出しがnilを返す場合は、代わりに最後のBarインスタンスを返します。

71
Randy Simon

「スーパー」を使用するのが最善の方法であることがわかりました

def bar
  super || Bar.last
end

これがあなたのお役に立てば幸いです:D

22
alxibra

ランディの答えはスポットですが、alias_method_chainを使用してそれを書く簡単な方法があります:


def bar_with_default_find
  self.bar_without_default_find || Bar.last
end
alias_method_chain :bar, :default_find

これにより2つのメソッドが作成されます-bar_with_default_findおよびbar_without_default_findbarメソッドのエイリアスwith。これにより、どちらか一方を明示的に呼び出すか、デフォルトのままにすることができます。

10
Cory Foy