terça-feira, 19 de abril de 2011

Ajax no Rails 3

    Era para eu falar neste post sobre teste de controller com RSpec, mas estava fazendo alguns testes com Ajax, então aproveitei o momento para falar de Ajax. Desculpe a demora por novos posts, estava em período de entrega de trabalhos e provas na faculdade, não deu tempo de preparar nada. Todos os códigos que faço aqui estão no Github(github.com/vagnerzampieri/zblog).
    Pegue aquele CRUD que fizemos sobre Post, ele vai ser modificado e dará lugar a documentos com extensão '.js.erb'. A ideia é que todas as ações fiquem na index, sendo assim, ficará um carregamento mais rápido e uma página mais dinâmica.
    Primeiro coloque a gem 'jquery-rails' no arquivo Gemfile da sua aplicação. A versão que estou usando está com o jquery 1.5.
        gem 'jquery-rails', '0.2.7'
    Logo em seguida, vá em um terminal e rode o 'bundle install'. Agora rode no terminal 'rails generate jquery:install', ele irá substtuir o prototype pelo jquery.
    Primeiro, vamos começar modificando a criação de post. Ele vai ficar da seguinte forma, ao clicar no link 'New' irá carregar abaixo um formulário, ao ser preenchido e enviado irá aparecer na lista o item que foi criado.
    Na index, vou modificar a tabela e colocar um id, esse id irá servir depois para identificar aonde irá adicionar na lista o post que for criado.
        posts/index.html.erb:
       
        <table id="posts">
       
    Crie um partial que irá virar uma lista dinâmica, já que será muito utilizada no ajax:
        posts/_post.html.erb:
       
        <tr id="post_<%= post.id %>">
          <td><%= post.title %></td>
          <td><%= truncate post.body, :length => 20 %></td>
          <td><%= post.publication.strftime "%Y-%m-%d %H:%M:%S" %></td>
          <td><%= post.enabled %></td>
          <td><%= link_to 'Show', post, :remote => true %></td>
          <td><%= link_to 'Edit', edit_post_path(post), :remote => true %></td>
          <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete, :remote => true %></td>
        </tr>
       
    Note que coloquei um id dinâmico no 'tr', e nos liks adicionei ':remote => true' é ele que irá fazer a mágica no Ajax, coloque ele também no 'form'.
        <%= simple_form_for(@post, :remote => true) do |f| %>
   
    Na index coloque um render para esse partial.
        posts/index.html.erb:
       
        <% @posts.each do |post| %> 
          <%= render post%>
        <% end %>
       
    Adicione também o link 'New' um pouco abaixo:
        <%= link_to 'New', '/posts/new', :remote => true %>
       
    E uma div onde será chamado o formulário:
        <div id="form">
        </div>
       
    Crie um arquivo 'new.js.erb' e dentro dele coloque o código abaixo:
   
        $('#form').empty();
        $("#form").append("<%= escape_javascript(render(:partial => "form"))%>");
       
    Esse código é bem simples, a primeira linha vai deixar vazio a div 'form', por um simples motivo, se você não colocar essa linha sempre que clicar em um botão ele vai criar um novo elemento em vez de excluir o antigo. A segunda linha chama o partial do 'form'. Crie um arquivo 'create.js.erb' e adicione o código abaixo:
   
        $('#posts').append('<%= escape_javascript(render(@post)) %>');
        $("#new_post")[0].reset();
       
    A primeira linha chama o partial 'post' que nós criamos e adiciona mais um elemento na lista. A segunda limpa o formulário para poder ocorrer mais um cadastro. Para finalisar, melhore o controller assim:
        def create
          @post = Post.new params[:post]

          flash[:notice] = 'Post was successfully created.' if @post.save
          respond_with @post
        end
    
    Agora o 'Show', mais acima irá notar que o link para o 'Show' já fi criado. Adicione a div abaixo na index, ela será o guia que utilizaremos para a aparição do show.
       
        <div id="show"> 
        </div>
       
    Crie um arquivo 'show.js.erb' e adicione o código abaixo:
       
        $('#show').empty();
        $('#show').append('<h2>Show post</h2><p><b>Title: </b><%= @post.title %></p><p><b>Body: </b><%= @post.body %></p><p><b>Publication: </b><%= @post.publication.strftime "%Y-%m-%d %H:%M:%S" %></p><p><b>Enabled: </b><%= @post.enabled %></p>');
   
    Como acontece no 'New' a primeira linha é para limpar se existir algo antes. A segunda irá exibir o item ao ser clicado, o append vai exibir tudo que estiver dentro dele. O próximo é o destroy, é o mais simples de todos, crie o arquivo 'destroy.js.erb' e adicione:
   
        $('#post_<%= @post.id %>').remove();
       
    Vai remover a linha exata que você destruir. O último é editar, é bem parecido que o criar, crie os arquivos 'edit.js.erb' e 'update.js.erb':
        posts/edit.js.erb:
       
        $('#form').empty();
        $("#form").append("<%= escape_javascript(render(:partial => "form"))%>")
       
    Mesma explicação do 'New'.
   
        posts/update.js.erb:
       
        $("#post_<%= @post.id %>").replaceWith("<%= escape_javascript(render(:partial => @post)) %>");
        <% @post = Post.new %>
        $(".simple_form").replaceWith("<%= escape_javascript(render(:partial => "form"))%>")
       
    Primeira linha, vai adicionar o elemento criado na lista. Segundo e terceira linha, vai resetar a variável de instância para ao editar o formulário, se modifique de edição para criação. Deixe o método update no controller da forma abaixo:
   
        def update
          @post = Post.find params[:id]

          flash[:notice] = 'Post was successfully updated.' if @post.update_attributes params[:post]
          respond_with @post
        end
       
    Pode apagar agora os arquivos abaixo, as suas funcionalidades não serão mais necessárias já que foram migradas.
        new.html.erb
        edit.html.erb
        show.html.erb
   
    Chega por hoje, ainda não pensei em um próximo post, talvez um banco de imagem com mais brincadeiras com Ajax.
    Até a próxima!!

3 comentários:

  1. E como seria tratado os erros de possíveis validações no modelo? Outra coisa a mensagem (flash) não é mostrada.

    ResponderExcluir
  2. tenho que pegar esse código e dar uma revisa então, faz muito tempo que não mexo nele, não poderia te responder sem dar essa revisada ... vou tentar fazer isso o mais rápido possível e postar uma revisão.

    ResponderExcluir
  3. Olá Vagner primeiramente quero parabenizar pelo series de tutorias fantástico muito difícil encontrar material passo a passo. Porém tem alguns etapa que não vai mais pra frente.

    ResponderExcluir