requires_approval

Installation

To install, just add requires_approval to your Gemfile

# Gemfile
gem "requires_approval"

Activation

To activate, use the requires_approval_for method in your class definition

# app/models/user.rb
# 
# - first_name :string
# - last_name :string
# - birthday :date
# - created_at :datetime
# - updated_at :datetime

class User < ActiveRecord::Base
  requires_approval_for(:first_name, :last_name)
end

And create a migration that adds the necessary table and fields for your requires_approval model

# db/migrate/TIMESTAMP_add_user_versions.rb
def self.up
  User.prepare_tables_for_requires_approval
end

This does the equivalent of the the following

# Generated migration
def self.up
  create_table(:user_versions, :force => true) do |t|
    t.string(:first_name)
    t.string(:last_name)
    t.integer(:user_id)
    t.boolean(:is_approved)
    t.timestamps
  end
  add_index(:user_versions, [:user_id, :is_approved])

  # starts all new records out as frozen so they don't show up
  add_column(:users, :is_frozen, :boolean, :default => true)

end

Usage

The first_name and last_name methods are now delegated to the user’s latest_unapproved_version

u = User.new
u.first_name = "Dan"
u.first_name => nil
u.latest_unapproved_version.first_name => "Dan"
u.pending_changes => {
  "first_name" => {
    "was" => nil,
    "became" => "Dan"
  }
}
u.save

u.approve_attributes(:first_name)

u.first_name => "Dan"

# it created one version and approved it
u.versions.count => 1

# so it won't show up as an unapproved version
u.latest_unapproved_version => nil
u.pending_changes => {}

Denying attributes

You can also deny changes. If you do so, they just disappear from the latest_unapproved_version

u = User.create(:first_name => "X", :last_name => "Y")
u.approve_all_attributes

u.update_attribute(:first_name => "Dan")
u.pending_changes => {
  "first_name" => {
    "was" => "X",
    "became" => "Dan"
  }
}

u.deny_attributes(:first_name)
# no more changes
u.pending_changes => {}

FYI, this doesn’t actually remove the latest_unapproved_version, it just sets its values to be the same as the values in the parent record.

Contributing to requires_approval

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet.

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it.

  • Fork the project.

  • Start a feature/bugfix branch.

  • Commit and push until you are happy with your contribution.

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2012 Dan Langevin. See LICENSE.txt for further details.