rails覆盖关系的默认getter(belongs_to)

bra*_*rad 47 activerecord ruby-on-rails associations default-value

所以我知道如何覆盖ActiveRecord对象的属性的默认getter

def custom_getter
  return self[:custom_getter] || some_default_value
end
Run Code Online (Sandbox Code Playgroud)

我试图实现相同的东西,但属于一个属于协会.例如.

class Foo < AR
  belongs_to :bar

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

class Bar < AR
  has_one :foo
end
Run Code Online (Sandbox Code Playgroud)

当我说:

f = Foo.last
Run Code Online (Sandbox Code Playgroud)

我想让方法f.bar返回最后一个Bar,而不是nil,如果该关联还不存在.

但这不起作用.原因是self [:bar]总是未定义的.它实际上是自我[:bar_id].

我可以做一些天真的事情:

def bar
  if self[:bar_id]
    return Bar.find(self[:bar_id])
  else
    return Bar.last
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,即使已经获取了Bar,这也总是会进行db调用,这当然不是理想的.

有没有人能够了解我如何建立关系,以便belongs_to属性只加载一次,如果没有设置则具有默认值.

Ran*_*mon 71

alias_method是你的朋友.

alias_method :original_bar, :bar
def bar
  self.original_bar || Bar.last
end
Run Code Online (Sandbox Code Playgroud)

这样做的方法是将默认的"bar"方法别名为"原始栏",然后实现自己的"bar"版本.如果对original_bar的调用返回nil,则返回最后一个Bar实例.

  • 第3行不能只是`original_bar || Bar.last` (5认同)
  • 更好:`超级|| 酒吧最后` (4认同)

alx*_*bra 22

我发现使用"超级"是最好的方法

def bar
  super || Bar.last
end
Run Code Online (Sandbox Code Playgroud)

我希望这会对你有所帮助:D

  • 这是一个很好的答案,因为它只使用普通的旧 Ruby 继承。它比公认的答案简单得多。 (3认同)

Cor*_*Foy 10

Randy的答案很明显,但使用alias_method_chain可以更轻松地编写它:


def bar_with_default_find
  self.bar_without_default_find || Bar.last
end
alias_method_chain :bar, :default_find
Run Code Online (Sandbox Code Playgroud)

这就产生了两个方法- bar_with_default_findbar_without_default_find和别名barwith方法.这样你就可以明确地调用其中一个,或者只保留默认值.