没有数据表的Rails模型

41
我想创建一个选择列表,比如颜色,但不想为颜色创建表格。我在哪里看到过它,但在Google上找不到。
我的问题是:如何在没有数据库表的情况下将颜色放入模型中?
还是有更好的Rails方式来做这个?
我见过有人直接在模型中放置数组或哈希表,但现在我找不到了。

1
可能是没有数据库的Rails模型的重复问题。 - Ciro Santilli OurBigBook.com
我想将其用于复杂搜索过滤表单,以保存表单值但不保存到数据库中。 - Chloe
7个回答

66
class Model

  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :whatever

  validates :whatever, :presence => true

  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end

end

attr_accessor将创建您的属性,您将使用initialize()创建对象并设置属性。

方法persisted将告诉您与数据库没有链接。 您可以找到类似这样的示例: http://railscasts.com/episodes/219-active-model?language=en&view=asciicast 这将为您解释逻辑。


28

答案适用于2013年,但自Rails 4以来ActiveRecord的所有与数据库无关的特性都被提取到ActiveModel中。此外,有一个很棒的官方指南可供参考。

您可以包含所需数量的模块,也可以只包含部分模块。

例如,您只需要include ActiveModel::Model,就可以放弃这样一个initialize方法:

def initialize(attributes = {})
  attributes.each do |name, value|
    send("#{name}=", value)
  end
end

只需使用:

attr_accessor :name, :age

1
整洁但似乎不允许使用belongs_to。我想使用@filterModel.sector.name并在模型中使用sector_id - Chloe
include ActiveModel::Model allows also to avoid the cancan ArgumentError: cancancan (3.0.0) lib/cancan/controller_resource_builder.rb:8:in initialize'` - iGian
在2022年,使用ActiveModel是正确的方法。 - mthorley

11
最简单的答案就是不要从ActiveRecord::Base进行子类化。然后你可以直接编写你的对象代码。

4
那么,文件color.rb只需要写上 def Color [一些对象代码] end 就可以了。它只是一个普通的对象。 - Scott S
1
抱歉,我觉得我没有理解。除非您想保留其他类似表格的行为,否则没有表格的模型只是一个对象。要添加数组或哈希,只需将其作为实例或类变量添加到对象中(在此处有解释:http://railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/)。 - Scott S
这篇文章在我使用Rails 4.2时无法工作--在前两行class_inheritable_accessorself.columns上出现了“未定义的方法”错误,针对的是MyModel(表不存在):Class - Don Cheadle
与 Rails 4.2 至少不相符,所链接的文章并未解决问题。然而,该文章链接了另一篇文章,可提供帮助:http://snipplr.com/view/1849/tableless-model/。 - Don Cheadle
文章链接已损坏。 - Michael Minter
显示剩余3条评论

6

在Rails 6中对我有效的方法:

class MyClass
  include ActiveModel::Model

  attr_accessor :my_property
end

2
如果你需要一个没有关联表的模型来创建一个抽象类,让真正的模型继承它,ActiveRecord支持这一点:
class ModelBase < ActiveRecord::Base
  self.abstract_class = true
end

请注意,在Rails 6.0中,抽象类无法实例化;ModelBase.new会引发NotImplementedError异常。 - Masa Sakano
1
@MasaSakano 在Rails 6中也不需要了。ActiveModel已经是具有abstract_classActiveRecord所拥有的东西了。 - Itay Grudev
ActiveModel和ActiveRecord是不同的。例如,如果一个对象包含了ActiveModel,则可以在表单和视图中使用该模型。但是它不允许您使用store_accessor这样在ActiveRecord中定义的方法。在我的情况下,我想测试一些concerns,但不是通过测试我在其中包含模块的ActiveRecord对象,而是在测试文件中定义一个“虚拟”的或新的对象。这是不可能仅仅通过包含ActiveModel来实现的,因为concern使用了scopestore_accessor - chopi321

1
如果您想要一个不变的选择列表,您可以在您的ApplicationHelper中定义一个方法来返回一个列表,例如:
 def my_color_list
   [
     "red",
     "green",
     "blue"
   ]
 end

是的,但 collection_select 只接受响应方法名称的模型。http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select - Chloe

0
我正在使用Rails 7,但我认为这在Rails 6中也适用。
class MyModel
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :title, :string
  attribute :created_at, :datetime
end

我更喜欢这种方式,而不是使用attr_accessor,因为它允许我将属性解析为数据类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接