Un buen concepto de diseño o buena práctica en rails (y en cualquier aplicación que siga el patrón Modelo Vista Controlador) es el de Fat Model, Skinny Controller. Consiste en mover tanta lógica de negocio como sea posible al modelo y de dejar al controlador como un simple agente que se encargue de interactuar con modelo y enviar los resultados a la vista.

Con esta práctica se limpia el controlador de responsabilidades que no son suyas y de código que seguramente estará repetido en otros controladores, permitiendo mejor reusabilidad, mantenimiento y testeabilidad de código.

Por tanto nuestros modelos tienden a engordar, englobando todas las operaciones pertenecientes a ellos mismos, con validaciones, callbacks, etc..

Las validaciones permiten asegurarnos que nuestra base de datos solamente se llenara con datos validos. Los callbacks y los observers nos ofrecen la posibilidad de realizar ciertas acciones antes o después de alterar el estado de los objetos.

No hay duda de que las validaciones han de ir en los modelos. Crearlas en los controladores nos implicaría repetirlas en cada controlador que interactuara con ellos.
El problema es cuando implementar callbacks y cuando observers, ya que ambos son similares.

Los callbacks son métodos que son llamados en ciertos momentos durante el ciclo de vida de un objeto para realizar acciones relacionadas con la naturaleza del modelo que los modela.
Por ejemplo, en el siguiente código:


class Usuario < ActiveRecord::Base
  validates_pressence_of :name, :email
  has_one :preferencia
end

class Preferencia < ActiveRecord::Base
  belongs_to :usuario
end

El modelo Usuario que define la lógica de los usuarios en una aplicación.
Los usuarios tienen preferencias de usuario.

¿Donde y cuando creamos y asignamos estas preferencias?
 - Podríamos hacerlo en el controlador:

class AltasController < ActionController::Base
  ...
  def create
    @usuario = Usuario.create(params[:usuario])
    @usuario.preferencia.create
  end
  ...
end

Esto se salta lo comentado anteriormente, porque si ahora queremos crear un usuario desde otro controlador deberemos recordar y repetir la misma acción:

class AdminsController < ActionController::Base
  ...
  def create
    @usuario = Usuario.new(params[:usuario])
    @usuario.admin = true
    @usuario.save
    @usuario.preferencia.create
  end
  ...
end

Cuando se crea un usuario, sea donde sea queremos queremos asociarle un nuevo objeto con sus preferencias, ya que todo usuario debe tener sus preferencias. Esto forma parte de la lógica de negocio del modelo, así que mediante un simple callback podemos tener este comportamiento:

class Usuario < ActiveRecord::Base
  validates_pressence_of :name, :email
  has_one :preferencia, :dependent => :destroy
  after_create :crea_preferencias
 
  private
  def crea_preferencias
    self.preferencia.create
  end
end

Ahora ya no necesitamos crear las preferencias cuando creemos el usuario. Esto se realizará automáticamente:

class AltasController < ActionController::Base
  ...
  def create
    @usuario = Usuario.create(params[:usuario])
  end
  ...
end
class AdminsController < ActionController::Base
  ...
  def create
    @usuario = Usuario.new(params[:usuario])
    @usuario.admin = true
    @usuario.save
  end
  ...
end

Ya no repetimos código. Los controladores sólo hacen lo que tienen que hacer. Somos más DRY.

Los observers son similares a los callbacks, pero permiten definir y/o realizar acciones que no están relacionadas directamente con la naturaleza del modelo. Lo bueno de los observers es que permiten definir este comportamiento fuera del modelo en si.

Siguiendo con nuestro ejemplo, queremos que cuando se cree un usuario nuevo reciba un correo de confirmación de registro.

¿Donde ponemos esta funcionalidad?

 - ¿En el controlador?
   Nos pasaría como en el caso anterior. Los controladores harían más de lo que debieran, más código repetido, etc..
  
 - ¿En el modelo con callbacks?
   Podríamos, pero el modelo usuario no tiene porque ocuparse del envío de emails de confirmación. No es su responsabilidad.
  
Así que esto tiene pinta de ir en un Observer:

class UsuarioObserver < ActiveRecord::Observer
  def after_create(usuario)
    UsuarioMailer.deliver_new_user(usuario)
  end
end

Al registrarlo en config/environment.rb, cada vez que creemos un usuario, se crearán sus preferencias y recibirá un email de confirmación de registro.

Entonces aquí viene lo interesante. Si en algún momento queremos simplemente el usuario, ya sea para hacer una prueba, o por cualquier otro motivo en el que no deseemos que se envíe ningún correo, podemos desactivar los observers en tiempo de ejecución y crear el usuario.

Usuario.delete_observers
Usuario.create(:name => "Superadmin", :email => "superadmin@application.com")

De esta forma el usuario no recibirá un correo, porque en este caso no nos interesa, pero si que recibirá unas preferencias.

En caso de confusión, suelen haber dos reglas básicas para usar callbacks:
 - Si la acción modifica el estado del objeto
 - Si un objeto puede ser invalido en caso de que no se ejecute la acción

Para todo lo demás, observers.