Skip to content

Instantly share code, notes, and snippets.

@joelvh
Last active December 14, 2015 12:39
Show Gist options
  • Save joelvh/5088192 to your computer and use it in GitHub Desktop.
Save joelvh/5088192 to your computer and use it in GitHub Desktop.
Generating methods that update an instance or multiple database records the same way
class Membership
###### SCOPES ######
scope :active, where(:is_active => true)
scope :not_active, where{is_active != true}
scope :removed, where(:is_active => false, :unsubscribed_at => nil)
scope :unsubscribed, where{(is_active == false) & (unsubscribed_at != nil)}
scope :admin, active.where(:is_admin => true)
####################
STATE_UPDATES = {
:activate => { :attributes => ->{{:is_active => true}}, :if => ->{{:is_active => false}} },
:remove => { :attributes => ->{{:is_active => false}}, :if => ->{{:is_active => true}} },
:restore => { :attributes => ->{{:is_active => true}}, :if => ->{{:is_active => false, :unsubscribed_at => nil}} },
:unsubscribe => { :attributes => ->{{:is_active => false, :unsubscribed_at => Time.now}}, :if => ->{{:is_active => true}} }
}
STATE_UPDATES.each do |name, config|
# create method that changes state
define_method name do
# if the instance matches the attribute values, it can be updated with the new values
result = config[:if].call.map{|k,v| send(k) == v}.all?
# update the instance with the new values if the old values were correct
self.attributes = config[:attributes].call, {:without_protection => true} if result
# indicate if a change was possible
result
end
# create method that auto-saves
define_method :"#{name}!" do
send(name)
save!
end
# create method that mass updates db with state change
define_singleton_method :"#{name}!" do
scoped.where(config[:if].call).update_all(config[:attributes].call)
end
end
##### OLD WAY THAT IS REPLACED BY GENERATED METHODS ABOVE #####
def activate
if !active?
self.is_active = true
true
else
false
end
end
def activate!
activate
save!
end
# update for a collection
def self.activate!
scoped.not_active.update_all(:is_active => true) > 0
end
def active?
is_active == true
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment