Como tratar requisições web com Ruby on Rails
Nesse artigo iremos conhecer um pouco melhor o framework Ruby on Rails, iremos aprender a trabalhar com o tratamento de requisições web em um sistema que permite o cadastro de usuários de um sistema.
O framework Ruby on Rails é open-source desenvolvido por David Heinemeier Hansson, para a construção de aplicações web, escrito totalmente em Ruby, linguagem de script. Todas as aplicações desenvolvidas em Rails seguem o padrão de arquitetura MVC (Model-View-Controller).
O Rails é um meta-framework, ou seja, um framework composto por outros frameworks, são eles: Active Record, Action Pack, Action Mailer, Active Support e Action Webservices.
Modelo para Cadastro de Usuários
Nossa aplicação deverá conter três camadas: modelo, controle e visão. O Modelo pode ser considerado a camada mais importante de um projeto MVC, dessa forma, devemos iniciar nossa aplicação implementando essa camada. Vamos construir um modelo para cadastro de usuários que deverá conter os seguintes dados: Nome completo, E-mail, Senha e Endereço.
O Rails disponibiliza uma série de geradores de código que aumentam a produtividade no desenvolvimento, assim o desenvolvedor não precisa implementar a aplicação do zero, mas com um simples comando pode pedir ao Rails que crie alguns aspectos básicos da aplicação, como as funções de um CRUD.
O primeiro passo é entrar no diretório que se pretende guardar o projeto, pelo prompt de comando, e digitar o seguinte código:
rails new usuarios
Entre no diretório usuario que acabamos de criar e digite o comando a seguir para rodar sua aplicação:
rails server
Agora que já criamos uma aplicação, então poderemos criar o nosso modelo e garantir a integridade dos dados. Para o nosso exemplo utilizaremos o gerador de modelos já nos fornece uma classe User. Use o comando a seguir para gerar esse modelo:
$ rails generate model user full_name email password address:text
Não devemos esquecer de gerar o banco de dados da aplicação usando o código a seguir:
rake db:create
Após o comando de geração do modelo, o Rails irá gerar vários códigos, dentre eles uma migração, que tem como função registrar as alterações feitas no schema do banco de dados. Esta pode ser encontrada no diretório db/migrate, onde também se encontra um arquivo cujo nome inicia com a data de criação do modelo e termina com _create_usuario.rb. Na Listagem 1 vemos o código dessa migração.
Listagem 1. Migração gerada automaticamente.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :full_name
t.string :email
t.string :password
t.string :address
t.timestamps
end
end
end
Para dar continuidade a criação do nosso modelo, altere a classe CreateUser, como mostrado na Listagem 2.
Listagem 2. Classe CreateUsers com alteração.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :full_name
t.string :email
t.string :password
t.string :address
t.index :email, unique: true
t.timestamps
end
end
end
A partir dessa alteração será criado um índice para o campo e-mail da tabela users adicionando a propriedade de unicidade. Para vermos o resultado da nossa alteração, vá ao prompt de comando do Rails e digite:
$ rake db:migrate
.
O resultado deve ser algo como:
== CreateUsers: migrating ========================
-- create_table(:users)
-> 0.0093s
== CreateUsers: migrated (0.0140s) ===============
O resultado foi a criação de uma tabela no banco de dados e a adição do índice.
Agora vamos voltar para o console do Rails para alterar o banco de dados de forma direta. Para isso, vamos fazer alguns testes, como mostrados na Listagem 3.
Listagem 3. Acessando diretamente o banco de dados.
User.create email: 'admin@devmedia.com'
# A saída será a seguinte (com quebra de linhas para facilitar a visualização):
# => #<User id: 1,
# full_name: nil,
# email: "admin@devmedia.com",
# password: nil,
# address: nil,
# created_at: "2015-05-04 15:22:45",
# updated_at: "2015-05-04 15:22:45">
Inicialmente o Rails adicionou o campo id, apesar de não haver qualquer declaração de migração. Repare que esta é a chave primária do banco que o Rails adicionou automaticamente.
Também observamos que os campos full_name, password e address possuem seu valor como nil, por ainda não termos atribuído nenhum valor a eles. No entanto, podemos perceber que os campos created_at e updated_at foram populados automaticamente.
Criando Validações
É muito importante criarmos validações para evitar a entrada de dados errados. O Active Record nos fornece um conjunto de validações que podemos aplicar na maioria das situações cotidianas como, por exemplo, o preenchimento de formulário com sexo masculino ou feminino, e-mail e etc. Além das validações padrão, o Rails fornece ferramentas para implementarmos nossas próprias validações. Para isso, usamos o recurso de class macros. Assim, a nossa validação irá exigir o E-mail, nome, endereço e senha, juntamente com a repetição da senha, para que o usuário não cometa nenhum erro de digitação.
Inicialmente iremos implementar as validações de presença e de informações obrigatórias do formulário, alterando a classe user.rb, que está localizada em app/models/user.rb. Use o código a seguir para tal modificação:
class User < ActiveRecord::Base
validates_presence_of : email, :full_name, :address, :password
end
Após salvar o arquivo da classe user.rb volte ao rails console e digite o código presente na Listagem 4 para testar nossa validação.
Listagem 4. Testando a validação de presença.
user = User.new
user.valid? # => o retorno deverá ser false
user.save # => o retorno deverá ser false
user = User.new
user.email = 'seunome@devmedia.com'
user.full_name = 'Seunome'
user.location = 'Rio Grande do Norte, Brasil'
user.password = 'minhasenha'
user.valid? # => o retorno deverá ser true
user.save # => o retorno deverá ser true
Ao executar o comando #valid?, o ActiveRecord irá executar todas as validações que estiverem disponíveis no modelo e imprimir no console o resultado.
O método #save executa o #valid? e, caso todas as validações sejam executadas com sucesso, ele irá salvar no banco de dados o modelo user. Caso tudo ocorra bem, o método #save retornará true, e caso contrário, retornará false.
Agora que já conhecemos como funcionam as validações, vamos implementar a validação da confirmação da senha, usando para isso o modelo user da Listagem 5.
Listagem 5. Validação para confirmação de senha.
class User < ActiveRecord::Base
validates_presence_of :email, :full_name, :location, :password
validates_confirmation_of :password
end
Quando utilizamos o validates_confirmation_of, só poderemos salvar um objeto no banco de dados se tivermos um atributo “virtual” chamado password_confirmation. Não é necessária a criação manual desse atributo, pois o próprio ActiveRecord::Base o cria.
Ainda no console do rails execute os comandos apresentados na Listagem 6.
Listagem 6. Testando nossas validações.
reload! # Reloading...
# => true
user = User.new
user.email = 'seunome@devmedia.com'
user.full_name = 'Seunome'
user.location = 'Rio Grande do Norte, Brasil'
user.password = 'minhasenha'
user.password_confirmation = 'errei_minha_senha'
user.valid? # => false
# As senhas não são iguais
user.errors.messages # => {:password=>["doesn't match confirmation"]}
Ao executar os comandos #save ou #valid? será populado o atributo erros, fornecendo os erros que ocorreram durante a validação.
Agora criaremos uma validação para o formato do e-mail, pois da forma atual podemos adicionar qualquer coisa no campo, sem necessariamente se referir a um formato válido. Para isso, poderíamos utilizar o validates_format_of, que valida o formato de um texto com uma expressão regular, mas iremos optar por construir nossa própria validação para entendermos como esse processo funciona.
Nossa validação informa ao usuário quando algo estiver errado com o e-mail fornecido. Para isso, usaremos uma expressão regular retirada da biblioteca Devise (para baixá-la use o link disponível na seção Links).
O nosso código ficará como o apresentado na Listagem 7.
Listagem 7. Validação do formato de e-mail.
class User < ActiveRecord::Base
EMAIL_REGEXP = /\A[^@]+@([^@\.]+\.)+[^@\.]+\z/
validates_presence_of :email, :full_name, :address, :password
validates_confirmation_of :password
validate :email_format
private
# Essa validação pode ser representada da seguinte forma:
# validates_format_of :email, with: EMAIL_REGEXP
def email_format
errors.add(:email, :invalid) unless email.match(EMAIL_REGEXP)
end
end
Agora vamos criar uma validação para garantir que não teremos mais de um usuário cadastrado com o mesmo e-mail, utilizando para isso o validates_uniqueness_of. Contudo, vale ressaltar que existe um problema com esse método, pois o Rails primeiro checa se o e-mail fornecido já está cadastrado e logo após cria o modelo no banco de dados, se tudo tiver dado certo. Dessa forma, não é descartada a hipótese de, entre a verificação e a criação, o e-mail ser inserido no banco de dados, fazendo com que o Rails tente criar o modelo mesmo não estando tudo ok. Para evitar esse problema devemos criar também uma validação para o banco de dados, assim a validação criada no modelo servirá apenas para dar um retorno ao usuário. O código para isso é o apresentado na Listagem 8.
Listagem 8. Nova validação para formato de e-mail.
class User < ActiveRecord::Base
EMAIL_REGEXP = /\A[^@]+@([^@\.]+\.)+[^@\.]+\z/
validates_presence_of :email, :full_name, :address, :password
validates_confirmation_of :password
validates_uniqueness_of :email
# Essa validação pode ser representada da seguinte forma:
# validates_format_of :email, with: EMAIL_REGEXP
validate do
errors.add(:email, :invalid) unless email.match(EMAIL_REGEXP)
end
end
Tratando Requisições Web
Agora que já estamos com o nosso modelo e banco de dados prontos e todas as validações já estão funcionando corretamente, iremos começar a tratar nossas requisições web.
Primeiro vamos começar criando um código que mostre ao roteador do Rails como interpretar requisições de uma determinada URL. Iremos modificá-lo para adicionar algumas ações ao recurso usuário indicando rotas tanto no roteador quanto no controle que responderá as requisições. Para isso devemos editar o arquivo config/routes.rb, presente na Listagem 9.
Listagem 9. Arquivo de rotas padrão.
Usuario::Application.routes.draw do
resources :users
# Aqui estará diversos comentários gerados automaticamente pelo Rails
# explicando o funcionamento do roteador.
end
Agora iremos fazer um pequeno teste executando o servidor Rails. Para isso acesse a pasta do projeto e execute o rails server, como fizemos anteriormente.
Em seguida, abra algum navegador e entre no endereço http://localhost:3000/users/new. Deverá ser exibida uma tela de erro, como a da Figura 1.
Figura 1. Erro: Routing error (Erro de roteamento)
Esse erro é muito comum, pois aqui o roteador está tentando encaminhar a execução das requisições de um recurso para o controle correspondente. No nosso caso em especial, o Rails irá tentar encaminhar todas as rotas que possuírem /users para o controle do usuário o UsersController, mas, no entanto, esse controle ainda não existe.
Os controladores devem ser encontrados na pasta app/controllers, então dentro dessa pasta devemos criar o arquivo users_controller.rb com o código a seguir:
class UsersController < ApplicationController
end
Um controle é uma classe Ruby que obrigatoriamente deve herdar de ApplicationController, que é uma classe abstrata fornecendo características globais. Ela é gerada quando criamos a aplicação a partir do comando rails new. Se abrimos o arquivo app/controllers/application_controller.rb veremos o seguinte código apresentado na Listagem 10, que foi gerado automaticamente pelo Rails.
Listagem 10. Classe ApplicationController.
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
Agora vamos implementar uma ação no controle de usuários, criando a ação de cadastro de um novo usuário, ou seja, a ação create. Devemos adicionar a ação new no userController, que pode ser encontrado em app/controllers/users_controller.rb. Veja a Listagem 11.
Listagem 11. Implementando a ação create no UsersController.
class UsersController < ApplicationController
def new
end
end
Por enquanto vamos deixar esse método vazio, mas voltaremos a trabalhar nele depois.
Se voltarmos a acessar http://localhost:3000/users/new veremos que será apresentado um erro diferente: o Template is missing, que quer dizer que a ação foi encontrada, no entanto, o Rails não está conseguindo achar a apresentação dessa ação, como mostra a Figura 2.
Figura 2. Erro: Template is missing (template ausente)
Todos os templates podem ser encontrados na pasta app/views, onde iremos encontrar uma hierarquia. Assim como vimos que o nome do controle deriva do nome do recurso, da mesma forma iremos encontrar uma convenção do Rails para os templates. Nesse caso, se possuirmos um controle chamado UserSessionsController, os seus templates deverão ser procurados em app/views/user_sessions. Sendo assim, os templates do controle UsersController estão sendo procurados em app/views/users.
Dentro da pasta app/views encontramos os templates que geralmente são utilizados por vários controles e são a base para a injeção do template de cada ação. Para entendermos melhor vamos observar a Listagem 12.
Listagem 12. Composição de página usando layouts, código fonte do arquivo app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Colchonet</title>
<%= stylesheet_link_tag “application”,
media: “all”,
“data-turbolinks-track” => true %>
<%= javascript_include_tag “application”,
“data-turbolinks-track” => true %>
<%= csrf_meta_tags %>
</head>
<body>
</body>
</html>
A utilização de layouts torna-se bem prática, pois não há a necessidade da repetição de comandos e tags, sendo apenas necessária a escrita do código HTML específico da página que será inserido no layout da sua aplicação.
A diferença entre ações e layouts de ações é que o primeiro executa o comando yield, que informa ao Rails o local onde deverá ser inserido um outro template. Veja a Listagem 13.
Listagem 13. Conteúdo do arquivo application.html.erb.
<html>
<body>
<%= yield %>
</body>
</html>
Se no template da ação new do controle UsersController tivermos o código a seguir:
<h1>Cadastro</h1>
render "new", layout: "application"
Será gerado automaticamente pelo Rails o código apresentado na Listagem 14.
Listagem 14. Código gerado pelo Rails.
<html>
<body>
<h1>Cadastro</h1>
</body>
</html>
Configurando a Ação Raiz (Root)
A ação root é executada quando entramos no endereço raiz do site, que no caso é http://localhost:3000/. No nosso exemplo, essa página ainda está exibindo a página de boas-vindas do Rails.
O arquivo config/routes.rb aponta para a página principal da aplicação, então só precisamos alterar a entrada para a nossa página principal que ainda iremos criar, como mostra a Listagem 15.
Listagem 15. Conteúdo do arquivo routes.rb.
Colchonet::Application.routes.draw do
resources :rooms
resources :users
root 'home#index'
end
O código “home#index” se refere ao controle HomeController e a ação index. Precisamos então criar o arquivo home_controller.rb na pasta app/controllers/, que deve conter o código mostrado na Listagem 16.
Listagem 16. Conteúdo do arquivo home_controller.rb.
class HomeController < ApplicationController
def index
end
end
Crie a pasta app/views/home e dentro dela o template index.html.erb, que deve conter o código mostrado na Listagem 17.
Listagem 17. Implementação do template index.html.erb.
<h1>Página Inicial</h1>
<p>
Escolha uma das ações a seguir:
<ul>
<li><%= link_to "Cadastro", new_user_path %> </li>
<li><%= link_to "Visualizar quartos", rooms_path %> </li>
</ul>
</p>
Após a implementação do último template possuímos uma página principal customizada e não mais a página do Rails.
Não deixe de conferir tb o curso de Ruby on Rails da DevMedia.
Links
Biblioteca Devise
http://github.com/plataformatec/devise
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo