Delegando atributos de ActiveRecord

El otro día tratando de mejorar un modelo de una aplicación me topé con el problema de tener muchos atributos virtuales para poder acceder a atributos de un objeto relacionado y no caer en lo siguiente :

class Player < ActiveRecord::Base
  belongs_to :user

  def name
    user.name
  end

  def email
    user.email
  end

  # ... y varios más
end

Esto no lo puedo evitar mucho ya que Player es una clase intermedia en una relación de N-M entre los usuarios y los partidos, y además contiene información necesaria para la lógica del modelo.

Tampoco era muy feliz tener por todos lados Message Chains:

@player.user.name
@player.user.email
# etc ....

Una de las recomendaciones que se usan en estos casos es Hide Delegate para ocultarle al cliente de donde sale el dato realmente. Cabe aclarar que no siempre son un problema las llamadas encadenadas.

Recordando el anuncio de Rails 2.2 noté que al final hablaba de un delegate que tenía un nuevo feature. Buscando un rato por google encontré este post donde hablaba de un método delegate para hacer justamente esto que yo quería.

Lo extraño, que también menciona el autor es que no está documentado en la API oficial de Rails aunque mirando el código veo que explica como usarla. Explícitamente dice :

Provides a delegate class method to easily expose contained objects’ methods as your own

En la documentación también aclara que es útil tanto para atributos propios como para asociaciones entre diferentes instancias de ActiveRecord. La realidad es que por cómo está implementada funciona para cualquier objeto ruby que se nos ocurra.

El ejemplo con el que empezamos el post quedaría resumido a :

class Player  :user
end

Quedando mucho más corto el código, por lo tanto más fácil de mantener.

Tomando prestado los ejemplos del otro blog, también podemos hacer cosas con atributos que no son asociaciones, como por ejemplo una fecha :

# Forma abreviada
class Content  :published_at
end

# Forma desglosada
class Content  :published_at
  delegate :month, :to => :published_at
  delegate :day, :to => :published_at
end

# Podemos escribir
@content.year

# en lugar de
@content.published_at.year

2 comentarios en “Delegando atributos de ActiveRecord”

  1. No entiendo porqué en tu ejemplo usas:
    delegate :name, :email, … , :to => :user
    y en el ‘robado’ hacen cosas bastante más feas para delegar a un mismo objeto varios atributos (como el each, o repetir 3 veces la linea).

    La sintaxis que pusiste vos anda? Porque si es así esa ‘forma abreviada’ y su ‘forma desglosada’ son simplemente una negrada desagradable… o me estoy perdiendo algo?

    Me gusta

  2. No se porqué el ejemplo se complica usando un each. La documentación dice “Multiple delegates to the same target are allowed” y el ejemplo que di lo estoy usando.

    Ahi edito y le saco el each. Al parecer el flaco del otro blog sacó el ejemplo de Mephisto.

    Me gusta

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 )

Google+ photo

Estás comentando usando tu cuenta de Google+. 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 )

Conectando a %s