activerecord-Rails重写关系的默认getter(longs_to)

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

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返回最后一个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属性仅加载一次,并且如果未设置则具有默认值。

3个解决方案
71 votes

alias_method是您的朋友在这里。

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

这种工作方式是将默认的“ bar”方法别名为“ original bar”,然后实现自己的“ bar”版本。 如果对original_bar的调用返回nil,则您将返回最后一个Bar实例。

Randy Simon answered 2020-02-21T13:05:33Z
22 votes

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

def bar
  super || Bar.last
end

我希望这对您有帮助:D

alxibra answered 2020-02-21T13:05:57Z
10 votes

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


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

这将创建两个方法-bar_with_default_findbar_without_default_find,以及with方法的别名bar。 这样,您可以显式调用其中一个,也可以仅保留默认值。

Cory Foy answered 2020-02-21T13:06:24Z
translate from https://stackoverflow.com:/questions/2500775/rails-override-default-getter-for-a-relationship-belongs-to