Rails: Búsquedas sin alcance/ámbito (unscoped) en ActiveRecord

09 Jul
Published by fernando.villalobos in

Tags 

Rails, Ruby

Rails

Cuando trabajamos con modelos ActiveRecord en Rails, solemos definir scopes de búsqueda (los más comunes suelen ser para ordenamiento o filtrado), por ejemplo:

default_scope :order => "created_at DESC"
default_scope { where(published: true) }

Pero ¿qué pasa si queremos realizar alguna búsqueda ignorando dichos scopes? Vamos a suponer que queremos obtener todos los articulos, incluso los no publicados (published: false):

Article.where(published: false) -> []

Siempre obtendremos resultados vacíos, ya que el default_scope está de por medio. Para lidiar con ésto tenemos el método unscoped en 2 variantes.

unscoped a nivel de modelo/relation

Basta con llamar al método antes del llamado al where

Article.unscoped.where(published: true) -> [<Article>, <Article>]

Lo que hace unscoped es eliminar toda la cláusula where construida hasta ese punto, devolviéndonos un objeto limpio a partir del cual podemos realizar nuevas consultas.

Ahora, como mencioné hace un momento (hasta lo puse en negritas) unscoped borra toda la cláusula where, entonces, como podrán suponer, si yo ya tengo un ActiveRelation construido, unscoped me "reiniciará" el objeto, perdiendo toda la consulta previa (en el ejemplo queremos obtener todos los artículos creados el día de hoy, sin importar si han sido publicados o no).

articles = Article.where(created_at: date).count -> 2
articles.unscoped.count -> 5

Para estos casos, tenemos la segunda variante de uso

unscoped a nivel de clase

Similar a lo que se hizo en el punto anterior, debemos usar el método unscoped PERO a nivel de clase, de la siguiente forma:

Article.unscoped do
  articles = Article.where(created_at: date)
  articles.count -> 2
end

Aplicando el unscope de esta manera, eliminamos únicamente el scope que ha sido puesto desde la clase.

Espero les sea de utilidad.