【问题标题】:Rails model without database没有数据库的 Rails 模型
【发布时间】:2010-09-23 20:54:03
【问题描述】:

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

【问题讨论】:

标签: ruby-on-rails ruby activerecord


【解决方案1】:

只需按照您习惯的约定(文件名和类名单数,文件名用下划线,类名用驼峰式大小写)在“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 类,也许你会发现这个解决方案更好;)

【讨论】:

  • 但这并没有给他 AR 验证。
  • 好点。我敢打赌这两种解决方案都有很多用例:)
【解决方案2】:

如何将类标记为抽象类?

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

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

[编辑]

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

my_car = Car.new

【讨论】:

    【解决方案3】:

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

    【讨论】:

    【解决方案4】:

    有一个关于非 Active Record 模型的 screencast,由 Ryan Bates 组成。一个很好的起点。

    以防万一你还没有看过。

    【讨论】:

    • 同样,这并不能解决使用 AR 验证的海报问题。
    • 我在我的应用程序中按照这些说明进行操作,效果很好。
    【解决方案5】:

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

    config.frameworks -= [:active_record]
    

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

    【讨论】:

    • 就像 Tiago Pinto 的回答一样,这不会帮助我们的朋友在他的课堂上使用 AR 验证。
    【解决方案6】:

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

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

    【讨论】:

    • 运行良好且非常轻巧。 Rails 2.3 会抱怨脚本/控制台缺少表格,但添加“self.abstract_class= true”可以解决这个问题(不阻止实例化)。
    • 这对我来说似乎很可怕。如果您不想要数据库后端,为什么还要从 ActiveRecord::Base 继承呢?还有其他库提供了不假设数据库后端的验证功能。
    • @大卫。好的,这是一个。还有其他人吗?
    • 仅作记录:第一个选项 (stackoverflow.com/questions/3416484/…) 仅适用于 Rails 3。
    【解决方案7】:

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

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

    只是一个想法。

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

    【讨论】:

    • 您的回答现在很有用,因为该博文已不存在。
    【解决方案8】:

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

    http://validatable.rubyforge.org/

    【讨论】:

      【解决方案9】:

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

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

      【讨论】:

      • 这些天我可能会加入 ActiveModel 和我需要的任何其他东西。
      【解决方案10】:

      按照 John Topley 的建议,我已经构建了一个快速的 Mixin 来处理这个问题。

      http://github.com/willrjmarshall/Tableless

      【讨论】:

        【解决方案11】:

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

        【讨论】:

        • 我投票给你是因为我同意这是一种更清洁、更好的方法,尤其是在开始一个新项目时。但是,我确实发现 John Topley 的解决方案在很多代码仍然需要认为您的模型是 ActiveRecord::Base 的子类的项目中更好。如果您的代码依赖于依赖于 ActiveRecord 的 3rd 方插件,则此方法不容易工作的一个具体示例。
        • 在 Rails 4 中还有 ActiveModel::Model,它包括许多 ActiveModel 模块和一些其他的魔法,让你感觉你的(非持久化或自定义持久化)模型就像一个 ActiveRecord 模型.
        【解决方案12】:

        现在有更简单的方法:

        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

        【讨论】:

        • 这是现在要走的路
        【解决方案13】:

        为了完整起见:

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

        include ActiveModel::Model

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

        完整文档是here

        【讨论】:

          猜你喜欢
          • 2012-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-31
          相关资源
          最近更新 更多