martes, 26 de enero de 2010

Configuracion de las aplicaciones

Para definir los parámetros configurables de la aplicación, utilizo lo siguiente: un fichero config/config.yml y un initializer config/initializers/local_config.rb:

En el config.yml, mantengo en formato yaml los valores de los parámetros:

development:
  authentication: "restful" 
  manager:
    activities:
      activate: "Activate"
      create: "Create"

En local_config.rb:

APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]


Así, desde cualquier punto de la aplicación puedo hacer:

if APP_CONFIG['authentication'] == 'restful'
...
end

o

lst = APP_CONFIG['manager']['activities']

que devolveria una hash con:

{"create"=>"Create", "activate"=>"Activate"}

lunes, 25 de enero de 2010

Formularios personalizados

Tienes que pintar siempre el mismo tipo de formulario en la aplicacion? Por ejemplo, tienes que pintar siempre una etiqueta al lado del input?

Tienes un formulario del siguiente estilo:

<% form_for :user do |f| %>
<fieldset>
    <p>
      <label>Login</label><br/>
      <%= f.text_field :login %>
   </p>
    <p>
      <label>Password</label><br/>
      <%= f.password_field :password %>
   </p>
</fieldset>
<% end %>


Quedaría más limpio así:

<% form_for :user, :builder=>LabeledFormBuilder do |f| %>
<fieldset>
     <%= f.text_field :login, :label=>"Login" %>
     <%= f.password_field :password, :label=>"Password" %>
</fieldset>
<% end %>


Todo lo que tienes que hacer es crearte una clase en app/builders:

class LabeledFormBuilder < ActionView::Helpers::FormBuilder

  helpers = field_helpers +
            %w{date_select datetime_select time_select} +
            %w{collection_select select country_select time_zone_select} -
            %w{hidden_field label fields_for} # Don't decorate these

  helpers.each do |name|
    define_method(name) do |field, *args|
      options = args.last.is_a?(Hash) ? args.pop : {}
      label = label(field, options[:label], :class => options[:label_class])
      @template.content_tag(:p, label +'
' + super)  #wrap with a paragraph
    end
  end

end



y añadir a tu config/environment.rb:


config.load_paths += %W( #{RAILS_ROOT}/app/builders)


Si quieres que por defecto todos tus formularios usen este builder, inicializa en application_helper o en algun initializer:

ActionView::Base.default_form_builder = LabeledFormBuilder

Controllers y Presenters

Cuando nos queremos dar cuenta, tenemos los controladores llenos de código y empiezan a ser pesados y difíciles de mantener. He visto que hay un patrón de diseño que permite mantener toda esta lógica "sobrante" en otra clase, y dejar en los controladores sólo la funcionalidad de recuperar datos de los modelos y decidir el flujo de la navegación. A este patrón lo llaman Presenter.

Consiste en crear una clase donde se haga toda la recogida de datos que se hace en los controladores. Por ejemplo, antes tenia un controlador con esta acción:

def show
  @profile = Profile.active.find(params[:id])
  @friends = @profile.friends.first 12
  @recommended_profiles = @profile.recommended(:limit => 12)
  @graffities = @profile.graffities.all(:limit => 12)
  Comment.preload_wall_associations(@graffities)
 

  store_location
 

  respond_to do |format|
    format.html # show.html.erb
    format.xml { render :xml => @profile }
  end
end


Los hay peores, pero esto se puede sustituir por:

  def show
    @presenter = ProfilePresenter.new(params)
    store_location

    respond_to do |format|
      format.html # index.html.erb
      format.xml { render :xml => @presenter }
    end
  end


Como se ve, en ProfilePresenter dejamos toda la lógica de recogida de datos.

class ProfilePresenter

  def initialize(params)
    @presenter_params = params
  end
 
  def profile
    @profile ||= Profile.active.find(@presenter_params[:id])
  end

  def friends
...

  end


  def recommended
...
  end


  def graffities
...
  end

end



Asi, en las vistas, podemos utilizar @presenter.profile o @presenter.friends, etc. y dejamos los controladores claros y limpios.

Estos presenters pueden dejarse en el directorio app/presenters, por ejemplo. No te olvides de añadir a config/environment.rb la linea:

config.load_paths += %W( #{RAILS_ROOT}/app/presenters)