sábado, 13 de mayo de 2006

Clase para parámetros de una aplicación en Rails

Estaba buscando algún plugin para Rails para manejar los parámetros (preferencias, opciones, settings, etc.) de una web que estoy haciendo.

En el wiki de Rails encontré este ConfigurationGenerator que parecía muy atractivo, y que se adaptaba exactamente a lo que yo estaba necesitando, pero no pude encontrar el código de él por ningún lado, ni he obtenido respuesta a un post que coloqué en el foro de Rails sobre este generador.

Luego conseguí este otro Settings plugin, que me pareció fantástico, pero no era exactamente lo que yo quería.

Así que decidí emprender la tarea de hacer mi propio modelo para el manejo de los parámetros de mi aplicación web, tomando como base un poco de esos otros pulgins que ya había visto.

Lo que me interesaba era tener una tabla que siempre tendría un sólo registro, y con una columna para cada opción que hubiese en los parámetros. Eso me permitiría guardar cada opción en el tipo de dato y tamaño de columna adecuado. Además me interesaba poder acceder a cualquier parámetro, desde cualquier lugar de la aplicación, con algo simple como:

Parametros.opción

Los parámetros con que arranqué eran el nombre de la aplicación y un texto del tipo "about us", o "quienes somos", para la página principal de la web. La migración quedó asi:

class AgregarParametros < ActiveRecord::Migration

  def self.up

    # Archivo de parámetros de la aplicación
    create_table :parametros do |table|
      table.column :aplicacion, :string, :limit => 100
      table.column :quienes_somos, :text
      table.column :updated_at, :datetime
    end
    
    execute "Insert into parametros (aplicacion, quienes_somos) Values ('App. web', 'Somos...')"
    
  end

  def self.down
    drop_table :parametros
  end

end

Este archivo contendrá siempre un registro único, ni más, ni menos, así que se incluye automáticamente durante la migración misma, con valores iniciales cualesquiera. Los valores reales se asignaran en la aplicación web.

Y el modelo de Rails quedó de esta manera:

class Parametros < ActiveRecord::Base
  
  set_table_name "parametros"
  validates_presence_of :aplicacion, :quienes_somos
  private_class_method :new, :create, :destroy, :destroy_all, :delete, :delete_all
  
  @@p = find(:first)

  def self.method_missing(method, *args)
    opcion = method.to_s
    if opcion.include? '='
        # Asignar un valor a la opción
        nombre_var = opcion.gsub('=', '')
        valor = args.first
        @@p[nombre_var] = valor
      else
        # Retornar el valor de la opción
        @@p[opcion]
    end
  end
  
  def self.save
    @@p.save
  end

  def self.update_attributes(atributos)
    @@p.update_attributes(atributos)
  end

  def self.errors
    @@p.errors
  end

end

Me interesaba accesar los parámetros con la forma en plural Parametros (en contra de las convenciones de Rails), y la tabla que uso tiene el mismo nombre en plural (esta vez si como lo indican las convenciones de Rails), así que debí incluir set_table_name "parametros" para saltarme la convención del nombre del modelo.

Haría uso de la clase directamente, sin instanciarla, así que debía prevenir que se crearan objetos de la clase con la línea private_class_method :new, :create. A esa lista se agregan :destroy, :destroy_all, :delete, :delete_all porque ciertamente no me interesa que se borre ese registro único de la tabla de parámetros. La lista de métodos se puede alargar a cualquier otro del que se quiera bloquear el acceso.

No quería ir a la base de datos cada vez que necesitara un parámetro, así que usé una variable de clase para hacer un cache de los valores, que sería inicializada la primera vez que se llame a los parámetros, con el contenido de ese registro único de la tabla: @@p = find(:first)

Los métodos save, update_attributes y errors se definen como métodos de clase, con self, para poder llamarlos sin tener necesidad de instanciar la clase.

Se pueden asignar todos los valores a los parámetros, uno por uno, y al final llamar a save para grabarlos en una sola operación en la base de datos. O se puede llamar a update_attributes con un "hash" como parámetro, con todos los valores de los parámetros a grabar (al grabar desde una forma, en una página de parámetros, por ejemplo). El método errors se define para poder utilizar el "helper" error_messages_for 'parametros' en una forma.

Para actualizar los parámetros se puede hacer algo como lo que sigue. En el controlador adecuado:

def parametros
  @parametros = Parametros
end

def grabar_param
  @parametros = Parametros
  if @parametros.update_attributes(params[:parametros])
    flash[:notice] = 'Parámetros grabados'
    redirect_to :action => "index"
  else
    render :action => "parametros"
  end
end

Y en la vista hacer:

<h1>Parámetros de la web</h1>
<br>
<%= start_form_tag :action => 'grabar_param' %>
  <%= error_messages_for 'parametros' %>
 <p><label for="parametros_aplicacion">Nombre de la web:</label><br/>
 <%= text_field_tag 'parametros[aplicacion]', @parametros.aplicacion %></p>
  <p><label for="parametros_quienes_somos">Quienes somos:</label><br/>
  <%= text_area_tag "parametros[quienes_somos]", @parametros.quienes_somos %></p>
  <br>
  <%= submit_tag 'Aceptar' %>
<%= end_form_tag %>

Esta es la mejor manera que se me ha ocurrido para manejar los parámetros de la manera que yo quería. Si conocen de una manera mejor, estaré gustoso de escucharla.

¿Te gustó este artículo? Digg it!

No hay comentarios.: