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

Posted

技术标签:

【中文标题】rails 覆盖关系的默认 getter (belongs_to)【英文标题】:rails override default getter for a relationship (belongs_to) 【发布时间】:2011-01-30 20:12:40 【问题描述】:

所以我知道如何使用

覆盖 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 方法返回最后一个 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

然而,这总是会进行 db 调用,即使 Bar 已经被获取,这当然不理想。

有没有人了解我如何建立这样的关系,即 belongs_to 属性只加载一次,如果未设置则具有默认值。

【问题讨论】:

【参考方案1】:

alias_method 是你的朋友。

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

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

【讨论】:

你没有那个循环吗?因为在 bar 中调用 bar ? 不,你叫“original_bar”,这是“bar”的新名称。 一件事让我很头疼,就是要记住在新的别名方法之前调用 alias_method 第 3 行不能只是 original_bar || Bar.last 更好:super || Bar.last【参考方案2】:

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

def bar
  super || Bar.last
end

希望对你有帮助:D

【讨论】:

这是一个很好的答案,因为它只是使用普通的旧 Ruby 继承。而且它比公认的答案要简单得多。【参考方案3】:

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 并将 bar 别名为 with 方法。这样您就可以显式调用其中一个,或者保留默认值。

【讨论】:

很酷的解决方案,因为您可以使用_without_default_find 来了解原始关联方法的概念。是我唯一能够开始工作的人。谢谢 我相信alias_method_chain 现在已被弃用。【参考方案4】:

基于此处的其他答案,您可能还想处理分配操作。

别名方法:

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

超级方法:

def bar
  super || bar = Bar.last
end

这对我有用的地方是在使用 Bar.find_or_initialize_by 时,这意味着记录并不总是持久化,而且任何非持久化的更改也会反映在父记录上。

【讨论】:

这并没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review 我的答案与已接受的解决方案具有相同的逻辑,但对其进行了扩展以进行分配操作。

以上是关于rails 覆盖关系的默认 getter (belongs_to)的主要内容,如果未能解决你的问题,请参考以下文章

覆盖 getter 只需要 @synthesize

覆盖rails3中模型名称的默认复数

自定义 rails 确认框(带有 $.rails.confirm 覆盖)

Dart中类的getter和setter

Rails:rails 模型的默认排序顺序?

覆盖 Kotlin 数据类的 getter