Faça sua própria loja virtual com Ruby on Rails. Com essa nova série de artigos você aprenderá como criar uma loja para venda de livros onde os usuários poderão escolher o que comprar através de uma interface rica.
Esta edição da WebMobile traz o último artigo de um minicurso sobre Ruby on Rails. Esta série apresentava as características básicas do framework através da criação de um sistema de publicação de posts. O desenvolvimento do blog mostrou como as ferramentas do Ruby on Rails podem ser utilizadas e na prática foram criados recursos para autenticação, busca e comentários de usuários.
A partir desta edição um novo projeto será criado. Dessa vez vamos desenvolver uma livraria virtual, onde os usuários poderão comprar livros sem sair de casa, em um serviço semelhante às livrarias virtuais existentes na Internet. Para começar, serão apresentadas as funcionalidades da loja e criaremos o catálogo de produtos.
Funcionalidades
A Figura 1 apresenta como será nossa loja virtual. Entre as funcionalidades que serão desenvolvidas na série, estão:
- Catálogo de livros;
- Filtros para autor e categoria;
- Busca, em uma interface com paginação de resultados;
- Carrinho de compras com Ajax;
- Cadastro de usuários, onde as vendas só serão efetuadas por usuários registrados;
- Página do administrador com registros dos pedidos dos usuários.
Com as funcionalidades apresentadas, chegou a hora de definirmos nosso ambiente de desenvolvimento e começarmos a programação do aplicativo.
Ambiente de desenvolvimento
Antes de iniciarmos o desenvolvimento, é preciso configurar o ambiente que iremos utilizar para desenvolver a aplicação. Vamos utilizar o banco de dados MySQL e a versão mais atualizada do framework Ruby on Rails. Antes de começar, verifique se você possui a última versão do framework Rails instalado. Para isso, execute no terminal o comando:
gem list
O comando gem acompanhado do parâmetro list apresentará o nome e as versões de todas as gems de seu sistema. No momento que esse artigo é escrito, a versão mais atualizada do framework é a 2.3.5. Caso sua versão do Rails esteja defasada, faça a atualização para a última versão através do comando:
sudo gem update rails
Lembre-se que a atualização da gem só poderá ser realizada caso o comando seja executado como usuário administrador, por isso o comando gem é antecedido de sudo. O comando sudo em sistemas operacionais derivados do Unix faz com que seja exigido do usuário a senha de administrador para que o comando seja executado. No ambiente Windows, o comando sudo não é necessário.
Desenvolvimento
Nosso desenvolvimento começa com a criação da estrutura básica dos arquivos do projeto e com a configuração das informações de banco de dados. Na janela do terminal, execute:
rails lojadelivros -d mysql
O comando rails recebe como parâmetro o nome do aplicativo que será criado e a opção d. Essa opção define o banco que será utilizado no aplicativo, no nosso caso o MySQL. A escolha do MySQL deve-se ao fato de ser um SGBD livre e compatível com diversos sistemas operacionais, além de contar com diversas ferramentas para administração.
O SQLite é o banco de dados padrão do Rails por ser mais rápido de configurar e utilizar, entretanto, é menos conhecido entre os desenvolvedores. Além disso, não é recomendada a sua utilização em servidores de produção.
Após a execução do comando rails, devemos configurar o arquivo database.yml e definir como será feita a conexão com o banco de dados. Este arquivo é escrito em formato yml, um formato semelhante ao padrão XML (Listagem 1).
development:
adapter: mysql
encoding: utf8
reconnect: false
database: lojadelivros01_development
pool: 5
username: root
password:
socket: /tmp/mysql.sock
test:
adapter: mysql
encoding: utf8
reconnect: false
database: lojadelivros01_test
pool: 5
username: root
password:
socket: /tmp/mysql.sock
production:
adapter: mysql
encoding: utf8
reconnect: false
database: lojadelivros01_production
pool: 5
username: root
password:
socket: /tmp/mysql.sock
A Listagem 1 apresenta o arquivo database.yml. Observe que são definidos três bancos de dados distintos, sendo um para desenvolvimento, outro para testes e outro para produção. Essa distinção existe para que não haja conflitos entre os dados envolvidos. Defina no arquivo as suas configurações de banco de dados e crie, no terminal, o banco de dados lojadelivros01_development. Esse é o banco de dados que será utilizado durante todo o minicurso.
mysqladmin -u root -p create lojadelivros01_development
Definido o banco de dados, nosso próximo passo é gerar a página de livros, que será nosso catálogo de produtos. Para criarmos a entidade Book (livro), executaremos o scaffold no terminal:
script/generate scaffold Book name:string description:
text price:float category_id:integer author_id:integer
A entidade Book possui os seguintes campos: name (nome do livro), description (descrição do livro), price (preço do livro), category_id (categoria do livro – chave estrangeira para a entidade Category, que será criada posteriormente) e author_id (autor do livro – chave estrangeira para a entidade Author, que também será criada posteriormente).
O recurso Scaffold do Rails pode ser traduzido para português como andaime, metaforicamente tem função parecida. Ele gera as páginas e métodos necessários para as operações CRUD (Create, Read, Update e Delete) de um objeto. Além disso, cria um arquivo de migration, que possui informações para modificar o banco de dados. Nesse caso, uma migration foi gerada com instruções para criação de uma tabela chamada books com os campos name, description, price, category_id e author_id, como mostra a Listagem 2.
class CreateBooks < ActiveRecord::Migration
def self.up
create_table :books do |t|
t.string :name
t.text :description
t.float :price
t.integer :category_id
t.integer :author_id
t.timestamps
end
end
def self.down
drop_table :books
end
end
Observe na Listagem 2 que a classe CreateBooks possui dois métodos: up e down. O método up cria a tabela books com os campos informados e o método down reverte o que foi realizado no método up, ou seja, a remoção da mesma. Além disso, o método up cria também timestamps (linha 10), que são dois campos de data que armazenam a data da criação do objeto (created_at) e a data de atualização do objeto (updated_at).
Para agilizar o desenvolvimento das aplicações, Ruby on Rails adota algumas convenções. Para cada entidade, a tabela será criada com o nome dessa entidade no plural. A chave primária sempre é chamada "id" e as chaves estrangeiras mostram o nome da entidade no singular acompanhadas de "_id". Veja o exemplo: A entidade Book possui uma tabela "books", com chave primária "id". O campo "author_id" é a chave estrangeira que representa o campo id da entidade Author.
As instruções realizadas no arquivo de migration só serão realizadas no banco de dados após a execução do comando:
rake db:migrate
Você verá que foi criada a tabela books. Em seguida, inicialize o servidor web com o comando:
script/server
Feito isso, abra o navegador e carregue o endereço: http://localhost:3000/books. O resultado é exibido na Figura 2.
A Figura 2 mostra a página da entidade Book. Essa página lista os registros do banco de dados – por hora ainda não existe nenhum – e apresenta um link para a criação de um novo registro – "New book". Todas essas páginas foram geradas pelo scaffold.
Uma das formas de povoar o banco de dados é através do cadastramento dos registros via browser, outra forma é através de uma migration. Para povoar o banco através de migration, execute no terminal o seguinte comando:
script/generate migration add_book_data
A execução do comando acima gera um arquivo na pasta db/migrate com o nome add_book_data.rb, acompanhado com o timestamp da execução do comando. Abra esse arquivo e digite o conteúdo da Listagem 3.
class AddBookData < ActiveRecord::Migration
def self.up
Book.create(:name => "Memórias de Brás Cubas", :description =>
"O romance é narrado por um defunto, que reconta a própria vida,
do fim para o começo, num relato marcado pela franqueza e ironia.", :price => 12.12)
Book.create(:name => "Harry Potter e a Pedra Filosofal",
:description => "O best-seller de maior sucesso na atualidade
conta como o garoto Harry Potter foi adotado pelos tios, após a
morte de seus pais. Aos 12 anos ele inicia-se na feitiçaria e torna-se um
símbolo entre os sobrenaturais que habitam este mundo paralelo.",
:price => 10.99)
Book.create(:name => "O Iluminado", :description => "Danny
Torrance não é um menino comum. Danny é capaz de ouvir pensamentos.
Ele pode transportar-se no tempo e olhar o passado e o futuro.
Danny é um iluminado. Maldição ou benção? A resposta pode estar
guardada na imponência assustadora do hotel Overlook.", :price => 19.90)
end
def self.down
Book.delete_all
end
end
Veja que o método up do arquivo da Listagem 3 cria três registros informando em cada um deles o nome do livro (name), a descrição (description) e o preço (price). Depois de modificar o arquivo, execute a migration:
rake:db:migrate
A Figura 3 mostra como ficam os primeiros registros de nossa loja, que foram criados através da migration add_book_data.rb.
Relacionamento entre as entidades
Criamos a entidade Book que é a classe principal de nossa livraria, mas além dela precisamos de duas outras entidades: Category e Author. Para a criação das duas entidades executaremos os scaffolds Category e Author, e posteriormente, executaremos as alterações no banco de dados:
script/generate scaffold Category name:string --skip-timestamps
script/generate scaffold Author name:string --skip-timestamps
rake db:migrate
Agora que já temos as duas entidades, precisamos estabelecer os relacionamentos entre elas. Esse relacionamento é estabelecido no model das entidades. Para isso, abra o model post.rb e veja as modificações desse arquivo na Listagem 4.
class Book < ActiveRecord::Base
belongs_to :category
belongs_to :author
end
Em nosso sistema, um livro pertence a uma categoria e a um autor. Esse relacionamento pode ser descrito através do método belongs_to. Ao utilizarmos esse método, o Rails estabelecerá no banco de dados o relacionamento entre os objetos book, category e author. Por outro lado, pode-se dizer que uma categoria possui um ou mais livros – como exposto na Listagem 5.
class Category < ActiveRecord::Base
has_many :books
end
O método has_many é utilizado para estabelecer relacionamentos do tipo 1-N, por exemplo, uma categoria possui um ou mais livros. É esse também o relacionamento usado na classe author.rb para indicar que um autor possui um ou mais livros, conforme apresenta a Listagem 6.
class Author < ActiveRecord::Base
has_many :books
end
Criados os relacionamentos entre as entidades, vamos alterar o formulário de criação/edição de um livro. Para isso criaremos um arquivo de partial dentro da pasta app/views/books, chamado _form.html.erb.
Partial é um recurso do Ruby on Rails que pode ser entendido como um template parcial. Você a utiliza para exibir um código comum a mais de uma página, evitando redundâncias em seu código. Todo arquivo de partial começa com o caractere "_".
Em seguida, abra os arquivos new.html.erb e edit.html.erb da view books e observe que eles possuem código comum. Essas partes em comum serão inseridas na partial _form.html.erb, como exibido na Listagem 7 (ler Nota DevMan 4).
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.label :price %><br />
<%= f.text_field :price %>
</p>
<p>
<%= f.label :category_id %><br />
<%= f.text_field :category_id %>
</p>
<p>
<%= f.label :author_id %><br />
<%= f.text_field :author_id %>
</p>
Substitua o trecho acima nas views edit.html.erb e new.html.erb pela chamada do método render:
<%= render :partial => "form", :locals => { :f => f } %>
As Listagens 8 e 9 mostram como ficam, respectivamente, as partials edit.html.erb e new.html.erb, após as alterações realizadas.
<h1>Editando livro</h1>
<% form_for(@book) do |f| %>
<%= render :partial => "form",
:locals => { :f => f } %>
<%= f.submit "Atualizar" %>
<% end %>
<%= link_to "Visualizar", @book %> |
<%= link_to "Voltar", books_path %>
<h1>Novo livro</h1>
<% form_for(@book) do |f| %>
<%= render :partial => "form", :locals => { :f => f } %>
<%= f.submit "Criar" %>
<% end %>
<%= link_to "Voltar", books_path %>
Na partial que acabamos de criar implementaremos nossa próxima funcionalidade, que tem a ver com o relacionamento entre book, category e author.
Atualmente, a partial _form.html.erb possui campos de texto onde indicamos o id da categoria e do autor. Substituiremos esses campos de texto por menus dropdown com os registros vindos do banco, de acordo com a Listagem 10.
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.label :price %><br />
<%= f.text_field :price %>
</p>
<p>
<%= f.label :category_id %><br/>
<%= f.collection_select :category_id, Category.find(:all),
:id, :name, :prompt => "Selecione" %>
</p>
<p>
<%= f.label :author_id %><br/>
<%= f.collection_select :author_id, Author.find(:all),
:id, :name, :prompt => "Selecione" %>
</p>
Os campos de texto das linhas 17 e 21 foram substituídos pelo método collection_select. Esse método criará um menu dropdown, onde as opções do menu serão povoadas com uma busca em todos os registros das tabelas categories e authors.
A Figura 4 mostra o resultado de nossa alteração. Como não temos nenhuma categoria cadastrada, o menu de opções encontra-se vazio. Para aprimorar ainda mais essa funcionalidade vamos criar dois campos de texto, para inserção de uma categoria e autor, de modo que possamos utilizá-los sempre que não encontrarmos a informação desejada. Para isso, acrescente o trecho da partial _form.html.erb exposto na Listagem 11.
<p>
<%= f.label :category_id %><br/>
<%= f.collection_select :category_id, Category.find(:all), :id, :name, :prompt => "Selecione" %>
<span class="help">ou crie um novo</span>
<%= f.text_field :new_category_name %>
</p>
<p>
<%= f.label :author_id %><br/>
<%= f.collection_select :author_id, Author.find(:all), :id, :name, :prompt => "Selecione" %>
<span class="help">ou crie um novo</span>
<%= f.text_field :new_author_name %>
</p>
Observe que existem nas linhas 19 e 25 dois campos de texto, chamados new_category_name e new_author_name. Esses campos precisam ser criados no modelo Book, para que possam ser usados na camada de visualização. Então, abra o model book.rb e insira em seu conteúdo:
attr_accessor :new_category_name, :new_author_name
O attr_accessor cria métodos de leitura e definição para os campos new_category_name e new_author_name. Ele tem a mesma função dos métodos getter e setter do Java. Com a alteração da partial e do model, nosso formulário ficará semelhante à Figura 5.
Com o nosso formulário pronto, criaremos no model Book.rb os métodos responsáveis por criar uma categoria e um autor, caso algum valor seja informado nos campos de texto correspondentes.
class Book < ActiveRecord::Base
belongs_to :category
belongs_to :author
attr_accessor :new_category_name, :new_author_name
before_save :create_category_from_name, :create_author_from_name
def create_category_from_name
create_category(:name => new_category_name) unless new_category_name.blank?
end
def create_author_from_name
create_author(:name => new_author_name) unless new_author_name.blank?
end
end
Observe na Listagem 12, linha 7: o método before_save indica os métodos que deverão ser executados antes que um novo livro seja salvo no banco de dados. Neste caso, serão executados os métodos create_category_from_name (linha 9) e create_author_from_name (linha 13).
O método create_category_from_name criará uma categoria caso o campo de texto new_category_name não esteja em branco. Caso o campo create_author_from_name não esteja em branco, um novo autor será criado, através da execução do método create_author_from_name.
Com essas alterações podemos, ao criar ou editar um livro, escolher ou criar um novo autor e categoria.
Layout
O scaffold do Rails gera para cada entidade um arquivo de layout na pasta app/views/layouts. Como geramos os scaffolds das entidades Book, Category e Author, essa pasta possui os arquivos book.html.erb, category.html.erb e author.html.erb.
Substituiremos todos esses arquivos de layout por apenas um, chamado application.html.erb. Assim, remova os três arquivos gerados pelo scaffold do Rails e crie o novo arquivo, cujo conteúdo é disposto na Listagem 13. Esse será o layout base de nosso aplicativo.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Minha loja de livros</title>
<%= stylesheet_link_tag "application" %>
</head>
<body>
<div id="body">
<div id="header">
<h1><a href="/">Minha loja de livros</a></h1>
</div>
<div id="menu">
<h3>Menu</h3>
</div>
<div id="content">
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</div>
</div>
</body>
</html>
...
Confira outros conteúdos:
Black November
Desconto exclusivo para as primeiras 200 matrículas!
Pagamento anual
12x no cartão
De: R$ 69,00
Por: R$ 54,90
Total: R$ 658,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- 12 meses de acesso
Pagamento recorrente
Cobrado mensalmente no cartão
De: R$ 79,00
Por: R$ 54,90 /mês
Total: R$ 658,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- Fidelidade de 12 meses
- Não compromete o limite do seu cartão
<Perguntas frequentes>
Nossos casos de sucesso
Eu sabia pouquíssimas coisas de programação antes de começar a estudar com vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa bagagem consegui um estágio logo no início do meu primeiro período na faculdade.
Estudo aqui na Dev desde o meio do ano passado!
Nesse período a Dev me ajudou a crescer muito aqui no trampo.
Fui o primeiro desenvolvedor contratado pela minha
empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um
Full-Stack Dev!
Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a pena, pois a plataforma é bem intuitiva e muuuuito didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito obrigado!
Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento front-end, tinha coisas que eu ainda não tinha visto. A didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado, adorando demais.
Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É um passo a passo incrível. Só não aprende quem não quer. Foi o melhor investimento da minha vida!
Foi um dos melhores investimentos que já fiz na vida e tenho aprendido bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da programação, irei assinar meu contrato como programador graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana, aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem como não aprender, estão de parabéns!
Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na área.
Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.