Ruby on Rails é um framework web poderoso e flexível e na maioria de projetos, é possível construir aplicações robustas apenas com o que o framework oferece. No entanto, há momentos em que precisamos ir além do que o Rails oferece por padrão, e pensar fora da caixa.
Uma maneira simples e elegante de fazer isso é utilizando POROs
(Plain Old Ruby Objects) para encapsular regras de negócio, validações e outras lógicas que não se encaixam perfeitamente em modelos do ActiveRecord ou controladores.
class PersonForm
attr_accessor :age, :name, :birthday, :favorit_color
def initialize(params = {})
@age = params[:age]
@name = params[:name]
@birthday = params[:birthday]
@favorit_color = params[:favorit_color]
end
def call!
# Do some cool stuff
end
end
person = PersonForm.new(age: "92", name: "Buzz Aldrin", birthday: "20-01-1930")
person.age
# => "92"
person.birthday
# => "20-01-2930"
person.favorit_color
# => nil
Com isso, já seria possível isolar coisas como: validações personalizadas; definir atributos padrões; normalizar parâmetros e etc.
Agora, é comum que você queira que o age
seja um número inteiro e o birthday
seja um objeto do tipo Date
. Para isso, você pode fazer o cast dos dados manualmente:
require 'date'
class PersonForm
attr_accessor :age, :name, :birthday, :favorit_color
def initialize(params = {})
@age = params[:age].to_i
@name = params[:name]
@birthday = Date.parse(params[:birthday])
@favorit_color = params[:favorit_color]&.strip || 'red'
end
def call!
# Do some cool stuff
end
end
person = PersonForm.new(age: '92', name: ' Buzz Aldrin ', birthday: '20-01-1930')
person.age
# => 92
person.birthday
# => <Date: 1930-01-20 ((2425997j,0s,0n),+0s,2299161j)>
person.favorit_color
# => "red"
Também é comum que você queira validar os dados, por exemplo, garantir que o name
não seja nil
ou vazio. Para isso, você pode irá precisar adicionar métodos de validação, definir um formato de errors e aí que o ActiveModel
pode te ajudar.
ActiveModel::Attributes
Se você está em um projeto Ruby on Rails, provavelmente, já tem o AvtiveModel::Attributes
disponível para usar. Ele permite que você defina atributos com tipos específicos e validações
out-of-the-box, tornando o processo de criação de POROs mais simples.
Uma maneira de fazer isso é incluindo o módulo ActiveModel::Model
e ActiveModel::Attributes
no seu PORO. Isso lhe dará acesso a funcionalidades como validações, atributos “tipados” e irá entregar uma estrutura que provavelmente você já está acostumado a trabalhar.
class PersonForm
include ActiveModel::Model
include ActiveModel::Attributes
validates :name, presence: true
attribute :age, :integer
attribute :name, :string
attribute :birthday, :date, default: -> { Date.new }
attribute :favorit_color, :string, default: 'red'
def call!
# Do some cool stuff
end
end
person = PersonForm.new(age: '92', name: 'Buzz Aldrin', birthday: '20-01-1930')
person.age
# => 92
person.birthday
# => <Date: 1930-01-20 ((2425997j,0s,0n),+0s,2299161j)>
person.favorit_color
# => "red"
person = PersonForm.new(age: '92', name: nil, birthday: '20-01-1930')
person.valid?
# => false
person.errors.full_messages
# => ["Name can't be blank"]
Como pode ver, a gente ganha métodos como valid?
e errors
para validar os dados e obter mensagens de erro, além de poder definir atributos com tipos específicos, como :integer
, :string
, :date
, etc.
Tem um framework no meu framework
Amarrar toda sua codebase em bibliotecas externas também é algo perigoso. O Ruby on Rails já entrega uma gama extraordinária de implementações de alto nível e mantido por desenvolvedores muito experientes, provavelmente, você já tem tudo o que precisa para resolver a maioria dos problemas comuns.
Fique atento para não criar uma sobrecarga desnecessária e transformar algo simples em algo complexo.
- Faça funcionar primeiro Foque no simples, faça funcionar primeiro. Algo importante, e que é necessário ficar atento, é que não há problemas em, inicialmente, manter duplicidade de código. Lembre-se de que abstrações prematuras, ou mal elaboradas, podem acabar se transformando em armadilhas.
Conclusão
Embora seja tentador adicionar gemas e gemas é importante lembrar que a simplicidade é muitas vezes a chave. Se concentrar no negócio e pensar de forma simples, podemos evitar estar cavando um buraco mais fundo do que o necessário.