Por que eu devo ler este artigo:A partir dessa edição é dado início a uma nova série de artigos. Agora, você poderá criar sua própria loja virtual e trabalhar com venda de produtos pela Internet. Neste primeiro artigo apresentaremos as funcionalidades que serão desenvolvidas no aplicativo e daremos início à criação do catálogo de produtos. No artigo desta edição definiremos a base da nossa loja virtual, configurando o ambiente da aplicação, e em seguida criaremos o catálogo de produtos. Esta série de artigos possibilitará o aprendizado do Ruby on Rails na prática.

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.

Resultado final da loja virtual
Figura 1. Resultado final da loja virtual

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:

O que é Gem?: Gem, ou gema – quando traduzido – é como uma biblioteca do Ruby é empacotada e distribuída. Essas bibliotecas podem ser instaladas e gerenciadas via terminal, através do comando gem.

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.

Nota: O banco de dados SQLite é uma biblioteca C que implementa um banco de dados SQL embutido. Ele lê e escreve dados diretamente no disco.

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
Listagem 1. Arquivo database.yml

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
Listagem 2. Migration CreateBooks

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).

Convenções do Rails

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.

Página da entidade Book
Figura 2. Página da entidade Book

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
Listagem 3. Migration add_book_data

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.

Página da entidade Book com nossos primeiros registros
Figura 3. Página da entidade Book com nossos primeiros registros

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
Listagem 4. Arquivo app/models/book.rb

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
Listagem 5. Arquivo app/models/category.rb

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
Listagem 6. Arquivo app/models/author.rb

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.

O que é partial?:

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>
Listagem 7. Partial app/views/books/_form.html.erb

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 %>
Listagem 8. View app/views/books/edit.html.erb

<h1>Novo livro</h1>
 
<% form_for(@book) do |f| %>
  <%= render :partial => "form", :locals => { :f => f } %>
 
  <%= f.submit "Criar" %>
<% end %>
 
<%= link_to "Voltar", books_path %>
Listagem 9. View app/views/books/edit.html.erb

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>
Listagem 10. Partial app/views/books/_form.html.erb

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.

Partial _form.html.erb
Figura 4. Partial _form.html.erb

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>
Listagem 11. Partial app/views/books/_form.html.erb

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.

Partial _form.html.erb
Figura 5. Partial _form.html.erb

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
Listagem 12. Model book.rb

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> ... 

Quer ler esse conteúdo completo? Tenha acesso completo