Ruby on Rails desde Cero: ActiveModel

Publicado el 04 octubre 2013 por Codehero @codeheroblog

¿Qué es ActiveModel?

Es una serie de módulos que se pueden utilizar para implementar funcionalidades comunes extraídas de ActiveRecord e implementarlas en modelos comunes sin que tenga interacción directa con la base de datos. Algunos de los módulos que incluye ActiveModel son los siguientes:

  • ActiveModel::AttributeMethods
  • ActiveModel::Callbacks
  • ActiveModel::Conversion
  • ActiveModel::Dirty
  • ActiveModel::Lint
  • ActiveModel::Model
  • ActiveModel::Naming
  • ActiveModel::SecurePassword
  • ActiveModel::Serialization
  • ActiveModel::Serializers
  • ActiveModel::Translation
  • ActiveModel::Validations

La sintaxis para desarrollar una clase con estas características es exactamente igual que una clase normal, solo que a esta se le incluyen los módulos de ActiveModel que vayamos a utilizar. Un ejemplo de esto es el siguiente:

class Message include ActiveModel::Validations attr_accessor :nombre, :email, :contenido validates_presence_of :nombre, :email, :contenido def initialize (nombre, email,contenido) @nombre, @email, @contenido = nombre, email, contenido final final

123456789101112 classMessage  include ActiveModel::Validations   attr_accessor:nombre,:email,:contenido   validates_presence_of:nombre,:email,:contenido   def initialize(nombre,email,contenido)   @nombre,@email,@contenido=nombre,email,contenido  final  final

Como ven en el ejemplo es una clase normal pero en ésta incluimos ActiveModel::Validations para utilizar el módulo de validaciones de ActiveRecord que estudiamos en el capítulo anterior.


Modelo con ActiveModel (Validations)

Para este curso realizaremos un ejemplo sencillo que consiste en un simple formulario en el que agregaremos un asunto, correo y contenido, el cual vamos a validar de igual forma que en el capítulo anterior (Haciendo usos de los módulos de ActiveModel), pero estos datos no serán guardados en base de datos. Probablemente se estén preguntando cual es la utilidad de agregar un formulario sin que los datos se dirijan a un destino, pues entre otras cosas, pudiéramos enviar el mensaje por correo electrónico desde nuestro servidor o incluso enviar los datos por medio de un servicio web (Web Service) a otra aplicación que lo procese.

Empezaremos creando nuestro modelo:

class Message #incluimos los módulos que vamos a utilizar include ActiveModel::Validations #necesario para agregar las condiciones de validacion include ActiveModel::Conversion # contiene entre otras cosas el metodo to_key que usamos en el formulario #declaramos las variables del modelo attr_accessor :name, :email, :content #Agregamos las condicones a vailidar validates_presence_of :name, :email, :content validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i validates_length_of :content, :maximum => 500 # El constructor que recibe un hash con los valores del formulario # y nos crea nuestro objeto mensaje def initialize(attributes = {}) attributes.each do |name, value| send("#{name}=", value) end end # Metodo que debemos agregar a nuestro modelo # ya que no se van a guardar los datos en la base de datos def persisted? false end end

1234567891011121314151617181920212223242526272829 classMessage #incluimos los módulos que vamos a utilizar   include ActiveModel::Validations  #necesario para agregar las condiciones de validacion  include ActiveModel::Conversion# contiene entre otras cosas el metodo to_key que usamos en el formulario #declaramos las variables del modelo    attr_accessor:name,:email,:content  #Agregamos las condicones a vailidar    validates_presence_of:name,:email,:content  validates_format_of:email,:with=>/^[-a-z0-9_+\]+\@([-a-z0-9]+\)+[a-z0-9]{2,4}$/i  validates_length_of:content,:maximum=>500  # El constructor que recibe un hash con los valores del formulario#  y nos crea nuestro objeto mensaje  def initialize(attributes={})  attributeseachdo|name,value|  send("#{name}=",value)  end  end # Metodo que debemos agregar a nuestro modelo# ya que no se van a guardar los datos en la base de datos    def persisted?  false  end  end

Una vez creado nuestro modelo ActiveModel simplemente creamos el controlador y las vistas necesarias. Como ya dijimos en capítulos anteriores podemos crear el controlador de una forma rápida con el terminal y la siguiente línea de comando:

rails g controller mensajes

1 railsgcontroller mensajes

Agregamos en el archivo de rutas la siguiente linea, para que Rails reconozca las rutas para el controlador:

resources :mensajes

1 resources:mensajes

Creamos nuestro controlador:

class MensajesController < ApplicationController def index @mensaje = Mensaje.new end def create @mensaje = Mensaje.new(params[:mensaje]) if @mensaje.valid? # TODO send message here flash[:notice] = "Se envío el mensaje con éxito" redirect_to root_url else render :action => 'index' end end end

123456789101112131415161718 classMensajesController&lt;ApplicationController   def index  @mensaje=Mensajenew  end    def create  @mensaje=Mensajenew(params[:mensaje])  if@mensajevalid?  # TODO send message here  flash[:notice]="Se envío el mensaje con éxito"  redirect_to root_url  else  render:action=>'index'  end  end  end

Vemos algunas diferencias mínimas con respecto a otro modelos que ya hemos creado antes con acceso a base de datos, por ejemplo: cambiamos el método save(@mensaje.save) por el método valid?(@mensaje.valid?) porque obviamente ya no estamos guardando en base de datos, de resto se maneja bastante parecido que con ActiveRecord.

Por último creamos nuestra vista de igual manera que en el capítulo anterior, agregando los bloques que detectan los errores del modelo:

Para finalmente tener un resultado parecido al siguiente, Cabe destacar que el diseño y los mensajes pudieran ser modificados para mejorar la presentación de la pagina.


ActiveModel (Serialization)

Para finalizar con el curso de hoy veremos como funciona el módulo para serializar un objetos con ActiveModel. En Rails es bastante sencillo convertir un objeto a JSON o XML solo necesitamos incluir en nuestra clase el módulo para serializar objetos:

include ActiveModel::Serializers::JSON include ActiveModel::Serializers::Xml

12 include ActiveModel::Serializers::JSON  include ActiveModel::Serializers::Xml

Luego declaramos un método donde creamos un Hash con los atributos del objeto de la siguiente forma (tomando como ejemplo el objeto del ejercicio anterior)

def attributes {'nombre' => nil,"email" =>nil, "contenido"=>nil} end

123 defattributes  {'nombre'=>nil,"email"=>nil,"contenido"=>nil}  end

Listo ahora en el controlador solo decidimos como queremos mostrar el resultado.

#formato XML # render :xml => @mensaje.to_xml #formato JSON render :json => @mensaje.to_json

12345 #formato XML  # render :xml => @mensaje.to_xml #formato JSON    render:json=>@mensajeto_json

y obtendremos algo como esto dependiendo del formato que lo necesitemos (El ejemplo lo muestra en formato JSON):

{ "nombre":"Ricardo Sampayo", "email":"me@RicardoSampayo.com", "contenido":"Mensaje" }

12345 {  "nombre":"Ricardo Sampayo",  "email":"me@RicardoSampayo.com",  "contenido":"Mensaje"}


Conclusión

En esta lección hemos visto un poco de una característica bien importante del framework como lo es ActiveModel, conocimos su sintaxis y una pequeña implementación que espero haya servido para reforzar sus destrezas en Rails y haya aumentado su curiosidad a probarlo.

Una vez más te recomiendo echarle un vistazo a la serie completa de Ruby desde cero, así como a las otras series de CodeHero, agradeciendo de antemano todas sus dudas y comentarios en la sección de comentarios.

¡Hasta el próximo capítulo!