module RequiresApproval::ClassMethods

Public Instance Methods

prepare_tables_for_requires_approval() click to toggle source

adds the correct tables and columns for requires_approval

# File lib/requires_approval.rb, line 215
def prepare_tables_for_requires_approval
  self.reset_column_information

  # adds is_active to the parent table
  self.add_requires_approval_fields
  self.reset_column_information

  # adds our versions table
  self.drop_versions_table

  self.create_versions_table

end
requires_approval_for(*attrs) click to toggle source
# File lib/requires_approval.rb, line 229
def requires_approval_for(*attrs)
  self.set_options(attrs.extract_options!)

  # set up our attributes that require approval
  self.class_attribute :fields_requiring_approval
  self.fields_requiring_approval = attrs.collect(&:to_s)

  # set up delegates
  self.set_up_version_delegates

  # create a blank version before create to handle if no
  # attributes were ever set
  self.before_validation(
    :latest_unapproved_version_with_nil_check,
    :on => :create
  )

  # create the versions class
  self.create_versions_class
  self.has_many :versions,
    :class_name => self.versions_class.name,
    :foreign_key => self.versions_foreign_key

  self.has_one :latest_unapproved_version,
    :autosave => true,
    :class_name => self.versions_class.name,
    :foreign_key => self.versions_foreign_key,
    :conditions => [
      "#{self.versions_table_name}.is_approved = ?", false
    ]
end
unapproved() click to toggle source
# File lib/requires_approval.rb, line 261
def unapproved
  includes(:latest_unapproved_version)
    .where("#{self.versions_table_name}.id IS NOT NULL")
end
versions_class() click to toggle source

the class which our versions are

# File lib/requires_approval.rb, line 267
def versions_class
  "#{self.name}::#{self.versions_class_name}".constantize
end

Protected Instance Methods

add_requires_approval_fields() click to toggle source
# File lib/requires_approval.rb, line 273
def add_requires_approval_fields
  # add is_frozen
  unless self.column_names.include?("is_frozen")
    self.connection.add_column(
      self.table_name, :is_frozen, :boolean, :default => true
    )

    self.attr_accessible(:is_frozen)
  end
  # add is_deleted
  unless self.column_names.include?("is_deleted")
    self.connection.add_column(
      self.table_name, :is_deleted, :boolean, :default => false
    )

    self.attr_accessible(:is_deleted)
  end
  true
end
create_versions_class() click to toggle source

create a class

# File lib/requires_approval.rb, line 294
def create_versions_class
  versions_table_name = self.versions_table_name

  self.const_set self.versions_class_name, Class.new(ActiveRecord::Base)

  self.versions_class.class_eval do
    self.table_name = versions_table_name

    # Whitelist public attributes
    # Everything since this class is for internal use only
    public_attributes = self.column_names.reject{|attr| self.protected_attributes.deny?(attr)}
    self.attr_accessible(*public_attributes)
  end
end
create_versions_table() click to toggle source
# File lib/requires_approval.rb, line 309
def create_versions_table
  self.connection.create_table(self.versions_table_name) do |t|
    self.columns.each do |column|
      t.send(column.type, column.name, {
        :default => column.default,
        :limit => column.limit,
        :null => column.null,
        :precision => column.precision,
        :scale => column.scale
      })
    end
    t.integer self.versions_foreign_key
    t.boolean :is_approved, :default => false
  end
  self.connection.add_index(
    self.versions_table_name,
    [self.versions_foreign_key, :is_approved]
  )
end
drop_versions_table() click to toggle source

drop the versions table if it exists

# File lib/requires_approval.rb, line 330
def drop_versions_table
  if self.connection.tables.include?(self.versions_table_name)
    self.connection.drop_table(self.versions_table_name)
  end
end
set_options(opts = {}) click to toggle source
# File lib/requires_approval.rb, line 336
def set_options(opts = {})
  @versions_class_name = opts.delete(:versions_class_name)
  @version_foreign_key = opts.delete(:versions_foreign_key)
  @versions_table_name = opts.delete(:versions_table_name)
end
set_up_version_delegates() click to toggle source
# File lib/requires_approval.rb, line 342
def set_up_version_delegates
  self.fields_requiring_approval.each do |f|
    define_method("#{f}=") do |val|
      # type cast our val so "0" changes to 'false'
      type_casted_val = self.column_for_attribute(f).type_cast(val)

      # if we have a latest_unapproved version already, let it handle
      # updates - if not, only create one if the type casted value is
      # not the same as what is in the parent value
      if self.latest_unapproved_version.present? ||
        type_casted_val != self.send(f)

        self.send("#{f}_will_change!")
        self.latest_unapproved_version_with_nil_check.send("#{f}=", val)
      end
    end
  end
end
validates_approved_field(*args) click to toggle source
# File lib/requires_approval.rb, line 361
def validates_approved_field(*args)
  self.versions_class.class_eval do
    validates(*args)
  end
end
versions_class_name() click to toggle source

class name for our versions

# File lib/requires_approval.rb, line 368
def versions_class_name
  @versions_class_name ||= "Version"
end
versions_foreign_key() click to toggle source

foreign key for our class on the version table

# File lib/requires_approval.rb, line 373
def versions_foreign_key
  @version_foreign_key ||= "#{self.base_class.name.demodulize.underscore}_id"
end
versions_table_name() click to toggle source

table name for our versions

# File lib/requires_approval.rb, line 378
def versions_table_name
  @versions_table_name ||= "#{self.base_class.name.demodulize.underscore}_versions"
end