繁体   English   中英

Rails的模型属性有时是虚拟的,有时是真实的

[英]Rails model attributes that are sometimes virtual and sometimes real

我有一个非常复杂的Rails(v 3.2)模型,正在对多个表进行手动选择。 这对于获取显示模型所需的所有数据非常有用。 但是,当我的数据不存在并且必须创建一个虚拟对象时,这些列在我的模型中就不存在。 对于我的一生,我想不出一种方法来支持模型上的虚拟列和实际列。

比这复杂得多,但这是我目前拥有的一般选择:

class MyObject < ActiveRecord::Base

  attr_accessible :apples, :bananas, :oranges

  def self.get(id)
    select("my_objects.*, table1.apples, table2.bananas, table3.oranges")
      .joins("left outer join table1 on something
              left outer join table2 on something
              left outer join table2 on something")
      .where(:my_object => id)
  end
end

id存在时,此功能非常适合我需要显示的内容。 但是,在某些情况下, id不存在,因此我必须显示一个虚拟(或默认)对象。

我以为我可以为该虚拟对象做这样的事情:

@my_object = MyObject.new({:apples => 1,
                           :bananas => 50,
                           :oranges => 10})

但是当然,在视图中,当我执行@my_object.apples ,会出现错误,因为MyObject实际上没有这些列:

ActionView::Template::Error (unknown attribute: apples)

我下一步是将attr_accessor添加到MyObject模型:

attr_accessor :apples, :bananas, :oranges

这对于MyObjectvirtual版本非常理想。 但是现在,当试图显示对象的真实版本时,我所有的苹果,香蕉和橙子都为零! 我认为这是因为attr_accessor getter和setter覆盖了select返回的内容。

如何在此模型上同时支持虚拟属性和实际属性?

ps我尝试了多种使用method_missingdefine_method ,但是一直无法获得成功的东西。

有趣的问题。

一种方法是像这样为虚拟属性定义setter方法

# MyObject.rb

def set_virtual_attribs=(hsh)
 hsh.map{|key,value|  self[key] = value}
end

然后可以像这样创建一个虚拟对象

@my_object = MyObject.new(:set_virtual_attribs => {
                           :apples => 1,
                           :bananas => 50,
                           :oranges => 10
                         })

现在,虚拟属性应以@my_object.apples形式提供,并且除非调用set_virtual_attribs否则它不会覆盖任何实际对象的属性方法。

我建议研究一下Null对象模式 我认为这些思路对您的情况会有所帮助。

通常的想法是,创建一个可以代替原始对象的对象,而不用在各处进行nil检查,并使用一些合理的默认值。

我假设class MyObject定义之外的内容决定了何时id不存在,因此您需要进行@my_object = MyObject.new({:apples => 1,...调用。而不是创建实例。在MyObject那里,您可以拥有一个不同的类,例如:

class MyNilObject
  def apples
    1
  end

  def bananas
    50
  end

  def oranges
    10
  end
end

然后执行@my_object = MyNilObject.new 如果要求您能够动态设置这些默认值,则可以有一个带有哈希值,分配属性并具有attr_readers的def initialize

此类将是一个普通的旧Ruby对象,它将没有任何数据库持久性。 它需要实现您的视图在MyObject实例上调用的任何其他方法。

我不确定在渲染对象后在这种情况下要做什么,因此您可能需要在该对象上实现诸如create的方法,该方法会将其转换为MyObject的实例并将其潜在地保存在数据库中。

您可以覆盖模型中的访问器方法:

class MyObject < ActiveRecord::Base

  def apples
    read_attribute(:apples) || 1
  end

  # etc ....
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM