Ruby on Rails
Patrón decorador
Buscar..
Observaciones
El patrón Decorator le permite agregar o modificar el comportamiento de los objetos de una manera coyuntural sin afectar el objeto base.
Esto se puede lograr a través de Ruby usando el stdlib, o por medio de gemas populares como Draper .
Decorar un modelo utilizando SimpleDelegator
La mayoría de los desarrolladores de Rails comienzan modificando la información de su modelo dentro de la propia plantilla:
<h1><%= "#{ @user.first_name } #{ @user.last_name }" %></h1>
<h3>joined: <%= @user.created_at.in_time_zone(current_user.timezone).strftime("%A, %d %b %Y %l:%M %p") %></h3>
Para modelos con una gran cantidad de datos, esto puede volverse engorroso rápidamente y llevar a copiar y pegar la lógica de una plantilla a otra.
Este ejemplo utiliza SimpleDelegator
de la stdlib.
Todas las solicitudes a un objeto SimpleDelegator
se pasan al objeto principal de forma predeterminada. Puede anular cualquier método con lógica de presentación, o puede agregar nuevos métodos que sean específicos para esta vista.
SimpleDelegator
proporciona dos métodos: __setobj__
para establecer a qué objeto se está delegando, y __getobj__
para obtener ese objeto.
class UserDecorator < SimpleDelegator
attr_reader :view
def initialize(user, view)
__setobj__ @user
@view = view
end
# new methods can call methods on the parent implicitly
def full_name
"#{ first_name } #{ last_name }"
end
# however, if you're overriding an existing method you need
# to use __getobj__
def created_at
Time.use_zone(view.current_user.timezone) do
__getobj__.created_at.strftime("%A, %d %b %Y %l:%M %p")
end
end
end
Algunos decoradores confían en la magia para conectar este comportamiento, pero puede hacer que sea más obvio de dónde proviene la lógica de presentación al inicializar el objeto en la página.
<% user = UserDecorator.new(@user, self) %>
<h1><%= user.full_name %></h1>
<h3>joined: <%= user.created_at %></h3>
Al pasar una referencia al objeto de vista al decorador, aún podemos acceder al resto de los asistentes de vista mientras construimos la lógica de presentación sin tener que incluirlo.
Ahora, la plantilla de vista solo se ocupa de insertar datos en la página, y es mucho más claro.
Decorando un modelo usando Draper
Draper combina automáticamente los modelos con sus decoradores por convención.
# app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
def full_name
"#{object.first_name} #{object.last_name}"
end
def created_at
Time.use_zone(h.current_user.timezone) do
object.created_at.strftime("%A, %d %b %Y %l:%M %p")
end
end
end
Dada una variable @user
que contiene un objeto ActiveRecord, puede acceder a su decorador llamando a #decorate
en @user
, o especificando la clase Draper si desea ser específico.
<% user = @user.decorate %><!-- OR -->
<% user = UserDecorator.decorate(@user) %>
<h1><%= user.full_name %></h1>
<h3>joined: <%= user.created_at %></h3>