#193 Tableless Model
Dec 21, 2009 | 8 minutes | Active Record
If you want to create a model without a database backend, you simply need to define a couple methods in the model like I show in this episode.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
Very cool. I'm playing with mongodb on a new project at the moment, any chance you plan on looking into any NoSQL stuff?
Thanks again Ryan!
Hi there,
Great cast again!
Like Ryan, I also researched the topic on table-less models about two months ago. While there are other solutions, I too chose the one Ryan liked most. Here's my implementation:
# Define an abstract base class for Tableless ActiveRecord models:
# and then use it like that:
# class Foo < TablelessModel
# column :bar, :string
# validates_presence_of :bar
# end
class TablelessModel < 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
I use it in a bit different way though: I have a base model class called TablelessModel and inherit from it whenever needed.
I needed table-less models because in my applications I frequently have some more complicated reports, which need more complex SQL queries. Since the SQL queries etc belong in the models, I started implementing them as (class or instance) methods in the models. But I didn't like cluttering my models with code that sometimes doesn't belong there, like some find_by_sqls needed by some report. So I implemented my models to deal with the DB tables/resources and wherever needed, I implemented table-less models to hold the report SQL queries and other logic.
I'm writing this as a possible use case of this techinque, although my own table-less models often do have to deal with the database, just not with an existing table.
:member => {:recommend => [:any]}
No need for table, model, controller. Just a little action to the articles controller.
Almost exactly the same but also does the before and after callbacks:
http://github.com/remvee/active_form
Hello Ryan
great episode as always! :)
I am doing an application that requires multi-field search, you said in the episode that you always store user submitted information in the database. What would be the reason for storing searches in a database? I am asking because I am struggling with the concept of having table-less search or not.
Thanks for covering this, Ryan. Another great episode :-) Keep up the good work!
Ryan, we are waiting for MongoDB railscast :) Please make us happy!
Ryan - another great screencast - thanks!
I thought I'd point out James Golick's latest tool - FriendlyORM.
It's similar in concept to what you cover here, but packaged up neatly with a few additional features.
Check it at http://github.com/jamesgolick/friendly
@Ryan:
Thanks for the episode!
Still, I believe this may soon become obsolete with the work being done in the ActiveModel project, which extracts validations, callbacks, etc. from ActiveRecord and ActiveModel.
Generally, I prefer a plain Ruby class whenever I need a tableless model. It's also good practice if you want to move towards NoSQL design and storage.
@Bjarki:
A good reason to store searches in your database might be logging, especially of empty searches (i.e. those returning no results).
Also, you could investigate collaborative filtering and provide automated recommendations based on previous searches.
Another plus comes form the url generated when creating a search. This url could be emailed and reused and you'd know how those visits are all related.
Hope that makes sense.
As far as validations, would Rails 3 improve this type of code?
Something like this perhaps?
class Recommendation
include ActionModel::Validations
attr_accessor :from_email
validates_presense_of :from_email
end
An overview of some Rails 3 things (like the new routing) might be nice. There has been a frenzy of commits recently. Maybe they are gearing up for a RC, one year exactly from the announcement of the merge...
Or you could use:
http://github.com/remvee/active_form
Which is the same thing sitting conveniently in your /lib
plus its properly tested!
thanks for the episode.
Woops... didn't read all the comments. The original author already pointed this out.
So what's the point for this? Simply encapsulating validations in a model? In that case, wouldn't it be easy to just no call the save method and that's it? It's surely less code.
Or you simply use the activerecord-tableless gem, which does the same basically ;)
A very similar but easier DSL is http://github.com/AnthonyCaliendo/acts_without_database
Andrés Mejía: If you had watched the episode, you would have known that that would still require the database table to be present, even if you never call #save.
simon: like Ryan mentioned there are a few gems around but e.g. if you're not using tableless models a lot, the solution presented in the ep. is more simple and a gem is really unnecessary unless you're doing this kind of stuff often.
Hi Ryan...
I always watching your tutorial about RoR. But what I can't find is How to Build Chat Application using RoR (e.g. Juggernaut). Would you please to email me if you've considered to make chat tutorial.
Thanks...
This is cool, but useful only if you need stuff like validation and callbacks. But you can get away without subclassing ActiveRecord::Base as well. Just define your own class or subclass OpenStruct, add validations with http://validatable.rubyforge.org/ and voila! This will work for most of the cases equally well.
If you are using RSpec and generate the model with its generator, you need to delete the empty fixture file, otherwise all tests will end with error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: portable_documents: DELETE FROM "portable_documents" WHERE 1=1
For Rails 3 check out:
http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
Why don't you make a plugin? Maybe acts_as_tabless? :)
Hey Ryan,
Thanks a million for your awesome work. Have been following your RailsCasts for a year now, and you really helped me out of a lot of problems.
Maybe I am overlooking something, but isn't it possible to use self.abstract_class = true in this situation??
Many greetings,
Jakob
Will this work in rails3 also?
New Railscast about Active Model probably helps: http://railscasts.com/episodes/219-active-model