Sakshi Jain
Sakshi Jain

Reputation: 420

Add scope in concerns for various models

In apps/models/concerns/deactivable.rb

module Deactivatable
  extend ActiveSupport::Concern

  included do
    scope :alive, -> { where(:deactivated_at => nil) }
  end

  def deactivate(t = Time.current)
    update_attribute(:deactivated_at,t)
  end

  def activate
    update_attribute(:deactivated_at,nil)
  end

  def deactivated?
    deactivated_at.present?
  end

end

This is being included in 2 models, app/models/activity_rules/activity_detection_rule.rb and app/models/concerns/generic_campaign.rb.

There are 2 more models which contain the same methods with different attribute name.

In redeemable.rb,

class Redeemable < ActiveRecord::Base
  scope :alive, -> { where("(deactivation_date is null) and (expiry_date is null or expiry_date >= ?)",Date.today) }

  def deactivate(t = Time.current)
    update_attribute(:deactivation_date,t)
  end

  def reactivate
    update_attribute(:deactivation_date,nil)
  end

  def deactivated?
    deactivation_date.present?
  end
end

and in surprise_set.rb

scope :alive, -> { where("deactivation_date is null") }

with the same 3 methods as redeemable.rb.

How to use Deactivable concern to DRY up the other two models?

Upvotes: 4

Views: 3803

Answers (1)

Shadwell
Shadwell

Reputation: 34784

You could return the attribute that indicates the time of deactivation from a class method. You can provide a default implementation in your concern and override in the class that includes the concern if you need to:

module Deactivatable
  extend ActiveSupport::Concern

  included do
    scope :alive, -> { where(deactive_attr => nil) }

    def self.deactive_attr
      :deactivated_at
    end
  end

  def deactivate(t = Time.current)
    update_attribute(self.class.deactive_attr, t)
  end

  def activate
    update_attribute(self.class.deactive_attr, nil)
  end

  def deactivated?
    self.send(self.class.deactive_attr).present?
  end

end

Then, in classes where you want to provide a different attribute you can add a class method:

include Deactivatable

def self.deactive_attr
  :deactivation_date
end

You could also DRY up your alive scope a bit by allowing the class that includes the concern to define the conditions for 'aliveness'. In the concern you can define the default

scope :alive, -> { where(self.active_conditions) }

def self.active_conditions
  { self.deactive_attr => nil }
end

You can then provide a different implementation of active_conditions in the class itself:

self self.active_conditions
  ["(deactivation_date is null) and 
   (expiry_date is null or expiry_date >= ?)", Date.today]
end

Upvotes: 7

Related Questions