没有数据库的Rails模型


68

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


1
链接的博客帖子现已消失。
杰里米·B

1
prestonlee.com/2007/12/29/…,但以新名字活着。
蒂姆·斯诺怀特


1
这似乎是stackoverflow.com/questions/937429/…的重复,实际上提出了一个更好的解决方案。
Michal

Answers:



69

在Rails 3中,有一种更好的方法可以做到这一点:http : //railscasts.com/episodes/219-active-model


我投票赞成您,因为我同意这是一种更清洁,更好的方法,特别是在启动新项目时。但是,我确实发现John Topley的解决方案在一个项目上会更好,在该项目上,仍然有很多代码需要认为您的模型是ActiveRecord :: Base的子类。这种方法不易使用的一个特定示例是,如果您的代码依赖于依赖ActiveRecord的第三方插件。
托尼

6
在Rails 4中,还有ActiveModel :: Model,其中包括许多ActiveModel模块和其他魔术,使您感觉到(非持久性或自定义持久性)模型就像ActiveRecord模型一样。
nandilugio 2014年

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>>

3
效果很好,非常轻巧。Rails 2.3会抱怨脚本/控制台中缺少表,但是添加“ self.abstract_class = true”可以解决该问题(不阻止实例化)。
Andrew Hodgkinson

这对我来说似乎很可怕。如果您不希望数据库后端,为什么还要麻烦从ActiveRecord :: Base继承呢?还有其他提供验证功能的库,这些库不具有数据库后端。
David J.


@大卫。好的,那是一个。还有其他吗?
雷金2010年

仅作记录:第一个选项(stackoverflow.com/questions/3416484/…)仅适用于Rails 3。
gorn 2011年

23

现在有一种更简单的方法:

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


2
这是现在要走的路
Alex Rodriguez Lopez

7

只需在您的“ models /”目录中遵循您惯用的约定(文件名和类名为单数,下划线为文件名,驼峰为类名)创建一个以“ .rb”结尾的新文件。这里的关键是不要从ActiveRecord继承您的模型(因为是AR提供了数据库功能)。例如:对于新的汽车模型,请在您的models /目录和模型内部创建一个名为“ 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类,也许您会找到更好的解决方案;)


2
但这并没有给他提供AR验证。
Mike Breen

好点子。我敢打赌,这两种解决方案都有很多用例:)
tpinto

5

为了完整性:

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

include ActiveModel::Model

这使您可以使用哈希进行初始化,以及使用验证等功能。

完整的文档在这里




2

将类标记为抽象怎么办?

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

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

[编辑]

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

my_car = Car.new


1

有人曾经试图包括ActiveRecord::ValidationsActiveRecord::Validations::ClassMethods在非Active Record类,看看想设置验证时,会发生什么?

我确信验证框架和ActiveRecord本身之间存在很多依赖关系。但是您可以通过从AR验证框架中派生自己的验证框架来成功摆脱那些依赖关系。

只是一个想法。

更新:糟糕,这或多或少是与您的问题相关的博文中所建议的内容。对不起,打扰了。


1
您的答案现在很有用,因为该博客文章不再存在。
epochwolf,2010年

0

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

config.frameworks -= [:active_record]

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


就像Tiago Pinto的答案一样,这不会帮助我们的朋友在他的课堂上使用AR验证。
Mike Breen

0

您应该签出PassiveRecord插件。它为非数据库模型提供了类似于ActiveRecord的界面。这很简单,并且比与ActiveRecord战斗更省力。

我们将PassiveRecord与Validatable gem结合使用,以获取OP所需的行为。


这些天,我可能会包括ActiveModel以及我需要的其他任何东西。
泰特·约翰逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.