Todos sabemos que en Ruby on Rails trabajamos con la filosofía fat model skinny controller por lo que estamos bastante acostumbrados a generar métodos dentro del modelo. Pues bien, un atajo a estos métodos son los scopes, que nos permiten generar subconjuntos de datos de nuestro modelo prácticamente en una línea de código, lo que los hace extremadamente atractivos para mantener nuestro código limpio, ordenado y además nos facilita mucho obtenerlos luego en nuestro controlador prefiltrados.
Pero vamos a mancharnos las manos de barro y vamos a ver exactamente el código con el que creamos un scope en rails. Recordad, el scope va en el modelo.
Imaginemos que tenemos una tienda online y queremos obtener datos algo refinados de nuestros artículos, pedidos y demás información, bien, vamos a ver algunos ejemplos útiles de como construir los scopes
Ejemplo 1. Scope simple
Ahora, si tenemos un modelo que se llama Product, por ejemplo, en el archivo product.rb incluiremos la siguiente línea
scope :enabled, -> { where(enabled: true) }
Ya tenemos nuestro primer scope, este scope nos devolverá todos los productos de nuestra tienda que estén habilitados (con el campo enabled a true) en realidad este scope es tan solo un método de clase que sustituye al siguiente código:
def self.enabled where(enabled: true) end
Y básicamente eso es un scope, un atajo de algunos métodos de clase muy fácil de escribir y práctico. Imaginad ahora el método index de nuestra tienda online, en el archivo products_controller.rb tendríamos algo como esto:
def index @products = Product.enabled end
Que es justo lo que queremos, un controlador simple y cortito, fácil de leer, en definitiva, por eso nos gusta tanto rails, no es así?
Ejemplo 2. Scope compuesto con asociación con otra tabla.
Pero vamos a ir un poquito más allá, ya que los scopes nos permiten también hacer queries más complejas, imaginad que queremos un scope con los pedidos prefiltrados de los últimos 6 meses, en nuestra base de datos, tenemos una tabla con los pedidos y otra tabla con los pagos, en la cual se almacena la fecha del pago, que es, de hecho, la fecha del pedido.
Si alguno de vosotros está pensando en este momento que la fecha del pago podría también ponerse en la tabla de pedidos, id a un rincón a pedir perdón y a autocastigaros de alguna manera dolorosa… no se duplica información en la base de datos, NEVER, no mancilléis vuestro nombre de programador ganado con horas de sufrimiento!
Dicho esto, vamos a ver como podríamos hacer un scope que nos diera esa información, en este caso, en el archivo Order.rb (o el archivo que represente nuestro modelo pedido) escribimos el siguiente scope:
scope :last_six_months, -> { joins(:payments).where('payments.payment_date > ?', 6.months.ago) }
Veis que sencillo? podemos incluso encadenar comandos de ActiveRecord, así que si no estáis usando scopes, ya podéis empezar a hacerlo, como véis es una forma muy limplia de prefiltrar datos y crear subconjuntos de nuestros modelos para llamarlos desde los controladores.
Y como no, si te interesa conocer más de Ruby on Rails, aquí te dejo el enlace de uno de los programas que le he dedicado en Full Stack Podcast
Deja una respuesta