ActiveWeekly #3

Cet article a été précédemment publié a cette adresse http://dev.af83.io/2011/11/11/activeweekly-3.html.

Troisième et dernière semaine d’ActiveDaily, une astuce quotidienne sur ActiveSupport et ActiveModel.

Vous pouvez suivre l’ActiveDaily sur github ou bien lire ces billets de blog hebdomadaire.

Cette semaine on se concentre sur ActiveModel, alors on installe un nouveau joyau:

gem install activemodel

Et puis on essaie de l’inclure.

require 'active_model' # Un underscore mais pas de /all

ActiveModel est la base d’ActiveRecord mais aussi de mongoid, tire, datamapper, redis_orm, …

ActiveModel::Callbacks

Si les callbacks d’ActiveSupport sont un peu rude, ceux d’ActiveModel sont plus sympa.

require 'active_model'

class Bim
  extend ActiveModel::Callbacks
  # On déclare les callbacks disponibles
  define_model_callbacks :kick

  # L'implémentation
  def kick
    run_callbacks :kick do
      puts 'BIMMMMMMMMM!'
    end
  end
end

class Norris < Bim
  # on rajoute les callbacks
  before_kick :before_kick
  after_kick :after_kick
  # on peut aussi utiliser around_kick :ma_methode

  def before_kick
    puts 'Be careful'
  end

  def after_kick
    puts 'KO'
  end
end

chuck = Norris.new
chuck.kick # Your are KO baby

Alors n’hésitez pas a rajouter des callbacks dans vos classes.

http://rubydoc.info/gems/activemodel/3.1.1/ActiveModel/Callbacks

ActiveModel::Observer

Les observers permettent de réagir à des actions d’une autre classe. Cela permet de découpler facilement deux composants. Dans la class Observé, il faut simplement appelé notify_observers.

require 'active_model'

class Norris
  include ActiveModel::Observing

  def kick
    notify_observers(:before_kick)
    puts 'BIMMMMMMMMM!'
    notify_observers(:after_kick)
  end
end

class NorrisObserver < ActiveModel::Observer
  def before_kick(norris)
     puts "start the video recording"
  end

  def after_kick(norris)
    puts "switch off the video recording"
  end
end

Norris.observers = NorrisObserver
Norris.instantiate_observers
chuck = Norris.new
chuck.kick

On arrive rapidement a avoir un comportement similaire. Seule petite déconvenue, je pensais que ActiveModel::Observing se branchait sur les callbacks.

http://rubydoc.info/gems/activemodel/3.1.1/ActiveModel/Observer http://rubydoc.info/gems/activemodel/3.1.1/ActiveModel/Observing/ClassMethods

ActiveModel::MassAssignmentSecurity

MassAssignmentSecurity permet de protéger l’écriture de certains attributs en fonction du rôle. MassAssignmentSecurity fournit deux facons de se protéger. Avec attr_accessible en mode whitelist ou avec attr_protected en mode blacklist.

require 'active_model'

class Norris
  include ActiveModel::MassAssignmentSecurity

  attr_accessible :name
  attr_accessible :name, :guns, :as => :chuck_norris

  def update(params, role=:default)
    sanitize_for_mass_assignment(params, role)
  end
end

chuck = Norris.new
p chuck.update({name: 'chuck', guns: 2}) # {name: 'chuck'}
p chuck.update({name: 'chuck', guns: 2}, :chuck_norris) # {name: 'chuck', guns: 2}

http://rubydoc.info/gems/activemodel/3.1.1/ActiveModel/MassAssignmentSecurity/Cla

ActiveModel::Dirty

Dirty vous aide a tracer les changements dans un objet.

require 'active_model'

class Norris
  include ActiveModel::Dirty # Chuck Norris cannot be dirty, should throw an exception

  define_attribute_methods [:first_name]
  attr_reader :first_name

  def first_name=(val)
    first_name_will_change! unless val == @first_name
    @first_name = val
  end
end

chuck = Norris.new
chuck.first_name = 'plop'
chuck.changes
chuck.changed_attributes

Vous avez ainsi accès à quelques méthodes:

chuck.changed? # true
chuck.first_name_changed? # true
chuck.first_name_was # nil

http://rubydoc.info/gems/activemodel/3.1.1/ActiveModel/Dirty

C’est le dernier ActiveDaily. Je préfère m’arrêter sur un numéro 13.

Vous avez raté:

  • des choses dans ActiveModel::AttributeMethods utilisé entre autre par ActiveModel::Dirty
  • ActiveSupport::Concern qui facilite l’écriture de mixins.
  • ActiveSupport::Inflector qui permet de transformer des mots du singulier au pluriel et d’autres truc aussi
  • Hash#except, l’inverse de Hash#slice
  • ActiveSupport::Notifications avec lequel je n’ai pas encore joué

Have a comment? Contact me by email.