L-exp Mobile

Active Record tips and tricks

Just a small collection of tips/tricks which I use a lot ( or try to ), that others might find helpful.

concerned_with

In most of the Rails applications that I work with, the primary model ( User model for example ) ends up being at least 1000 lines long. Thanks to Rick’s quick/awesome solution, we can easily split a model into different “concerns”.

RAILS_ROOT/config/initializers/concerns.rb
1 2 3 4 5 6 7 class << ActiveRecord::Base def concerned_with(*concerns) concerns.each do |concern| require_dependency "#{name.underscore}/#{concern}" end end end

Using concerned_with, lets split the User model into 2 different concerns and 3 different files :

app/models/user.rb – Main model app/models/user/validations.rb – User validations concern app/models/user/authentication.rb – User authentication concern RAILS_ROOT/app/models/user.rb
1 2 3 class User < ActiveRecord::Base concerned_with :validations, :authentication end
RAILS_ROOT/app/models/user/validations.rb
1 2 3 class User validates_presence_of :name end
RAILS_ROOT/app/models/user/authentication.rb
1 2 3 4 5 class User def self.authenticate(name, password) find_by_name_and_password(name, password) end end

Pay close attention to the directory structure and how concerns just open the existing class definition, make sure you don’t re-inherit the class from AR::Base inside concerns

log_to

I’ve always used log_to for monitoring query output if irb ( script/console ). But with the recent connection pool changes, it stopped working. So here’s a new version :

1 2 3 4 def log_to(stream=$stdout) ActiveRecord::Base.logger = Logger.new(stream) ActiveRecord::Base.connection_pool.clear_reloadable_connections! end
So.Many.Joins

As you might already know, you could use association names while constructing a join query with ActiveRecord::Base.find. For example :

1 2 3 class User < ActiveRecord::Base has_many :items end

Now, if you want to find all the users who have a black item, you could query like :

User.all :joins => :items, :conditions => { :"items.color" => 'black' }

Now the black magic part. Not many people know that you can supply the same join key more than once too. So :

User.all :joins => [:items, :items]

will produce a query like :

SELECT `users`.* FROM `users` INNER JOIN `items` ON items.user_id = users.id INNER JOIN `items` items_users ON items_users.user_id = users.id

This is very useful when you need to make complex sql queries. For example, if you want find all the users who have at least one “black” AND at least one “red” item :

User.all :joins => [:items, :items], :conditions => {:"items.color" => "red", :"items_users.color" => 'black'}

Of course, you’d want to be a little careful with joining too many tables if your tables are very large or if/when performance becomes a problem, etc. YMMV.

Force save

If you want to save an object even if the validations fail ( like, if your boss forces you to ) :

object.save(false)
Find By Bang!

This is new in edge. You can now use dynamic finders with a bang(!). If there is no result found, RecordNotFound exception will be raised :

User.find_by_name!('lifo')


Options:   Save This | Share
Viewed 0 times
Published 3 months ago
By pratik
From Resource has_many :bugs, :through => :rails - sleepless in london.. in lists:
Best Ruby on Rails Blogs

Menu

by Genís