bebanjo / persistize

Easy denormalization for your ActiveRecord models

This URL has Read+Write access

name age message
file .gitignore Sat Feb 28 17:11:56 -0800 2009 Changes for gem building on github [cavalle]
file MIT-LICENSE Sat Feb 28 12:33:19 -0800 2009 Improvements on license and readme [cavalle]
file README.rdoc Sun Mar 01 06:04:45 -0800 2009 Add support for belongs_to dependencies [cavalle]
file Rakefile Fri May 22 09:32:42 -0700 2009 Jewelling the gem [cavalle]
file VERSION Loading commit data...
file init.rb Fri Oct 03 07:45:23 -0700 2008 First implementation [porras]
directory lib/
file persistize.gemspec
directory test/
README.rdoc

Persistize

Persistize is a Rails plugin for easy denormalization. It works just like memoize but it stores the value as an attribute in the database. You only need to write a method with the denormalization logic and a field in the database with the same name of the method. The field will get updated each time the record is saved:

  class Person < ActiveRecord::Base
    def full_name
      "#{first_name} #{last_name}"
    end

    persistize :full_name
  end

  ...

  Person.create(:first_name => 'Jimi', :last_name => 'Hendrix')
  Person.find_by_full_name('Jimi Hendrix') # #<Person id:1, first_name:"Jimi", last_name:"Hendrix", full_name:"Jimi Hendrix" ...>

Dependency

Sometimes you want to update the field not when the record is changed, but when some other associated records are. For example:

  class Project < ActiveRecord::Base
    has_many :tasks

    def completed?
      tasks.any? && tasks.all?(&:completed?)
    end

    persistize :completed?, :depending_on => :tasks

    named_scope :completed, :conditions => { :completed => true }
  end

  class Task < ActiveRecord::Base
    belongs_to :project
  end

  ...

  project = Project.create(:name => 'Rails')
  task = project.tasks.create(:name => 'Make it scale', :completed => false)
  Project.completed  # []

  task.update_attributes(:completed => true)
  Project.completed  # [#<Project id:1, name:"Rails", completed:true ...>]

You can add more than one dependency using an array:

  persistize :summary, :depending_on => [:projects, :people, :tasks]

These examples are just some of the possible applications of this pattern, your imagination is the limit =;-) If you can find better examples, please send them to us.

Install

As a plugin (Rails >= 2.1.0)

  $ script/plugin install git://github.com/porras/persistize.git

As a gem (Rails >= 2.1.0)

  # in config/environment.rb
  config.gem "porras-persistize", :lib => "persistize", :source => "http://gems.github.com"

And then:

  $ [sudo] rake gems:install

To-do

  • More kinds of dependencies (has_one, has_many :through)
  • Make cache optional (cache can cause records to be inconsistent if changed and not saved so it would be nice to be able to deactivate it)

Copyright © 2008 Luismi CavallĂ© & Sergio Gil, released under the MIT license