17

I am trying to create a Active Record tableless Model. My user.rb looks like this

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

When creating the new object in controller

@user = User.new

I am getting the error

Mysql2::Error: Table 'Sampledb.users' doesn't exist: SHOW FIELDS FROM users

animuson
  • 53,861
  • 28
  • 137
  • 147
Achaius
  • 5,904
  • 21
  • 65
  • 122
  • 1
    Why do you need tableless model. You can just simply have a ruby class instead? And if you need non database functionality and using Rails3, you can see my answer down. – ducktyped Feb 03 '12 at 05:22

7 Answers7

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
ducktyped
  • 4,354
  • 4
  • 26
  • 38
  • 1
    This is essentially what's spelled out in http://railscasts.com/episodes/219-active-model?view=asciicast with some added bells and whistles, but they are nice bells and whistles. – fearless_fool Sep 05 '12 at 18:25
  • 1
    In Rails 4 there is also ActiveModel::Model, which includes many of the ActiveModel modules and some other magic, to make you feel your (non-persisted or custom-persisted) model like an ActiveRecord model. – nandilugio Sep 17 '14 at 12:49
8

Few things:

Firstly you are using the Rails2 approach outlined in Railscast 193 when really you should be using the Rails 3 approach, outlined in Railscast 219

You probably don't want to inherit from ActiveRecord::Base when doing this sort of thing.

Read Yehuda Katz's blog post on this.

Substantial
  • 6,684
  • 2
  • 31
  • 40
stephenmurdoch
  • 34,024
  • 29
  • 114
  • 189
  • +1 for explaining that the OP doesn't want to inherit from ActiveRecord::Base AND for showing what to do instead for Rails 3. I hadn't seen Katz's post before -- it has useful extensions to Ryan's Railcast 219. Thank you for that. – fearless_fool Sep 05 '12 at 18:28
1

As mentioned by stephenmurdoch in rails 3.0+ you can use the method outlined in railscasts 219

I had to make a slight modification to get this to work:

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
Justin Tanner
  • 14,062
  • 17
  • 82
  • 103
0

Just remove:

class_inheritable_accessor :columns

And it should work, even with associations just like a model with a table.

miligraf
  • 1,042
  • 9
  • 22
0

Just for anyone still struggling with this. For rails 2.x.x

class TestImp < ActiveRecord::Base

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

For rails 3.1.x you can either include ActiveModel (as explained by @ducktyped) without inheriting from ActiveRecord or If you do need to inherit from ActiveRecord::Base due to some reason then the above with one other addition:

class TestImp < ActiveRecord::Base

  def attributes_from_column_definition
    []
  end

  def self.columns
    @columns ||= []
  end
end
nas
  • 3,676
  • 19
  • 19
0

For Rails >= 3.2 there is the activerecord-tableless gem. Its a gem to create tableless ActiveRecord models, so it has support for validations, associations, types.

When you are using the recommended way to do it in Rails 3.x there is no support for association nor types.

Jarl
  • 2,831
  • 4
  • 24
  • 31
0

Don't inherit your class from ActiveRecord::Base.
If a model inherits from ActiveRecord::Base as you would expect a model class to,it wants to have a database back-end.

Jatin Ganhotra
  • 6,825
  • 6
  • 48
  • 71