42
Aprendendo Ruby on Rails - Aula 3 Maurício Linhares

Curso de Ruby on Rails - Aula 03

Embed Size (px)

DESCRIPTION

Material do curso de Ruby on Rails.

Citation preview

Page 1: Curso de Ruby on Rails - Aula 03

Aprendendo Ruby on Rails - Aula 3

Maurício Linhares

Page 2: Curso de Ruby on Rails - Aula 03

partials – reorganizando as views }  Quando uma view cresce demais ou tem pedaços que

podem ser reutilizados em outros lugares, esses pedaços podem ser transformados em um “partial”;

}  Partials são arquivos de view onde o nome começa com um “_” (underline) como em “_items.html.erb”;

}  É possível passar variáveis para partials e eles também tem acesso a todas as variáveis de instância que estejam nas views;

2

Page 3: Curso de Ruby on Rails - Aula 03

app/views/items/_item.html.erb <tr> <td> <%= item.nome %> </td> <td> <%= item.quantidade %> </td> <td> <%= number_to_currency item.preco_unitario %> </td> <td> <%= number_to_currency item.preco_total %> </td> </tr>

3

Page 4: Curso de Ruby on Rails - Aula 03

Fazendo a chamada do partial – app/views/itens/index.html.erb <table> <thead> <tr> <td> Nome </td> <td> Quantidade </td> <td> Preço unitário </td> <td> Preço total </td> </tr> </thead> <tbody> <% pedido_atual.itens.each do |item| %> <%= render 'item', :item => item %> <% end %> </tbody> </table>

4

Page 5: Curso de Ruby on Rails - Aula 03

<%= render ‘ item‘, :item => item %> }  Gere o partial “_item” dentro da pasta da view atual;

}  Passe a variável item com o nome “:item” para o partial;

}  Quando o caminho completo não for dado, o partial vai ser sempre procurado na pasta de view do controller atual;

}  render :partial => “items/item”, :locals => { :item => item }

5

Page 6: Curso de Ruby on Rails - Aula 03

Alterando vários itens ao mesmo tempo no carrinho – formulários aninhados

}  A solução mais simples pra editar vários elementos ao mesmo tempo em uma página;

}  Rails tem suporte direto a formulários aninhados dentro do framework;

}  Para usar formulários aninhados (para os objetos relacionados a outro) nós utilizamos o helper “accepts_nested_attributes_for”;

6

Page 7: Curso de Ruby on Rails - Aula 03

Na classe Pedido class Pedido < ActiveRecord::Base has_many :itens accepts_nested_attributes_for :itens #resto dos métodos end

7

Page 8: Curso de Ruby on Rails - Aula 03

Formulário no carrinho <%= form_tag atualizar_carrinho_itens_path, :method => :post do %> <table> <thead> <tr> <td> Nome </td> <td> Quantidade </td> <td> Preço unitário </td> <td> Preço total </td> </tr> </thead> <tbody> <% pedido_atual.itens.each do |item| %> <%= render 'item', :item => item %> <% end %> </tbody> </table> <% end %>

8

Page 9: Curso de Ruby on Rails - Aula 03

Adicionando campo de formulário ao _item.html.erb

9

<tr> <td><%= item.produto.nome %></td> <td> <%= hidden_field_tag 'pedido[itens_attributes][][id]', item.id %> <%= text_field_tag 'pedido[itens_attributes][][quantidade]', item.quantidade %> </td> <td><%= number_to_currency item.produto.preco %></td> <td><%= number_to_currency item.preco_total %></td> </tr>

Page 10: Curso de Ruby on Rails - Aula 03

Formato do formulário para itens aninhados

10

}  'pedido[itens_attributes][][id]’ }  Cada item deve vir com o seu próprio id, para que o item

correto seja atualizado;

}  'pedido[itens_attributes][][quantidade]’ }  Junto do ID vem o atributo (ou os atributos) que você deseja

alterar;

}  Veja que entre o [itens_attributes] e [id] existe um “[]”, esse par de colchetes serve pra definir que você está alterando um array de itens;

Page 11: Curso de Ruby on Rails - Aula 03

Formato do formulário que está sendo enviado para o controller

11

}  "pedido"=> }  {"itens_attributes"=>[

}  {"id"=>"1","quantidade"=>"5"}, }  {"id"=>"2","quantidade"=>"4"}, }  {"id"=>"3","quantidade"=>"8”}

}  ]}

Page 12: Curso de Ruby on Rails - Aula 03

Adicionando uma nova rota

12

}  map.resources :itens, :collection => { :atualizar_carrinho => :post }

}  Ações do tipo “collection” são definidas quando você vai chamar um método do controller que não afeta um recurso em específico, a URL gerada seria “/itens/atualizar_carrinho”;

}  A outra opção seria usar ações do tipo “member”, que afetam recursos específicos, a URL gerada seria “/itens/nome_da_acao/1”

Page 13: Curso de Ruby on Rails - Aula 03

Implementando o controller

13

def atualizar_carrinho pedido_atual.update_attributes( params[:pedido] ) respond_to do |format| format.html do flash[:success] = 'Carrinho de compras atualizado com sucesso' redirect_to itens_path end end end

Page 14: Curso de Ruby on Rails - Aula 03

Removendo itens que tenham a quantidade menor do que 1

14

}  O ActiveRecord define vários hooks (“ganchos”) onde você pode executar código durante o ciclo de vida de um objeto: }  before_validation }  before_validation_on_create }  validate_on_create }  after_validation }  after_validation_on_create }  before_save }  before_create }  after_create }  after_save

Page 15: Curso de Ruby on Rails - Aula 03

Ganchos do ActiveRecord

15

}  Esses ganchos podem ser utilizados para executar código nas suas classes, como fazer cache de valores, preencher os objetos com dados padrão;

}  Você pode definir vários métodos para um mesmo gancho, todos eles são executados na sequência em que foram definidos;

}  Quando um método retorna “false”, ele pára a execução de todos os ganchos que vem após ele;

Page 16: Curso de Ruby on Rails - Aula 03

Implementando um gancho

16

class Pedido < ActiveRecord::Base has_many :itens, :dependent => :destroy accepts_nested_attributes_for :itens after_save :remover_itens_zerados # resto do código protected def remover_itens_zerados zerados = self.itens.find_all { |item| item.quantidade.to_i < 1 } self.itens.delete( *zerados ) end end

Page 17: Curso de Ruby on Rails - Aula 03

self.itens.delete( *args ) – métodos encontrados em associações

17

}  itens.delete – remove objetos da associação (apagando ele do banco se o :dependent for :destroy ou :delete_all)

}  itens(true) – atualiza a coleção pra os valores mais atuais no banco

}  itens.item_ids – traz os ids dos objetos associados

}  itens.find – faz uma consulta no banco apenas nos objetos que fazem parte da associação

}  Outros métodos em -> http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

Page 18: Curso de Ruby on Rails - Aula 03

Montando a administração do site

18

}  Vive em um caminho/namespace separado do site principal (como em “/admin”);

}  Normalmente precisa de um controle de acesso mais complexo, liberando apenas para usuários que sejam administradores;

}  Também precisa de um layout específico pra ela, em vez de usar o layout comum do site;

Page 19: Curso de Ruby on Rails - Aula 03

Criando o controller base da administraçào

19

class Admin::BaseController < ApplicationController layout 'administracao' end

Page 20: Curso de Ruby on Rails - Aula 03

Pastas

20

}  O arquivo do controller deve ser base_controller.rb e deve ser criado dentro da pasta “app/controllers/admin”;

}  Quando um controller tem um namespace ( Admin::BaseController ), a pasta onde ele fica deve representar o mesmo caminho do namespace dele;

}  O nome final do arquivo é o nome do controller SEM o namespace;

Page 21: Curso de Ruby on Rails - Aula 03

Criando o controller base da administração

21

}  No controller fazemos a uma chamada ao método “layout” e passamos como parâmetro a string “administracao”;

}  Isso define que o controller Admin::BaseController não vai mais utilizar o layout “application.html.erb” mas sim o “administracao.html.erb”;

}  Cada controller pode definir o seu próprio layout base com a chamada do método “layout”;

Page 22: Curso de Ruby on Rails - Aula 03

Configurando as rotas com namespace

22

namespace :admin do resources :produtos end

Page 23: Curso de Ruby on Rails - Aula 03

rake routes | grep admin

23

}  admin_produtos GET /admin/produtos }  POST /admin/produtos }  new_admin_produto GET /admin/produtos/new }  edit_admin_produto GET /admin/produtos/:id/edit }  admin_produto GET admin/produtos/:id }  PUT /admin/produtos/:id }  DELETE /admin/produtos/:id

Page 24: Curso de Ruby on Rails - Aula 03

Instalando a gem de paginação

24

}  Instalando a gem }  gem install will_paginate

}  Configurando ela no environment.rb }  config.gem “will_paginate”

Page 25: Curso de Ruby on Rails - Aula 03

Adicionando métodos de paginação em ApplicationController

25

class ApplicationController < ActionController::Base #outros métodos protected def load_page @page = params[:page] || 1 @per_page = params[:per_page] || 10 end def paginate( scope, options = {} ) load_page scope.paginate( :page => @page, :per_page => @per_page ) end end

Page 26: Curso de Ruby on Rails - Aula 03

Métodos básicos - admin/produtos_controller.rb

26

class Admin::ProdutosController < Admin::BaseController before_filter :load_produto, :only => [ :new, :edit, :create, :update, :destroy ] #mais código aqui protected def load_produto @produto = params[:id].blank? ? Produto.new : Produto.find( params[:id] ) end def ir_para_listagem( mensagem ) respond_to do |format| format.html do flash[:success] = mensagem redirect_to admin_produtos_path end end end end

Page 27: Curso de Ruby on Rails - Aula 03

before_filter

27

}  Define métodos a serem executados antes da ação do controller ser executada;

}  Normalmente são utilizados para transformar dados da sessão em variáveis para o controller ou validar se a requisição é válida ou não;

}  Podem ser aplicados a todos os métodos de um controller ou apenas a alguns com :only e :except;

Page 28: Curso de Ruby on Rails - Aula 03

Criando e editando produtos – admin/produtos_controller.rb

28

def new respond_to do |format| format.html do render :new end end end alias :edit :new def create if @produto.update_attributes( params[:produto] ) ir_para_listagem( 'Produto criado/atualizado com sucesso' ) else new end end alias :update :create

Page 29: Curso de Ruby on Rails - Aula 03

alias

29

}  alias :edit :new }  Crie um método “edit” que aponte para o método “new”

}  Simplifica a definição de controllers, já que os métodos “new” e “edit” fazem a mesma coisa;

}  O funcionamento é o mesmo para “create” e “update”, os métodos fazem a mesma coisa, então definir um alias é mais prático;

Page 30: Curso de Ruby on Rails - Aula 03

Listando e removendo produtos – admin/produtos_controller.rb

30

def index @produtos = paginate( Produto ) respond_to do |format| format.html end end def destroy @produto.destroy ir_para_listagem( 'Produto removido com sucesso' ) end

Page 31: Curso de Ruby on Rails - Aula 03

Preparando a listagem de produtos da administração – admin/produtos/index

31

<% unless @produtos.blank? %> <%= will_paginate @produtos %> <table> <%= cabecalho_de_tabela 'Nome', 'Preço', 'Ações' %> <tbody> <%= render @produtos %> </tbody> </table> <%= will_paginate @produtos %> <% else %> <p> Não há produtos cadastrados no sistema. </p> <% end %>

Page 32: Curso de Ruby on Rails - Aula 03

Definindo um método em application_helper.rb

32

module ApplicationHelper def cabecalho_de_tabela( *nomes ) colunas = nomes.map { |nome| "<th>#{nome}</th>" } linha = content_tag( :tr, colunas.join("\n").html_safe ) content_tag( :thead, linha ).html_safe end end

Page 33: Curso de Ruby on Rails - Aula 03

Definindo um método em application_helper.rb

33

}  Métodos definidos em quaisquer arquivos dentro da pasta helper estão disponíveis por padrão em todas as views da sua aplicação;

}  Você deve agrupar os métodos em helpers dependendo da funcionalidade que implementam ou modelo sobre o qual interagem;

}  Não defina todos os seus métodos em application_helper.rb, crie outros arquivos de helper para organizar o seu código J

Page 34: Curso de Ruby on Rails - Aula 03

<%= will_paginate @produtos %>

34

}  O método de views will_paginate vai gerar na sua view um controle de paginação com os números de páginas e os botões anterior e próximo;

}  O parâmetro que ele recebe é uma coleção que tenha sido retornada através de um método paginate em um dos seus models, uma coleção normal não vai ser aceita;

}  Você pode personalizar as mensagens ou o HTML gerado através de opções passadas para esse método;

Page 35: Curso de Ruby on Rails - Aula 03

<%= render @produtos %>

35

}  Atalho para gerar uma lista de objetos que compartilham o mesmo partial;

}  No caso do exemplo, é equivalente a fazer: <% @produtos.each do |produto| %> <%= render “admin/produtos/produto”, :produto => produto %> <% end %> }  O caminho do partial a ser buscado vai ser sempre

“caminho_atual/nome_da_classe_no_singular”

Page 36: Curso de Ruby on Rails - Aula 03

Linha de produto – admin/produtos/_produto.html.erb

36

<tr> <td> <%= produto.nome %> </td> <td> <%= number_to_currency produto.preco %> </td> <td> <%= link_to 'Editar', edit_admin_produto_path(produto) %> | <%= link_to 'Remover’, admin_produto_path(produto), :method => :delete, :confirm => 'Tem certeza de que deseja remover este produto?' %> </td> </tr>

Page 37: Curso de Ruby on Rails - Aula 03

link_to - :method => :delete

37

}  Links em HTML geram, por padrão, uma requisição do tipo GET, mas no nosso caso precisamos que um link gere uma requisição do tipo :delete;

}  O Rails oferece uma opção chamada :method para links para que eles possam executar chamadas a outros métodos HTTP;

}  Além disso também é possível usar a opção :confirm para validar se o usuário quer realmente efetuar aquela ação;

Page 38: Curso de Ruby on Rails - Aula 03

Criando um helper para simplificar o formulário de produtos

38

module Admin::ProdutosHelper def admin_form_for_produto( &block ) opcoes = if @produto.new_record? [admin_produtos_path, :post] else [admin_produto_path( @produto ), :put] end form_for( @produto, :url => opcoes.first, :html => { :method => opcoes.last }, &block ) end end

Page 39: Curso de Ruby on Rails - Aula 03

RESTful forms

39

}  Formulários em Rails seguem a padronização RESTful que as rotas para os métodos definem;

}  Para criar um novo produto, é necessário um POST em “/admin/produtos”, para editar um produto é necessário um PUT em “/admin/produtos/ID”;

}  O método admin_form_for_produto usa o método new_record? de Produto para saber se ele está criando um novo ou editando um produto existente;

Page 40: Curso de Ruby on Rails - Aula 03

Formulário de criação/edição de produtos

40

<%= admin_form_for_produto do |f| %> <%= error_messages_for @produto %> <p> Nome: <br/> <%= f.text_field :nome %> </p> <p> Preço: <br/> <%= f.text_field :preco %> </p> <p> Descrição: <br/> <%= f.text_area :descricao %> </p> <p> <%= submit_tag 'Enviar' %> </p> <% end %>

Page 41: Curso de Ruby on Rails - Aula 03

Implementando o helper para mostrar os erros

41

module ApplicationHelper def error_messages_for( object, title = 'Foram encontrados erros nos seus dados' ) if object render 'compartilhados/erros', :title => title, :errors => object.errors.full_messages end end end

Page 42: Curso de Ruby on Rails - Aula 03

E o HTML – app/views/compartilhados/_erros.html.erb

42

<div class="alert-message block-message error"> <a class="close" href="#">&times;</a> <p><strong> <%= title %> </strong></p> <ul> <% errors.each do |error| %> <li><%= error %></li> <% end %> </ul> </div>