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 Tue Dec 29 12:00:43 -0800 2009 Update README [cavalle]
file Rakefile Fri May 22 09:32:42 -0700 2009 Jewelling the gem [cavalle]
file VERSION Tue Dec 29 05:53:06 -0800 2009 Version bump to 0.0.4 [porras]
file init.rb Fri Oct 03 07:45:23 -0700 2008 First implementation [porras]
directory lib/ Tue Dec 29 05:51:32 -0800 2009 Namespaced models support [porras]
file persistize.gemspec Fri May 22 09:49:29 -0700 2009 Gemspec version 0.0.2 [cavalle]
directory test/ Tue Dec 29 05:51:32 -0800 2009 Namespaced models support [porras]
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 gem

  # in config/environment.rb
  config.gem "persistize"

And then:

  $ [sudo] rake gems:install

As a plugin

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

To-do

  • More kinds of dependencies (has_one, <del>has_many :through</del>)
  • 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