【问题标题】:rails override default getter for a relationship (belongs_to)rails 覆盖关系的默认 getter (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 属性只加载一次,如果未设置则具有默认值。

【问题讨论】:

    标签: ruby-on-rails activerecord associations default-value


    【解决方案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 时,这意味着记录并不总是持久化,而且任何非持久化的更改也会反映在父记录上。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-30
    • 2011-12-28
    • 2012-04-02
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    相关资源
    最近更新 更多