Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

30 May 07 Quatro dias de Ruby On Rails – Segundo dia

Quatro dias de Ruby On Rails – Primeiro dia

Seguindo com a tradução do tutorial, vamos ao segundo dia.

Para prosseguir alem do ponto onde ja chegamos, precisaremos olhar com maiores detalhes o que acontece por traz dos panos, principalmente o código gerado pelo scaffold.

Com a ação “scaffold :entidade” o rails gera o código necessário dinamicamente, mas podemos também gerar o código para que possamos ler e alterar …

ruby script/generate scaffold categoryexists  app/controllers/
exists  app/helpers/
create  app/views/categories
exists  app/views/layouts/
exists  test/functional/
dependency  model
exists    app/models/
exists    test/unit/
exists    test/fixtures/
identical    app/models/category.rb
identical    test/unit/category_test.rb
identical    test/fixtures/categories.yml
create  app/views/categories/_form.rhtml
create  app/views/categories/list.rhtml
create  app/views/categories/show.rhtml
create  app/views/categories/new.rhtml
create  app/views/categories/edit.rhtml
create  app/controllers/categories_controller.rb
identical  test/functional/categories_controller_test.rb
create  app/helpers/categories_helper.rb
create  app/views/layouts/categories.rhtml
identical  public/stylesheets/scaffold.css

Este escript gerou todo o código necessário para este controller.

Preste atenção na pequena diferença de nomenclatura, nos mudamos do singular para o plural, agora para acessar o controller acessaremos o endereço: http://localhost:3000/categories, na verdade é melhor remover o controller antigo para evitar confusões.

O código gerado pelo Scaffold

O controller

Vamos dar uma olhada no código do controller, o controller é o lugar para a implementação da lógica da aplicação. Ele interage com o usuário através das views e com o banco de dados utilizando os models. Você deve conseguir ler o código do controller e entender como a aplicação funciona.

O código gerado pelo scaffold deve parecer com o seguinte:

class CategoriesController < ApplicationControllerdef index
list
render :action => 'list'
end
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :o nly => [ :destroy, :create, :update ],
:redirect_to => { :action => :list }
def list
@category_pages, @categories = paginate :categories, :per_page => 10
end
def show
@category = Category.find(params[:id])
end
def new
@category = Category.new
end
def create
@category = Category.new(params[:category])
if @category.save
flash[:notice] = 'Category was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
def edit
@category = Category.find(params[:id])
end
def update
@category = Category.find(params[:id])
if @category.update_attributes(params[:category])
flash[:notice] = 'Category was successfully updated.'
redirect_to :action => 'show', :id => @category
else
render :action => 'edit'
end
end
def destroy
Category.find(params[:id]).destroy
redirect_to :action => 'list'
end
end

Quando o usuário de uma aplicação rails, por exemplo “show”, o controller vai executar o código na seção apropriada, neste caso “def show”, e depois por padrão vai rendrizar o controller de mesmo nome, neste caso “show.rhtml”, este comportamento padrão pode ser alterado com facilidade.

  • render :action, vai renderizar o template referente a outra action, por exemplo a ação “def index” vai executar o código do metodo list, e depois vai renderizar o template list.rhtml em vez do index.rhtml que não existe.
  • redirect_to, vai um passo adiante, e retorna um “302 moved” para o browser, e o redireciona para o metodo indicado do controller, alterando também a URL do browser.

Documentação: ActionController::Base

O controller utiliza metodos da classe ActiveRecord por exemplo new, save, find, find_all, update_attributes e destroy para mover os dados de e para o banco de dados, perceba que não é necessário escrever nenhum SQL, mas se você quiserver o SQL que o rails esta gerando, ele é escrito para o arquivo development.log.

Documentação: ActiveRecord::Base

Perceba também que uma ação lógica, pela perspectiva do usuário, pode requerer duas passagens pelo código do controller, por exemplo quando um usuário seleciona “Edit” o controller busca os dados do banco e renderiza o template “edit.rhtml” e quando o usuário finaliza a edição, o metodo update é chamado, que por sua vez atualiza o model e renderiza a ação show.

A View

Views são o que utilizamos para definir a interface com o usuário. O Rails pode renderizar o HTML final apresentado para o usuário utilizando 3 componentes.

Layout Templates Partial
em app\views\layouts, padrão application.rhtml, ou <controller>.rhtml em app\views\<controller>, padrão <action>.rhtml em app\views\<controller>, padrão _<partial>.rhtml
  • Um layout prove código comum a todas as actions, normalmente o inicio e o fim do HTML.
  • Um template prove o código especifico da action, por exemplo o código especifico para o “edit” ou “list”.
  • Um Partial prove código comum, utilizado em diversas actions, como por exemplo uma tabela para o layout de um form.

Layout

Padrões de nomenclatura do Rails: se existir no diretório app\views\layouts, um arquivo com o mesmo nome do controller.rhtml este é utilizado por padrão, a não ser que outro seja configurado manualmente.

Sempre existe um arquivo de nome application.rhtml que é utilizado caso o layout do controller não seja encontrado, e nenhum outro seja configurado manualmente.

O código gerado para o layout no arquivo categories.rhtml é parecido com o seguinte:

<!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>Categories: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<p style="color: green"><%= flash[:notice] %></p><%= yield  %>
</body></html>

A maior parte é HTML simples, mais algumas poucas entradas de código ruby entre <% e %>, Este layout sera utilizado no processo padrão de renderização, e contem o HTML padrão para todas as páginas. O código Ruby do template sera traduzido para HTML em tempo de execução.

  • <% controller.action_name %> inclui o nome da action sendo executada no titulo, por exemplo “List”
  • <% stylesheet_link_tag %> é um helper, uma maneira fácil de gerar código HTML, existem dúzias de helpers no rails, este gera apenas uma tag <link href=”/stylesheets/scaffold.css” media=”screen” rel=”Stylesheet” type=”text/css”/>
  • <% yeld %> é a chave para o que acontece depois, ele insere o código gerado pela action executada neste ponto do HTML.

Template

Padrões de nomenclatura do Rails: templates ficam no diretório apps\controller\`action`.rhtml

o código para o new.rhtml gerado pelo scaffold parece com o seguinte:

<h1>New category</h1>
<% form_tag :action => 'create' do %>
<%= render :partial => 'form' %>
<%= submit_tag "Create" %>
<% end %>
<%= link_to 'Back', :action => 'list' %>
  • <% form_tag %> vai gerar uma tag <form> com a action correta para a ação especificada do controller, no caso “create”
  • <%= render :partial %> vai renerizar o código do partial especificado
  • <% submit_tag %> vai gerar um <input type=”submit”> com o texto especificado
  • <% link_to %> simplesmente cria um link para a action especificada

Partial

Padrão de nomenclatura do Rails: o partial “foo” vai estar em app/`controller`/_foo.rhtml, preste atenção no _ inicial.

O “scaffold” utiliza o mesmo código de formulário para processar o formulário de create e edit, o código dele se parece com o seguinte:

<%= error_messages_for 'category' %>
<!--[form:category]-->
<p><label for="category_category">Category</label><br/>
<%= text_field 'category', 'category'  %></p>
<p><label for="category_created_on">Created on</label><br/>
<%= datetime_select 'category', 'created_on'  %></p>
<p><label for="category_updated_on">Updated on</label><br/>
<%= datetime_select 'category', 'updated_on'  %></p>
<!--[eoform:category]-->
  • <% error_messages_for %> renderiza um texto com markup HTML se algum erro foi detectado em um envio anterior do formulário, o HTML gerado parece com o seguinte:
    <div class="errorExplanation" id="errorExplanation">
    <h2>n errors prohibited this xxx from being saved</h2>
    <p>There were problems with the following fields:</p>
    <ul>
    <li>field_1 error_message_1</li>
    <li>... ...</li>
    <li>field_n error_message_n</li>
    </ul>
    </div>

    Nos vimos o erro em ação no primeiro di, na seção capturando erros, perceba as classes css que podem ser utilizadas para alterar o estilo.

  • <% text_field %> é um helper do rails que gera um <input type=”text”> para o campo especificado
  • <% datetime_select %> é outro helper que gera um conjunto de campos select para a entrada de datas

As páginas para edição e visualização são similares a de criação, ja a página de listagem possui alguns pequenos truques.
O controler executa o seguinte código para popular a listagem:

@category_pages, @categories = paginate :category, :per_page => 10

o comando “paginate” popula uma lista ordenada com “per_page” registros por vez, e contem toda a lógica de paginação.
neste caso a coleção @catetory_pages é uma instancia da classe Paginator.

vamos ver como ficou o template para esta ação:

<h1>Listing categories</h1>
<table>
  <tr>
  <% for column in Category.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
  </tr>
<% for category in @categories %>
  <tr>
  <% for column in Category.content_columns %>
    <td><%=h category.send(column.name) %></td>
  <% end %>
    <td><%= link_to 'Show', :action => 'show', :id => category %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => category %></td>
    <td><%= link_to 'Destroy', { :action => 'destroy', :id => category }, :confirm => 'Are you sure?', :method => :post %></td>
  </tr>
<% end %>
</table>
<%= link_to 'Previous page', { :page => @category_pages.current.previous } if @category_pages.current.previous %>
<%= link_to 'Next page', { :page => @category_pages.current.next } if @category_pages.current.next %>
<br />
<%= link_to 'New category', :action => 'new' %>
  • content_columns – retorna a lista de todas as colunas simples, excluindo IDs e relacionamentos
  • human_name – é uma função que retorna um nome mais legivel para um atributo, por exemplo first_name vai ser First name
  • h – faz o escape automático de caracteres HTML
  • confirm – é uma opção para o comando link_to que abre um confirm em javascript antes de seguir o link

Melhorando um pouco o código gerado
O Controller:

  def list
    @category_pages, @categories = paginate :categories, :per_page => 10, :o rder_by => "category"
  end

Para que a lista ja venha ordenada

Bom, por enquanto é isto, no proximo “Dia” com o Rails, vamos adicionar os cadastros de notas e itens, e brincar um pouco com os helpers do Rails.

Tudo pronto? então siga para o Terceiro dia.

PS.: agradeço se os leitores que estão gostando do tutorial colocarem links em seus blogs para o tutorial, indicando para seus amigos.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Tags: ,

Reader's Comments

  1. |

    Urubatan, você que é o Cara em Java, me diz uma coisa, eu trabalho com JSF, tenho vários clientes que utilizam aplições que desenvolvi em Java, e vendo todo esse aue em torno de Ruby me preocupa o fato de eu ter me especiazado em Java, será que devo me preocupar em estudar logo outra linguagem ou deve continuar firme e forte no java.? grato, Anderson.

  2. |

    Aprender mais uma linguagem é sempre vantagem, mas se a tua preocupação é se alguma coisa vai ser descontinuada, não esquenta a cabeça …
    Ruby, e o Rails são alternativas para desenvolver alguns tipos de aplicações …
    Algumas aplicações que são escritas em Java poderiam ter sido desenvolvidas com RoR, outras seria problemático tentar escrever com RoR.
    mas o Java tem vida longa ainda :D

    o ideal é conhecer diversas opções para poder escolher qual a melhor para cada caso …

    Por exemplo este blog utiliza o wordpress que é uma aplicação escrita em PHP, mas esta rodando em uma implementação de PHP em Java, em um Tomcat.
    é possivel fazer a mesma coisa com o RoR …

    mas como eu disse antes, cada caso é um caso …

  3. |

    sessão ou seção? Que eu saiba, rails não suporta o conceito de sessão como no HttpSession do Java…

  4. |

    sorry, erro meu, neste caso é seção (de parte do código)

    mas Bla, o Rails suporta sim um conceito parecido com HttpSession do java, e é bem fácil de utilizar …
    Vamos ver isto no “Dia 4″, mas para colocar qualquer coisa no sessão do usuário no Rails basta executar um código parecido com:

    @session[:item_id] = @params[:id]
    
  5. |

    Olá amigo. Estou gostando bastante deste tutorial. Gostaria de saber se o material referente ao terceiro dia já se encontra disponível. Abraço!

  6. |

    ta quase pronto, só não esta pronto ainda por que depois que formatei o meu note, eu fiquei com preguiça de escrever :D
    Vou ver se consigo terminar hoje ou amanha :D

  7. |

    Olá Urubatan,

    vejo que você possui um bom conhecimento em RoR.
    Cara estou com um problema e ainda não encontrei uma solução boa,
    encontrei parte dela. Bom o problema é o seguinte tem um link remote
    que renderiza numa div um partial e dentro desse partial preciso
    fazer uma paginação, porém não tem como eu passar por um controller
    pois estou usando um esquema generalizado de chamadas remotas.
    Gostaria de saber se tem como fazer o paginate no partial(.rhtml),
    é que estou tentando fazer aqui e não da certo.
    Se você tiver alguma solução para ajudar ficarei grato.

    att