Reputation: 420
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
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