Mejorando algunos scopes de Rails

Muchas veces, para filtrar los resultados por una relación padre, he hecho o me encontrado scopes como el siguiente:

scope :for_user, -> (user) { where(user_id: user.id) }

Que me permite hacer cosas del estilo

MiModelo.for_user( User.first )

Pero tiene el inconveniente de que sólo funciona con un parámetro de tipo User (bueno, en realidad con un objeto que responda a #id). En multitud de ocasiones me he encontrado con un modelo que tiene una dependencia belongs_to sobre User, es decir, tiene un atributo user_id pero que no puedo usar directamente, porque el scope sólo acepta un objeto. Así, acabo haciendo cosas del estilo de

# membership.user carga el objeto user de BBDD sin necesidad
MiModelo.for_user(membership.user)

Sin embargo, Rails es lo suficientemente listo para discriminar qué parámetro se le pasa al where, y si no forzamos que el parámetro sea un objeto, ampliamos muchísmo la funcionalidad del scope:

scope :for_user, -> (user) { where(user_id: user) }

Simplemente quitando el .id ya podemos hacer las siguientes consultas:

MiModelo.for_user(User.first)         # Usa un objeto como parámetro
MiModelo.for_user(User.active)        # Usa una relación como parámetro
MiModelo.for_user(User.active.to_a)   # Usa un array de objetos como parámetro
MiModelo.for_user(membership.user_id) # Use un número como parámetro
MiModelo.for_user(Course.user_ids)    # Usa un array de números como parámetro
MiModelo.for_user(1..100])            # Usa un rango de números como parámetro

Deja un comentario