STATUS: No longer maintained / bad idea
Easily cache an attribute of an associated model.
Imagine you have a Post model that belongs_to a User model. Assume the User name changes almost never. If you want to display a lot of posts along with their user’s names and you do not always want to :include the User model, then this plugin gives you an alternative.
This plugin keeps a copy of the User.name in a column user_name on the posts table. When the user_id changes user_name is updated. In the rare case where the user.name changes all posts are updated automatically. All of this happens with half a line of extra code.
class Post < ActiveRecord::Base belongs_to :user, :cached_attributes => [:name, :email] end class User < ActiveRecord::Base has_many :users end
This automatically adds the needed before_save and after_save callbacks to the Post and User model resp to sync the user_name and user_email attributes in Post:
user = User.create(:name => 'Bob', :email => 'bob@example.com') post = user.posts.create post.user_name # => 'Bob' post.user_email # => 'bob@example.com' user.update_attribute(:name, 'Joe') post.user_name # => 'Joe'
In the above situation you probably could just use :joins. But calculated attributes are where the plugin comes in really handy:
class Post < ActiveRecord::Base belongs_to :user, :cached_attributes => :full_name end class User < ActiveRecord::Base has_many :users def full_name if first_name.blank? "#{title} #{name}" else "#{first_name} #{last_name}" end end end user = User.create(:title => 'Mr', :name => 'Doe', :first_name => 'John) post = user.posts.create post.user_full_name # => 'John Doe' user.update_attribute(:first_name, '') post.user_full_name # => 'Mr Doe'
Now you can show the user_full_name along with your posts without having to include the user association. If you add a *_changed? method Post.update_all will only be triggered if really needed:
class User < ActiveRecord::Base has_many :users def full_name if first_name.blank? "#{title} #{name}" else "#{first_name} #{last_name}" end end def full_name_changed? name_changed? || first_name_changed? || title_changed? end end # Post.update_all *will not* be called: user.update_attribute(:role, 'admin') # Post.update_all *will* be called: user.update_attribute(:name, 'Jim')
You might not want to overuse this feature. Keep in mind that it introduces a lot of duplication in your database. This plugin is quite new. Familiarize yourself with its internals if you want to use it (though you should probably do that with any plugin you use anyway).
Copyright © 2008 Tim Fischbach, released under the MIT license