DEV Community

Gabriel Schiavo
Gabriel Schiavo

Posted on • Edited on

4 3

Utilizando Scopes em Ruby on Rails

ActiveRecord é uma das engines dentro do core Rails, que trás consigo a implementação de um ORM (Object Relational Mapping), que é um conceito dentro da arquitetura de software na qual utilizamos técnicas de programação para converter/lidar com dados entre o banco de dados e a programação orientada a objetos, nesse caso, utilizando Ruby.

Ruby on Rails é um poderoso framework MVC que trás consigo várias soluções flexiveis e inteligentes para problemas já conhecidos dentro do desenvolvimento back-end.
Podemos citar algumas soluções que vem trazendo bastante poder aos desenvolvedores, porém hoje, trago uma funcionalidade que podemos utilizar nativamente em Rails, visto que vamos utilizar a RailsEngine::ActiveRecord

O funcionamento por “baixo dos panos” é poder fazer queries em SQL puro, porém utilizando os conceitos e métodos através de uma linguagem padrão.

Scopes em Ruby on Rails

• O que são scopes?

Geralmente utilizamos scopes para construir queries personalizadas dentro das entidades modelo da aplicação, e além disso, podemos utilizar o scope criado como um método de classe. Assim, fazemos uso desses scopes como qualquer outro método presente no ActiveRecord.

Sintaxe e parâmetros

Todo scope precisa receber dois argumentos, são eles:

• 1. Um nome, que será usado para chamar este scope no código.

• 2. Uma lambda, que implementa a query.

A sintaxe de um scope é definido por:

scope :name_of_your_scope, -> { where(“column_name = ?”, value)}

Também podemos passar diferentes parâmetros para utilizarmos ao fazer as nossas buscas. Para elucidar o conceito, suponhamos que seja necessário buscar em uma base de dados, os usuários que foram criados nos ultimos 30 dias.

Podemos declarar o scope para receber o parametro date da seguinte maneira:

class User < ApplicationRecord
  scope :get_users_by_date, -> (date) { where(*"created_at > ?"*, 30.days.ago if date.nil?) }
end
Enter fullscreen mode Exit fullscreen mode

Caso não seja passado nenhuma data, colocamos por padrão 30 dias a partir do dia de hoje.

Como resultado da chamada deste scope, recebemos um objeto do tipo ActiveRecord::Relation. Isso significa que podemos encadear e combinar diferentes scopes. Também, em termos de funcionalidade, o scope garante que erros sejam evitados caso o retorno da nossa query venha vazio.

Scopes com SQL puro

Outro jeito válido de declararmos scopes, é utilizando queries com SQL puro, assim conseguimos passar um ou mais parâmetros no scope e utilizá-los dentro da query, e claro, evitando injeção de outros parâmetros desnecessários na busca.

class User < ApplicationRecord
  scope :find_by_range_date, -> (start_date, end_date) { where(created_at >= ? AND created_at <= ?“, start_date, end_date)}
end
Enter fullscreen mode Exit fullscreen mode

Scope vs Default Scope

Quando declaramos um default_scope, garantimos que por padrão, essa query será aplicada automaticamente em nosso modelo.

class User < ApplicationRecord
 default_scope { where(admin: true) }
end
Enter fullscreen mode Exit fullscreen mode

Esse comportamento redefine por padrão o método .all do nosso modelo, portando devemos evitar seu uso, visto que alguns erros e tempo de depuração não sejam perdidos.

Conclusão

Um dos grandes potenciais do Rails é poder combinar ou encadear outros scopes diferentes, assim podemos criar queries mais fáceis de ler, ex:

def index
  date = Date.new(12/21/2021)
  @users = User.sort_by_creation(date).some_other_scope.where.not(role: admin)
end
Enter fullscreen mode Exit fullscreen mode

Assim, ao utilizarmos outros scopes e até os métodos padrões do ActiveRecord, podemos separar de forma mais limpa e clara, as responsabilidades e funcionalidades de cada query presente **nos modelos.

Outro ponto que não abordei ao longo deste guia, foi o uso de Lambdas para escrevermos os scopes utilizando apenas uma linha. Isso acontece pois a lambda é um objeto do tipo Proc. Basicamente, um proc, é um objeto que encapsula um bloco de código, exemplo:

lambda = ->(x) { x**2 }

lambda = Proc.new {|x| x**2 }

Ao fazer lambda.(3) ou lambda.call(3) em ambas as variavéis, vamos receber o resultado 9. Mas isso deixo pra abordar em meu proximo aprendizado, até mais, nos vemos lá!

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay