70

我想创建一个带有 ActiveRecord 验证但没有数据库表的 Rails(2.1 和 2.2)模型。最广泛使用的方法是什么?我发现了一些声称提供此功能的插件,但其中许多似乎并未被广泛使用或维护。社区建议我做什么?现在,我倾向于根据这篇博文提出自己的解决方案。

4

13 回答 13

70

在 Rails 3 中有一个更好的方法:http ://railscasts.com/episodes/219-active-model

于 2010-09-30T13:29:14.087 回答
43

这是我过去使用的一种方法:

app/models/tableless.rb

class Tableless < ActiveRecord::Base
  def self.columns
    @columns ||= [];
  end

  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
      sql_type.to_s, null)
  end

  # Override the save method to prevent exceptions.
  def save(validate = true)
    validate ? valid? : true
  end
end

app/models/foo.rb

class Foo < Tableless
  column :bar, :string  
  validates_presence_of :bar
end

脚本/控制台中

Loading development environment (Rails 2.2.2)
>> foo = Foo.new
=> #<Foo bar: nil>
>> foo.valid?
=> false
>> foo.errors
=> #<ActiveRecord::Errors:0x235b270 @errors={"bar"=>["can't be blank"]}, @base=#<Foo bar: nil>>
于 2008-11-25T21:22:42.460 回答
25

现在有更简单的方法:

class Model
  include ActiveModel::Model

  attr_accessor :var

  validates :var, presence: true
end

ActiveModel::Model代码:

module ActiveModel
  module Model
    def self.included(base)
      base.class_eval do
        extend  ActiveModel::Naming
        extend  ActiveModel::Translation
        include ActiveModel::Validations
        include ActiveModel::Conversion
      end
    end

    def initialize(params={})
      params.each do |attr, value|
        self.public_send("#{attr}=", value)
      end if params
    end

    def persisted?
      false
    end
  end
end

http://api.rubyonrails.org/classes/ActiveModel/Model.html

于 2015-12-18T11:45:27.780 回答
9

我认为您链接的博客文章是最好的方法。我只建议将存根的方法移到一个模块中,以免污染您的代码。

于 2008-11-25T15:20:49.600 回答
7

只需按照您习惯的约定(文件名和类名的单数,文件名的下划线,类名的驼峰式大小写)在“models/”目录中创建一个以“.rb”结尾的新文件。这里的关键是不要从 ActiveRecord 继承你的模型(因为它是为你提供数据库功能的 AR)。例如:对于汽车的新模型,在您的模型/目录和模型内部创建一个名为“car.rb”的文件:

class Car
    # here goes all your model's stuff
end

编辑:顺便说一句,如果你想要你的类的属性,你可以在这里使用你在 ruby​​ 上使用的所有东西,只需使用“attr_accessor”添加几行:

class Car
    attr_accessor :wheels # this will create for you the reader and writer for this attribute
    attr_accessor :doors # ya, this will do the same

    # here goes all your model's stuff
end

编辑#2:在阅读了 Mike 的评论之后,如果您想要 ActiveRecord 的所有功能但在数据库中没有表,我会告诉您按照他的方式行事。如果你只想要一个普通的 Ruby 类,也许你会发现这个解决方案更好;)

于 2008-11-25T01:14:01.730 回答
5

为了完整起见:

Rails 现在(在 V5 中)有一个方便的模块,您可以包括:

include ActiveModel::Model

这允许您使用哈希进行初始化,并使用验证等。

完整的文档在这里

于 2017-06-30T14:48:36.183 回答
4

有一个关于非 Active Record 模型的截屏视频,由 Ryan Bates 制作。一个很好的起点。

以防万一您还没有观看。

于 2008-11-25T15:23:28.020 回答
4

根据 John Topley 的建议,我已经建立了一个快速的 Mixin 来处理这个问题。

http://github.com/willrjmarshall/Tableless

于 2010-06-18T03:51:54.710 回答
2

将类标记为抽象类怎么样?

class Car < ActiveRecord::Base
  self.abstract = true
end

这将告诉 Rails Car 类没有对应的表。

[编辑]

如果您需要执行以下操作,这不会真正帮助您:

my_car = Car.new
于 2008-11-25T01:18:38.523 回答
2

使用可验证的 gem。正如您所说,有基于 AR 的解决方案,但它们往往很脆弱。

http://validatable.rubyforge.org/

于 2009-05-12T03:52:08.093 回答
1

有没有人尝试过在非 Active Record 类中包含和查看尝试设置验证器时会发生什么ActiveRecord::ValidationsActiveRecord::Validations::ClassMethods

我确信验证框架和 ActiveRecord 本身之间有很多依赖关系。但是您可以通过从 AR 验证框架中分叉出您自己的验证框架来成功摆脱这些依赖关系。

只是一个想法。

更新:哎呀,这或多或少是与您的问题相关的帖子中的建议。对不起,打扰了。

于 2008-11-26T10:21:44.743 回答
0

就像 Tiago Pinto 所说的那样,只是不要让你的模型从 ActiveRecord::Base 继承。它只是一个常规的 Ruby 类,您将其粘贴在 app/models/ 目录中的文件中。如果您的模型都没有表并且您的应用程序中根本没有使用数据库或 ActiveRecord,请务必修改您的 environment.rb 文件以具有以下行:

config.frameworks -= [:active_record]

这应该在Rails::Initializer.run do |config|块内。

于 2008-11-25T16:24:44.073 回答
0

你应该检查PassiveRecord插件。它为非数据库模型提供了一个类似于 ActiveRecord 的接口。这很简单,而且比对抗 ActiveRecord 更轻松。

我们将 PassiveRecord 与Validatable gem 结合使用来获得 OP 所需的行为。

于 2009-07-18T04:46:42.233 回答