Mittwoch, 12. Dezember 2012

Soft delete for ActiveRecord

Master data often require to be kept even if they are deleted by the user. One reason could be the requirement to be able to reactivate the record (RoR's ActiveRecord::Base). Another one could be to keep the references. No matter what the demand is. It's simple to solve.
I coded a module to reuse the logic and named it RecordActivation:
module RecordActivation
  extend ActiveSupport::Concern
  self.included do
    scope :active, where(:active => true)
    validates_presence_of :active
    before_validation :activate, 
      :on => :create, 
      :if => Proc.new { |r| r.active.nil? }
  end

  def activate
    self.active = true
  end
 
  def activate!
    activate
    save!
  end
  
  def deactivate
    self.active = false
  end
 
  def deactivate!
    deactivate
    save!
  end
end
As an example I created a Task migration:
class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :name
      t.boolean :active
      t.timestamps
    end
  end
end
... and included the module into the model:
class Task < ActiveRecord::Base
  include RecordActivation
end
Let's go into detail in terms of the module.
Please notice that I extended my module with ActiveSupport::Concern. It resolves module dependencies and should be preferred when it comes to module handling. The second I want to point to, is the snippet which is run, when the module is included:
    scope :active, where(:active => true)
    validates_presence_of :active
    before_validation :activate, 
      :on => :create, 
      :if => Proc.new { |r| r.active.nil? }
It spends a scope to the Task model. So finding all active tasks means:
Task.active.all
If you want to ensure, that the activation flag is qualified, add the validation by validates_presence_of. Also make sure that the flag is set initially before creation by calling the method "activate" (but only if the value is not set already/ still NULL). By default all new created records are active.
Task.new.save!
... will create a new active task.
Four instance methods allow to set or reset the boolean flag. Those with an exclamation mark at the end of their name force the saving immediately (following the convention). For example:
Task.active.order("created_at").first.deactivate!
will deactivate the oldest task at the database.
That's all.
Supported by Ruby on Rails 3.2.8

Keine Kommentare:

Kommentar veröffentlichen