如何在Rails 3中创建没有数据表的ActiveRecord模型

17

我正在尝试创建一个Active Record的无表模型。我的user.rb文件如下:

class User < ActiveRecord::Base

  class_inheritable_accessor :columns

  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


  column :name, :text
  column :exception, :text
  serialize :exception      
end

在控制器中创建新对象时

@user = User.new

我得到了这个错误

Mysql2::Error: 表'Sampledb.users'不存在:SHOW FIELDS FROM users


1
为什么需要无表模型?你可以只使用 Ruby 类,而不是使用它吗?如果你需要非数据库功能并且正在使用 Rails3,你可以看一下我的回答。 - ducktyped
7个回答

32
class Tableless

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

  def self.attr_accessor(*vars)
    @attributes ||= []
    @attributes.concat( vars )
    super
  end

 def self.attributes
   @attributes
 end

 def initialize(attributes={})
   attributes && attributes.each do |name, value|
     send("#{name}=", value) if respond_to? name.to_sym 
   end
 end

def persisted?
  false
end

def self.inspect
  "#<#{ self.to_s} #{ self.attributes.collect{ |e| ":#{ e }" }.join(', ') }>"
end

end

1
这基本上就是在http://railscasts.com/episodes/219-active-model?view=asciicast中所述的内容,加上了一些不错的功能,但它们是很好的功能。 - fearless_fool
1
在Rails 4中,还有ActiveModel :: Model,它包括许多ActiveModel模块和一些其他魔法,使您感觉到您的(非持久或自定义持久)模型就像一个ActiveRecord模型。 - nandilugio

8

以下是需要注意的几点:

首先,您正在使用Rails2中在Railscast 193中阐述的方法,但实际上您应该使用Rails 3中在Railscast 219中阐述的方法。

在这种情况下,您可能不想从ActiveRecord :: Base继承。

请阅读Yehuda Katz的博客文章了解更多信息。


+1 说明OP不想继承ActiveRecord :: Base,并展示了Rails 3的替代方法。我之前没有看过Katz的帖子——它对Ryan的Railcast 219有有用的扩展。谢谢你。 - fearless_fool

1

stephenmurdochrails 3.0+ 中提到的那样,您可以使用 railscasts 219 中概述的方法。

我不得不稍微修改一下才能使它正常工作:

class Message
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :name, :email, :content

  validates_presence_of :name
  validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
  validates_length_of :content, :maximum => 500

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

  def persisted?
    false
  end
end

0

只需删除:

class_inheritable_accessor :columns

它应该可以正常工作,即使涉及到与表格类似的关联。


0

对于仍然困惑的任何人。 对于rails 2.x.x

class TestImp < ActiveRecord::Base

  def self.columns
    @columns ||= []
  end
end

对于Rails 3.1.x,您可以选择在不继承ActiveRecord的情况下包含ActiveModel(如@ducktyped所解释的),或者如果由于某些原因确实需要继承ActiveRecord :: Base,则可以使用上述方法并进行以下一项其他添加:

class TestImp < ActiveRecord::Base

  def attributes_from_column_definition
    []
  end

  def self.columns
    @columns ||= []
  end
end

0
对于 Rails >= 3.2,有一个叫做 activerecord-tableless 的宝石。它是用来创建无表 ActiveRecord 模型的宝石,因此支持验证、关联和类型。
当你在 Rails 3.x 中使用推荐的方法时,不支持关联和类型。

0
不要从ActiveRecord::Base继承你的类。 如果一个模型像你期望的模型类一样从ActiveRecord::Base继承,它会想要有一个数据库后端。

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