Rails y el territorio de los helpers: ¿Qué responsabilidades pueden/deben tener los Helpers?


Ruby_on_Rails_logo (1)Hoy voy a hablar de un tema que me parece interesante,  el territorio de los helpers. Discutiendo sobre el tema que da título este post, en ocasiones nos planteamos qué cosas deberían ir en los helpers y podemos encontrarnos con métodos que hemos desarrollado nosotros mismos y en ocasiones no son muy acertados. Voy a intentar responder a las preguntas de ¿cuándo debo utilizar un helper? y ¿de qué manera debo hacerlo? Por ejemplo, imagina que tenemos un template que hacemos una llamada a un método helper y que dicho método helper lo que está haciendo es pintar una parte de HTML, ¿crees que un helper debería contener código HTML? es decir, ¿la etiqueta en este caso de tag(:br)?

def add_user_check_box(user)        

      content_tag(:label check_box_tag(“Users”,  + ” “  +  user.name ) +   tag(:br)

end

En mi opinión, creo que esto no pinta bien hacerlo así ya que el HTML no es territorio de helper es de la vista,  aunque únicamente sea que pinte una etiqueta tag, como es el caso o podemos añadir otras etiquetas HTML, select o checkboxes, dentro del método helper del ejemplo, pero tampoco sería el helper el lugar adecuado para ello, entonces yo me pregunto:

¿qué responsabilidad deberíamos dar el helper?, en mi opinión “Los helpers deberían ocultar complejidad en la que no tendría que formar parte de la vista, pero un helper tampoco debería contener HTML o responsabilidades añadidas como qué contenidos deben verse en caso de utilizar un método de autorización y que otros métodos podrían llegar a conocer por ejemplo o entablar relación con el modelo al preguntarle por atributos….”.

En mi opinión deberíamos tener un método y una vista como la siguiente:

HELPER

def add_user_check_box(user)        

      content_tag(:label,  check_box_tag(“Users”,  + ” “  +  user.name )

end

VISTA

<% user_without_project(project).each do |user| %>

        <label class=“checkbox”>

                <%= add_user_check_box(user) %>

        </label>

<% end %>

Veamos cómo analizamos todas las incógnitas, si partimos de la siguiente situación:

module UsersHelper
    def avatar_name(user)
        if user.avatar_image_name.present?
            user.avatar_image_name
          else
            “default.png”
       end
   end
end
Podemos observar que hemos incorporado en el helper de Users, un método que extrae de complejidad lógica en la vista, para disponer de la imagen del avatar del usuario o una imagen por defecto si no dispone aún de la suya propia. Entonces en la Vista contiene lo siguiente:
<div id=“profile”>
<%= link_to_if @user.url.present?, image_tag(“avatars/#{avatar_name(@user)}, class: “avatar”), @user.url %>
<h1><%= link_to_if @user.url.present?, (@user.full_name.present? ? @user.full_name : @user.username), @user.url %></h1>
<dl>
<dt>Username:</dt>
<dd><%= @user.username %></dd>
<dt>Member Since:</dt>
<dd><%= @user.created_at.strftime(“%B %e, %Y”) %></dd>
<dt>Website:</dt>
<dd>
<% if @user.url.present? %>
      <%= link_to @user.url, @user.url %>
    <% else %>
      <span class=“none”>None given</span>
    <% end %>
</dd>……………………………………………….more code

En este caso, tal como hemos mencionado anteriormente, estamos haciendo uso de un helper “avatar_name”,  nos quita de complejidad lógica en la vista y de tener dentro de la misma vista lo siguiente:

  if user.avatar_image_name.present?
      user.avatar_image_name
    else
      “default.png”
    end
Pero ahora nos preguntamos, ¿tiene nuestra vista la lógica en la que estamos accediendo al modelo con condiciones y otras lógicas de decisión? ¿debería estar contenida en la vista? o por el contrario ¿debería estar en el helper?, si la respuesta en positiva, entonces debemos pensar en llevarnos dicha lógica que contiene acceso al modelo y con lógica de decisiones a un Pattern Presenter o en un Pattern Decorator, que aplican la misma solución al mismo problema (en breve hablaré sobre cómo ordenar las vistas con ambos patrones).  Un adelanto ya que estamos hablando sobre helpers.
Si tenemos que tratar con un Presenter para llevarnos la lógica de la vista, lo que necesitamos es arrancar para apoyarnos, un helper, ya que no dependemos de parámetros o de variables de sesión y dicha responsabilidad recae sobre el Helper a la hora de crear el patrón Presenter y no sobre el controlador. Por tanto deberíamos declarar en un module UserHelper o ApplicationHelper nuestro método de inicio:
module UserHelper     
         def user_status_for(designer = @designer)           
                presenter = UserStatus.new(designer)           
                if block_given?               
                     yield presenter           
                else               
                     presenter           
                end     
         end
end
Seguiremos hablando de Helpers y Patrones para ordenar nuestras Vistas.
Nota de mejora: Comentando con Diego Rodríguez de Teowaki algunas cosas de Rails. me decía que es mejor escribir código más cercano a Rails y que sea el código más claro a la hora de leerlo y es cierto que queda más claro, pero además en una única línea. Veamos dicha mejora:
user.avatar_image_name.presence || ‘default.png’ 
en sustitución del código de:
if user.avatar_image_name.present?
      user.avatar_image_name
    else
      “default.png”
    end
Creo que no queda duda alguna de dicha mejora, gracias Diego!!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s