Forums » Ruby

Capítulo 9 - Controllers e Views

    • 467 posts
    23 de julho de 2013 01:51:24 ART

    Capítulo 9

    Controllers e Views


    "A Inteligência é quase inútil para quem não tem mais nada"

    Nesse capítulo, você vai aprender o que são controllers e como utilizá-los para o benefício do seu projeto, além de aprender a trabalhar com a camada visual de sua aplicação.

     

    9.1 - O "V" e o "C" do MVC

    O "V" de MVC representa a parte de view (visualização) da nossa aplicação, sendo ela quem tem contato com o usuário, recebe as entradas e mostra qualquer tipo de saída.

    Há diversas maneiras de controlar as views, sendo a mais comum delas feita através dos arquivos HTML.ERB, ou eRuby (Embedded Ruby), páginas HTML que podem receber trechos de código em Ruby.

    Controllers são classes que recebem uma ação de uma View e executam algum tipo de lógica ligada a um ou mais modelos. Em Rails esses controllers estendem a classe ApplicationController.

    As urls do servidor são mapeadas da seguinte maneira: /controller/action/id. Onde "controller" representa uma classe controladora e "action" representa um método do mesmo. "id" é um parâmetro qualquer (opcional).

     

    9.2 - Hello World

    Antes de tudo criaremos um controller que mostrará um "Hello World" para entender melhor como funciona essa ideia do mapeamento de urls.

    Vamos usar o generator do rails para criar um novo controller que se chamará"HelloWorld". Veja que o Rails não gera apenas o Controller, mas também outros arquivos.

     

    Apos habilitar o rota padrão do rails tente acessar a páginahttp://localhost:3000/hello_world

    Na URL acima passamos apenas o controller sem nenhuma action, por isso recebemos uma mensagem de erro.

     

    Além de não dizer qual a action na URL, não escrevemos nenhuma action no controller.

    Criaremos um método chamado hello no qual escreveremos na saída do cliente a frase "Hello World!". Cada método criado no controller é uma action, que pode ser acessada através de um browser.

    Para escrever na saída, o Rails oferece o comando render, que recebe uma opção chamada "text" (String). Tudo aquilo que for passado por esta chave será recebido no browser do cliente.

    Seus livros de tecnologia parecem do século passado?

     

    Conheça a Casa do Código, uma nova editora, com autores de destaque no mercado, foco em ebooks (PDF, epub, mobi), preçosimbatíveis e assuntos atuais.
    Com a curadoria da Caelum e excelentes autores, é uma abordagem diferente para livros de tecnologia no Brasil. Conheça os títulos e a nova proposta, você vai gostar.

    Casa do Código, livros para o programador.

     

    9.3 - Exercícios: Criando o controlador

    1. Vamos criar um controller para nossos restaurantes:
      1. Abra o Terminal.
      2. Execute rails generate controller restaurantes
    2. Mais tarde esse controller irá mediar todas as interações relacionadas à restaurantes. Agora ele irá simplesmente renderizar um HTML com o texto "Estou no controller de restaurantes!" envolvido por um parágrafo.
      1. Crie um arquivo HTML para o index: app/views/restaurantes/index.html.erb
      2. Como conteúdo do arquivo digite:
        1. <p>
        2.  Estou no controller de Restaurantes!
        3. </p>
    3.  
      1. Abra seu novo controller (app/controllers/restaurantes_controller.rb)
      2. Inclua a action index:
        1. def index
        2.   render "index"
        3. end
    4. Vamos habilitar as rotas padrões para restaurantes:
      1. Abra o arquivo config/routes.rb.
      2. Dentro do bloco de código adicione a linha:
        1. resources :restaurantes
    5.  
      1. O último passo antes de testar no browser é iniciar o server.
      2. Execute no Terminal: rails server
      3. Confira o link http://localhost:3000/restaurantes.


    9.4 - Trabalhando com a View: O ERB

    ERB

    ERB é uma implementação de eRuby que já acompanha a linguagem Ruby. Seu funcionamento é similar ao dos arquivos JSP/ASP: arquivos html com injeções de código. A ideia é que o HTML serve como um template, e outros elementos são dinamicamente inseridos em tempo de renderização.

     

    sintaxe básica

    Para uma página aceitar código Ruby, ela deve estar entre "<%" e "%>". Há uma variação deste operador, o "<%=", que não só executa códigos Ruby, mas também imprime o resultado na página HTML.

    Logo, o seguinte código ERB:

    <html>

     <body>

     <p>Meu nome é: <%= "João" %></p>

     <p>Não vai imprimir nada ao lado: <% "Não será impresso" %></p>

     </body>

    </html>

    Irá resultar em:

    <html>

      <body>

        <p>Meu nome é: João</p>

        <p>Não vai imprimir nada ao lado: </p>

      </body>

    </html>

     

    if, else e blocos

    O operador "<%" é muito útil quando precisamos que um pedaço de HTML seja adicionado com uma condição. Por exemplo:

    <body>

    <% if nomes.empty? %>

     <div class="popup">

     Nenhum nome

     </div>

    <% else %>

     <div class="listagem">

    <%= nomes %>

     </div>

    <% end %>

    </body>

    Caso a variável nomes seja igual à [], o resultado será:

    <body>

        <div class="popup">

          Nenhum nome

        </div>

    </body>

    Por outro lado, se nomes for igual à ["João", "Maria"] o resultado será:

    <body>

        <div class="listagem">

          ["João", "Maria"]

        </div>

    </body>

    Podemos ainda iterar pelos nomes imprimindo-os em uma lista, basta mudar o ERB para:

    <body>

    <% if nomes.empty? %>

     <div class="popup">

     Nenhum nome

     </div>

    <% else %>

     <ul class="listagem">

    <% nomes.each do |nome| %>

     <li><%= nome %></li>

    <% end %>

     </ul>

    <% end %>

    </body>

    Para nomes igual à ["João", "Maria"] o resultado seria:

    <body>

        <ul class="listagem">

            <li><%= João %></li>

            <li><%= Maria %></li>

        </ul>

    </body>

     

    Do controller para view

    É importante notar que todos os atributos de instância (@variavel) de um controlador estão disponíveis em sua view. Além disso, ela deve ter o mesmo nome da action, e estar na pasta com o nome do controlador o que significa que a view da nossa action index do controlador restaurantes_controller.rb deve estar em: app/views/restaurantes/index.html.erb.

     

    9.5 - Entendendo melhor o CRUD

    Agora, queremos ser capazes de criar, exibir, editar e remover restaurantes. Como fazer?

    Primeiro, temos de criar um controller para nosso restaurante. Pela view Generators, vamos criar um controller para restaurante. Rails, por padrão, utiliza-se de sete actions "CRUD". São eles:

    • index: exibe todos os items
    • show: exibe um item específico
    • new: formulário para a criação de um novo item
    • create: cria um novo item
    • edit: formulário para edição de um item
    • update: atualiza um item existente
    • destroy: remove um item existente

    Agora é a melhor hora de aprender algo novo

     

    Se você gosta de estudar essa apostila aberta da Caelum, certamente vai gostar dos novos cursos online que lançamos na plataforma Alura. Você estuda a qualquer momento com aqualidade Caelum.

    Conheça a assinatura semestral.

     

    9.6 - A action index

    Desejamos listar todos os restaurantes do nosso Banco de Dados, e portanto criaremos a action index.

    Assim como no console buscamos todos os restaurantes do banco de dados com o comando find, também podemos fazê-lo em controllers (que poderão ser acessados pelas nossas views, como veremos mais adiante).

    Basta agora passar o resultado da busca para uma variável:

    def index

      @restaurantes = Restaurante.order :nome

    end

    Com a action pronta, precisamos criar a view que irá utilizar a variável@restaurantes para gerar o HTML com a listagem de restaurantes:

    <table>

     <tr>

     <th>Nome</th>

     <th>Endereço</th>

     <th>Especialidade</th>

     </tr>

    <% @restaurantes.each do |restaurante| %>

     <tr>

     <td><%= restaurante.nome          %></td>

     <td><%= restaurante.endereco      %></td>

     <td><%= restaurante.especialidade %></td>

     </tr>

    <% end %>

    </table>

    De acordo com a convenção, esta view deve estar no arquivo:app/views/restaurantes/index.html.erb.

    Agora, basta acessar nossa nova página através da URL:http://localhost:3000/restaurantes/.

     

    9.7 - Exercícios: Listagem de restaurantes

    Vamos agora criar uma forma do usuário visualizar uma listagem com todos os restaurantes:

    1. Gere um controller para o modelo restaurante:
      1. Vá ao Terminal;
      2. Execute rails generate controller restaurantes
    2.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action index:
        1. def index
        2.   @restaurantes = Restaurante.order :nome
        3. end
    3.  
      1. Vamos criar também o arquivo ERB (app/views/restaurantes/index.html.erb) que servirá de base para a página HTML.
        1. <h1>Listagem de Restaurantes</h1>
        2.  
        3. <table>
        4.  <tr>
        5.  <th>ID</th>
        6.  <th>Nome</th>
        7.  <th>Endereço</th>
        8.  <th>Especialidade</th>
        9.  </tr>
        10.  
        11. <% @restaurantes.each do |restaurante| %>
        12.  <tr>
        13.  <td><%= restaurante.id %></td>
        14.  <td><%= restaurante.nome %></td>
        15.  <td><%= restaurante.endereco %></td>
        16.  <td><%= restaurante.especialidade %></td>
        17.  </tr>
        18. <% end %>
        19. </table>
    4.  
      1. Teste agora entrando em: http://localhost:3000/restaurantes (Não esqueça de iniciar o servidor)
      2. É possível que não tenhamos nenhum restaurante em nossa base de dados, nesse caso, vamos usar um pouco do poder de ruby para rapidamente criar alguns restaurantes via console (rails console):
        1. especialidades = %w{massas japonês vegetariano}
        2. 50.times do |i|
        3.   Restaurante.create!(
        4.     nome: "Restaurante #{i}",
        5.     endereco: "Rua #{i} de setembro",
        6.     especialidade: especialidades.sample
        7.   )
        8. end


    9.8 - Helper

    Helpers são módulos que disponibilizam métodos para serem usados em nossas views. Eles provêm atalhos para os códigos mais usados e nos poupam de escrever muito código. O propósito de um helper é simplificar suas views.

     

    Helpers padrões

    O Rails já nos disponibiliza uma série de helpers padrões, por exemplo, se quisermos criar um link, podemos usar o helper link_to:

    <%= link_to "Restaurantes", controller: "restaurantes", action: "index" %>

    Abaixo, uma lista com alguns helpers padrões:

    • link_to (âncora)
    • image_tag (img)
    • favicon_link_tag (link para favicon)
    • stylesheet_link_tag (link para CSS)
    • javascript_include_tag (script)

    Helper Method

    Existe também o chamado helper_method, que permite que um método de seu controlador vire um Helper e esteja disponível na view para ser chamado. Exemplo:

    class TesteController < ApplicationController

      helper_method :teste

     

      def teste

        "algum conteudo dinâmico"

      end

    end

    E em alguma das views deste controlador:

    <%= teste %>

    Você pode também fazer o curso RR-71 dessa apostila na Caelum

     

    Querendo aprender ainda mais sobre a linguagem Ruby e o framework Ruby on Rails? Esclarecer dúvidas dos exercícios? Ouvir explicações detalhadas com um instrutor?
    A Caelum oferece o curso RR-71 presencial nas cidades de São Paulo, Rio de Janeiro e Brasília, além de turmas incompany.

    Consulte as vantagens do curso Desenv. Ágil para Web com Ruby on Rails.


    9.9 - A action show

    Para exibir um restaurante específico, precisamos saber qual restaurante buscar. Pela convenção, poderíamos visualizar o restaurante de id 1 acessando a URL: http://localhost:3000/restaurantes/1. Logo, o id do restaurante que buscamos deve ser passado na URL.

    Ou seja, o caminho para a action show é: /restaurantes/:id. A action show receberá um parâmetro :id ao ser evocada. E esse id será utilizado na busca pelo restaurante:

    def show

      @restaurante = Restaurante.find(params[:id])

    end

    Após criar a action, devemos criar a view que irá descrever um restaurante:

    <h1>Exibindo Restaurante</h1>

     

    Nome: <%= @restaurante.nome %>

    Endereço: <%= @restaurante.endereco %>

    Especialidade: <%= @restaurante.especialidade %>

    Agora, basta acessar nossa nova página através da URL:http://localhost:3000/restaurantes/id-do-restaurante.


    9.10 - Exercícios: Visualizando um restaurante

    1.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action show:
        1. def show
        2.   @restaurante = Restaurante.find(params[:id])
        3. end
    2. Vamos criar também o arquivo ERB (app/views/restaurantes/show.html.erb).
      1. <h1>Exibindo Restaurante</h1>
      2.  
      3. <p>
      4.  <b>Nome: </b>
      5. <%= @restaurante.nome %>
      6. </p>
      7.  
      8. <p>
      9.  <b>Endereço: </b>
      10. <%= @restaurante.endereco %>
      11. </p>
      12.  
      13. <p>
      14.  <b>Especialidade: </b>
      15. <%= @restaurante.especialidade %>
      16. </p>
    3. Vamos agora usar o helper de âncora (link_to) para criar o link que tornará possível visualizar um restaurante apartir da listagem de restaurantes.
      1. Abra a view de index (app/views/restaurantes/index.html.erb).
      2. Vamos adicionar um link Mostrar ao lado de cada restaurante, que irá direcionar o usuário para o show do restaurante. Para isso, vamos substituir esse código:
        1. <% @restaurantes.each do |restaurante| %>
        2.  <tr>
        3.  <td><%= restaurante.nome %></td>
        4.  <td><%= restaurante.endereco %></td>
        5.  <td><%= restaurante.especialidade %></td>
        6.  </tr>
        7. <% end %>

    Por esse:

    <% @restaurantes.each do |restaurante| %>

     <tr>

     <td><%= restaurante.nome %></td>

     <td><%= restaurante.endereco %></td>

     <td><%= restaurante.especialidade %></td>

     <td>

    <%= link_to 'Mostrar', action: 'show', id: restaurante %>

     </td>

     </tr>

    <% end %>

    1. Teste clicando no link Mostrar de algum restaurante na listagem de restaurantes (http://localhost:3000/restaurantes).


    9.11 - A action destroy

    Para remover um restaurante, o usuário enviará uma requisição à nossa actiondestroy passando no id da url o id do restaurante a ser excluído:

    def destroy

      @restaurante = Restaurante.find(params[:id])

      @restaurante.destroy

    end

    Observe que a action destroy não tem intenção de mostrar nenhuma informação para o usuário. Por isso, após finalizar seu trabalho, ela irá chamar a index. Abaixo iremos entender melhor o mecanismo que iremos utilizar para implementar isso.

    Tire suas dúvidas no novo GUJ Respostas

     

    O GUJ é um dos principais fóruns brasileiros de computação e o maior em português sobre Java. A nova versão do GUJ é baseada em uma ferramenta de perguntas e respostas (QA) e tem uma comunidade muito forte. São mais de 150 mil usuários pra ajudar você a esclarecer suas dúvidas.

    Faça sua pergunta.


    9.12 - Redirecionamento de Action

    Dentro de uma action, podemos redirecionar a saída para uma outra action.

    Por exemplo, se tivermos um controller qualquer com duas actions podemos utilizar o método redirect_to para que o usuário seja redirecionado para aaction1 no momento que ele acessar a action2:

    class ExemploController < ApplicationController

      def action1

        render text: "ACTION 1!!!"

      end

     

      def action2

        redirect_to action: 'action1'

      end

    end

    Dessa forma, é possível que uma action exerça sua responsabilidade e depois delegue o final do processo para alguma outra action.

    Imagine no nosso controller de restaurantes, por exemplo. Criamos uma action para apagar um restaurante, porém o que acontecerá após o restaurante ser deletado?

    Faz sentido que o usuário volte para a página de index, para obtermos esse comportamento utilizaremos do redirect_to:

    def index

      @restaurantes = Restaurante.all

    end

     

    def destroy

      # código que deleta o restaurante

     

      redirect_to action: 'index'

    end

    Redirecionamento no servidor e no cliente

    O redirecionamento no servidor é conhecido como forward e a requisição é apenas repassada a um outro recurso (página, controlador) que fica responsável em tratar a requisição.

    Há uma outra forma que é o redirecionamento no cliente (redirect). Nesta modalidade, o servidor responde a requisição original com um pedido de redirecionamento, fazendo com que o navegador dispare uma nova requisição para o novo endereço. Neste caso, a barra de endereços do navegador muda.


    9.13 - Exercícios: Deletando um restaurante

    1.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action destroy:
        1. def destroy
        2.   @restaurante = Restaurante.find(params[:id])
        3.   @restaurante.destroy
        4.  
        5.   redirect_to(action: "index")
        6. end
    2.  
      1. Abra a view de index (app/views/restaurantes/index.html.erb).
      2. Vamos adicionar um link Deletar ao lado de cada restaurante, que irá invocar a action destroy:
        1. <!-- Deve ficar abaixo do td que criamos para o link "Mostrar" -->
        2. <td>
        3. <%= link_to 'Deletar', {action: 'destroy', id: restaurante},
        4.                          {method: "delete"}  %>
        5. </td>
    3. Teste clicando no link Deletar de algum restaurante na listagem de restaurantes (http://localhost:3000/restaurantes).


    9.14 - Helpers para formulários

    Quando trabalhamos com formulários, usamos os chamados FormHelpers, que são módulos especialmente projetados para nos ajudar nessa tarefa. TodoFormHelper está associado a um ActiveRecord. Existem também osFormTagHelpers, que contém um _tag em seu nome. FormTagHelpers, não estão necessariamente associados a ActiveRecord algum.

    Abaixo, uma lista dos FormHelpers disponíveis:

    • check_box
    • fields_for
    • file_field
    • form_for
    • hidden_field
    • label
    • password_field
    • radio_button
    • text_area
    • text_field

    E uma lista dos FormTagHelpers:

    • check_box_tag
    • field_set_tag
    • file_field_tag
    • form_tag
    • hidden_field_tag
    • image_submit_tag
    • password_field_tag
    • radio_button_tag
    • select_tag
    • submit_tag
    • text_area_tag
    • text_field_tag

    Agora, podemos escrever nossa view:

    <%= form_tag :action => 'create' do %>

     Nome: <%= text_field :restaurante, :nome %>

     Endereço: <%= text_field :restaurante, :endereco %>

     Especialidade: <%= text_field :restaurante, :especialidade %>

    <%= submit_tag 'Criar' %>

    <% end %>

    Este ERB irá renderizar um HTML parecido com:

    <form action="/restaurantes" method="POST">

      Nome: <input type="text" name="restaurante[nome]">

      Endereço: <input type="text" name="restaurante[endereco]">

      Especialidade: <input type="text" name="restaurante[especialidade]">

      <input type="submit">

    <% end %>

    Repare que como utilizamos o form_tag, que não está associado a nenhum ActiveRecord, nosso outro Helper text_field não sabe qual o ActiveRecord que estamos trabalhando, sendo necessário passar para cada um deles o parâmetro:restaurante, informando-o.

    Podemos reescrever mais uma vez utilizando o FormHelper form_for, que está associado a um ActiveRecord:

    <%= form_for @restaurante do |f| %>

     Nome: <%= f.text_field :nome %>

     Endereço: <%= f.text_field :endereco %>

     Especialidade: <%= f.text_field :especialidade %>

    <%= f.submit %>

    <% end %>

    Repare agora que não foi preciso declarar o nome do nosso modelo para cadatext_field, uma vez que nosso Helper form_for já está associado a ele.

    Nova editora Casa do Código com livros de uma forma diferente

     

    Editoras tradicionais pouco ligam para ebooks e novas tecnologias. Não conhecem programação para revisar os livros tecnicamente a fundo. Não têm anos de experiência em didáticas com cursos.
    Conheça a Casa do Código, uma editora diferente, com curadoria da Caelume obsessão por livros de qualidade a preços justos.

    Casa do Código, ebook com preço de ebook.


    9.15 - A action new

    Para incluir um novo restaurante, precisamos primeiro retornar ao browser um restaurante novo, sem informação alguma. Vamos criar nossa action new

    def new

     @restaurante = Restaurante.new

    end


    9.16 - Exercícios: Página para criação de um novo restaurante

    1.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action new:
        1. def new
        2.   @restaurante = Restaurante.new
        3. end
    2.  
      1. Vamos criar também o arquivo ERB (app/views/restaurantes/new.html.erb).
        1. <h1>Adicionando Restaurante</h1>
        2.  
        3. <%= form_for @restaurante do |f| %>
        4.  Nome: <%= f.text_field :nome %><br/>
        5.  Endereço: <%= f.text_field :endereco %><br/>
        6.  Especialidade: <%= f.text_field :especialidade %><br/>
        7. <%= f.submit %>
        8. <% end %>
    3.  
      1. Abra a view de index (app/views/restaurantes/index.html.erb).
      2. Vamos adicionar um link Novo para direcionar o usuário para a action new. Diferente dos outros links que criamos, esse deverá ser inserido abaixo da lista de restaurantes:
        1. <!-- lista de restaurantes -->
        2.  
        3. <br/>
        4. <%= link_to 'Novo', action: 'new' %>
    4. Teste clicando no link Novo na listagem de restaurantes (http://localhost:3000/restaurantes).


    9.17 - Recebendo um parâmetro por um formulário

    Não são raros os momentos onde precisamos que o usuário digite informações que utilizaremos no lado do servidor. Para isso utilizamos formulários como:

    <form action='/restaurantes'>

     Nome: <input type='text' name='nome'/>

     <input type='submit' value='Create'/>

    </form>

    Porém, como teremos acesso ao texto digitado pelo usuário? Toda informação introduzida em um formulário, é passada para o controller como um parâmetro. Logo, para receber este valor nome no controlador, basta usar o hash params. (Repare que agora usamos outra action, create, para buscar os dados do formulário apresentado anteriormente):

    class RestaurantesController < ApplicationController

      def create

        nome = params[:nome]

      end

    end

    Porém essa não é a action create dos restaurantes, precisamos de algo mais completo.

     

    Recebendo parâmetros ao utilizar o helper form_for

    Diferente do exemplo anterior, nossa view new.html.erb utiliza o helper form_forpara representar o formulário de um restaurante, da seguinte maneira:

    <%= form_for @restaurante do |f| %>

     Nome: <%= f.text_field :nome %><br/>

     Endereço: <%= f.text_field :endereco %><br/>

     Especialidade: <%= f.text_field :especialidade %><br/>

    <%= f.submit %>

    <% end %>

    Ao utilizar o helper form_for o Rails irá agrupar os parâmetros desse formulário na chave :restaurante. Logo, é possível imprimir cada um dos parâmetros da seguinte maneira:

    def create

      puts params[:restaurante][:nome]

      puts params[:restaurante][:endereco]

      puts params[:restaurante][:especialidade]

    end

    Porém, imprimir os parâmetros não é suficiente para persistir um restaurante.

    Já conhece os cursos online Alura?

     

    Alura oferece dezenas de cursos online em sua plataforma exclusiva de ensino que favorece o aprendizado com aqualidade reconhecida da Caelum. Você pode escolher um curso nas áreas de Java, Ruby, Web, Mobile, .NET e outros, ou fazer a assinatura semestral que dá acesso a todos os cursos.

    Conheça os cursos online da Caelum.


    9.18 - A action create

    O agrupamento de parâmetros mostrado anteriormente combina perfeitamente com a hash aceita pelas classes do ActiveRecord, por isso podemos criar um novo restaurante da seguinte maneira:

    Restaurante.new params[:restaurante]

    Não faz sentido que criemos um novo restaurante sem persisti-lo. Vamos criar uma variável e utilizá-la em seguida para salvá-lo:

    def create

      @restaurante = Restaurante.new params[:restaurante]

      @restaurante.save

    end


    9.19 - Exercícios: Persistindo um restaurante

    1.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action create:
        1. def create
        2.   @restaurante = Restaurante.new(params[:restaurante])
        3.   @restaurante.save
        4.   redirect_to(action: "show", id: @restaurante)
        5. end


    9.20 - A action edit

    Para editar um restaurante, devemos retornar ao browser o restaurante que se quer editar, para só depois salvar as alterações feitas:

    def edit

      @restaurante = Restaurante.find(params[:id])

    end

    A view de edit.html.erb terá o mesmo formulário utilizado na viewnew.html.erb:

    <%= form_for @restaurante do |f| %>

     Nome: <%= f.text_field :nome %><br/>

     Endereço: <%= f.text_field :endereco %><br/>

     Especialidade: <%= f.text_field :especialidade %><br/>

    <%= f.submit %>

    <% end %>

    Perceba que ao editar, é usual que o usuário possa ver as informações atuais do restaurante. Para isso, não precisaremos fazer nada pois o helper form_for irá se encarregar de restaurar os dados do restaurante no formulário.

    Após implementar a action e a view, podemos acessar o formulário de edição acessando a URL: http://localhost:3000/restaurantes/id-do-restaurante/edit.

    Você não está nessa página a toa

     

    Você chegou aqui porque a Caelum é referência nacional em cursos de Java, Ruby, Agile, Mobile, Web e .NET.
    Faça curso com quem escreveu essa apostila.

    Consulte as vantagens do curso Desenv. Ágil para Web com Ruby on Rails.


    9.21 - A action update

    Uma vez que o usuário tenha atualizado as informações do restaurante e deseje salvá-las, enviará uma requisição à nossa action update passando o id do restaurante a ser editado na url, bem como os novos dados do restaurante.

    A hash params terá uma estrutura parecida com:

    {

      id: 1,

      restaurante: {

        nome: "Comidubom",

        endereco: "Rua da boa",

        especialidade: "massas"

      }

    }

    Logo, podemos implementar nosso update da seguinte maneira:

    def update

      @restaurante = Restaurante.find params[:id]

      @restaurante.update_attributes params[:restaurante]

    end


    9.22 - Atualizando um restaurante

    Vamos implementar as actions e views envolvidas na atualização de um restaurante. Ao final, note como o processo de atualização tem várias semelhanças com o de criação.

    1.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action edit:
        1. def edit
        2.   @restaurante = Restaurante.find params[:id]
        3. end
    2.  
      1. Vamos criar também o arquivo ERB (app/views/restaurantes/edit.html.erb).
        1. <h1>Editando Restaurante</h1>
        2.  
        3. <%= form_for @restaurante do |f| %>
        4.  Nome: <%= f.text_field :nome %><br/>
        5.  Endereço: <%= f.text_field :endereco %><br/>
        6.  Especialidade: <%= f.text_field :especialidade %><br/>
        7. <%= f.submit %>
        8. <% end %>
    3.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Adicione a action update:
        1. def update
        2.   @restaurante = Restaurante.find(params[:id])
        3.   @restaurante.update_attributes(params[:restaurante])
        4.  
        5.   redirect_to action: "show", id: @restaurante
        6. end
    4.  
      1. Abra a view de index (app/views/restaurantes/index.html.erb).
      2. Vamos adicionar um link Editar ao lado de cada restaurante, que irá direcionar o usuário para a action edit:
        1. <!-- Deve ficar abaixo do td que criamos para o link "Deletar" -->
        2.  
        3. <td>
        4. <%= link_to 'Editar', action: 'edit', id: restaurante %>
        5. </td>
    5. Teste clicando no link Editar na listagem de restaurantes (http://localhost:3000/restaurantes).


    9.23 - Exercícios Opcionais: linkando melhor as views

    Até agora só criamos links na página que lista os restaurantes, como se fosse uma espécie de menu principal. Porém, na grande maioria dos casos, criamos links nas outras páginas também. Por exemplo, se o usuário estiver visualizando um restaurante, seria conveniente ele ter um link para poder voltar à listagem. Vamos criar esses links agora:

    1.  
      1. Abra o arquivo ERB da action new (app/views/restaurantes/new.html.erb).
      2. Adicione no final do ERB o seguinte link:
        1. <%= link_to 'Voltar', {action: 'index'} %>
    2.  
      1. Abra o arquivo ERB da action edit (app/views/restaurantes/edit.html.erb).
      2. Adicione no final do ERB o seguinte link:
        1. <%= link_to 'Voltar', action: 'index' %>
    3.  
      1. Abra o arquivo ERB da action show (app/views/restaurantes/show.html.erb).
      2. Adicione no final do ERB os seguintes links:
        1. <%= link_to 'Editar', action: 'edit', id: @restaurante %>
        2. <%= link_to 'Voltar', action: 'index' %>

    Seus livros de tecnologia parecem do século passado?

     

    Conheça a Casa do Código, uma nova editora, com autores de destaque no mercado, foco em ebooks (PDF, epub, mobi), preçosimbatíveis e assuntos atuais.
    Com a curadoria da Caelum e excelentes autores, é uma abordagem diferente para livros de tecnologia no Brasil. Conheça os títulos e a nova proposta, você vai gostar.

    Casa do Código, livros para o programador.


    9.24 - Mostrando erros ao usuário

    Desenvolvemos todas as actions e views necessárias para um CRUD de restaurante, porém não nos preocupamos de impedir que o usuário crie um restaurante inválido.

    Felizmente, as validações que fizemos no modelo já impedem que restaurantes inválidos sejam salvos. Porém, se testarmos, veremos que ao tentarmos criar um restaurante inválido veremos uma página de erro.

    Apesar de já estarmos protegidos contra o mau uso do sistema, nosso sistema responde de uma forma ofensiva, através de uma mensagem de erro.

     

    Usuário ter a oportunidade de tentar novamente

    Para resolver esse problema, mudaremos nossa action create para renderizar novamente o formulário caso um dado inválido esteja errado, dessa forma o usuário terá a oportunidade de corrigir os dados e enviá-los novamente.

    Inicialmente, poderíamos pensar em utilizar o método redirect_to, dessa forma:

    def create

      @restaurante = Restaurante.new params[:restaurante]

     

      if @restaurante.save

        redirect_to action: "show", id: @restaurante

      else

        redirect_to action: "new"

      end

    end

    Utilizando o redirect_to o usuário iria ver novamente o formulário caso digitasse dados inválidos, porém o formulário iria aparecer vazio e o usuário seria obrigado à digitar todas as informações novamente, ao invés de corrigir o erro. (Faça o teste)

    Para resolvermos isso, iremos utilizar o método render para fazer com que a action create reaproveite a view app/views/restaurantes/new.html.erb. Dessa forma:

    def create

      @restaurante = Restaurante.new params[:restaurante]

     

      if @restaurante.save

        redirect_to action: "show", id: @restaurante

      else

        render action: "new"

      end

    end

    A utilização do método render irá resultar em um formulário com os dados do restaurante, por que a view new.html.erb irá utilizar a variável @restaurante que foi criada na action create.

     

    Avisar ao usuário os erros que foram cometidos

    Apesar do usuário poder corrigir o erro, será difícil para ele enxergar sozinho que campos estão com erros.

    Por isso, iremos mudar a view new.html.erb para mostrar os erros ao usuário. É importante lembrarmos o método errors que retorna um objeto que representa os erros do restaurante em questão. Iremos utilizar também o método full_messagesque retorna uma array com as mensagens de erro.

    Na nossa view new.html.erb iremos criar uma <ul> e iterar pela array de mensagens encaixando elas criando uma <li> para cada mensagem:

    <ul>

    <% @restaurante.errors.full_messages.each do |msg| %>

     <li><%= msg %></li>

    <% end %>

    </ul>

    Feito isso, ficará fácil para o usuário tomar conhecimentos dos erros cometidos e consertá-los caso necessário.


    9.25 - Exercícios: Tratamento de erros na criação

    1. O usuário não pode salvar um restaurante inválido, porém não há nada que avise o usuário. Vamos alterar nossa página de forma que sejam mostrados os erros do restaurante logo acima do formulário.
      1. Abra a view do formulário de criação de um restaurante (app/views/restaurantes/new.html.erb).
      2. Adicione a lista de erros logo acima do formulário:
        1. <ul>
        2. <% @restaurante.errors.full_messages.each do |msg| %>
        3.  <li><%= msg %></li>
        4. <% end %>
        5. </ul>
        6.  
        7. <%= form_for @restaurante do |f| %>
        8. <!-- resto do HTML -->
    2. Vamos preparar o controller de restaurantes para quando a criação de um restaurante falhar nas validações. Nesse caso, ele deve renderizar o formulário de criação (new.html.erb) apartir do restaurante com erros:
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Altere a action create para:
        1. def create
        2.   @restaurante = Restaurante.new(params[:restaurante])
        3.   if @restaurante.save
        4.     redirect_to action: "show", id: @restaurante
        5.   else
        6.     render action: "new"
        7.   end
        8. end


    9.26 - Mensagens de erro na atualização

    Um problema parecido com o que experimentamos no momento da criação de um novo restaurante ocorrerá no processo de atualização de um restaurante. Para resolvê-lo, iremos alterar a action update para renderizar a view edit.html.erbcaso o usuário tenha entrado com dados inválidos. Em seguida adicionaremos a listagem de erros na view edit.html.erb assim como fizemos na new.html.erb.

     

    As alterações necessárias

    Assim como na action create, também utilizaremos o método render na actionupdate:

    def update

      @restaurante = Restaurante.find params[:id]

     

      if @restaurante.update_attributes(params[:restaurante])

        redirect_to action: "show", id: @restaurante

      else

        render action: "edit"

      end

    end

    Para mostrar os erros ocorridos, assim como tivemos que implementar na viewnew.html.erb, precisaremos inserir a lista de erros na view edit.html.erb:

    <ul>

    <% @restaurante.errors.full_messages.each do |msg| %>

     <li><%= msg %></li>

    <% end %>

    </ul>

     

    <%= form_for @restaurante do |f| %>

    <!-- resto do HTML -->

    Agora é a melhor hora de aprender algo novo

     

    Se você gosta de estudar essa apostila aberta da Caelum, certamente vai gostar dos novos cursos online que lançamos na plataforma Alura. Você estuda a qualquer momento com aqualidade Caelum.

    Conheça a assinatura semestral.


    9.27 - Exercícios: Tratamento de erros na atualização

    Assim como no formulário e action de criação, temos que preparar nossa aplicação para o caso de uma atualização de restaurante falhar em uma validação:

    1.  
      1. Abra a view do formulário de edição de um restaurante (app/views/restaurantes/edit.html.erb).
      2. Adicione a lista de erros logo acima do formulário:
        1. <ul>
        2. <% @restaurante.errors.full_messages.each do |msg| %>
        3.  <li><%= msg %></li>
        4. <% end %>
        5. </ul>
        6.  
        7. <%= form_for @restaurante do |f| %>
        8. <!-- resto do HTML -->
    2.  
      1. Abra o seu controller de Restaurantes (app/controllers/restaurantes_controllers.rb)
      2. Altere a action update para:
        1. def update
        2.   @restaurante = Restaurante.find(params[:id])
        3.  
        4.   if @restaurante.update_attributes(params[:restaurante])
        5.     redirect_to action: "show", id: @restaurante
        6.   else
        7.     render action: "edit"
        8.   end
        9. end
    3.  
      1. (Opcional) Quando o restaurante não tem erros, uma ul vazia é renderizada. Para evitar esse tipo de poluição, podemos envolver a <ul> com um if:
        1. <% if @restaurante.errors.any? %>
        2.  <!-- ul com erros aqui -->
        3. <% end %>
      2. (Opcional) Faça a mesma alteração do exercício acima na páginaapp/views/restaurantes/new.html.erb.


    9.28 - Partial

    Agora, suponha que eu queira exibir em cada página do restaurante um texto, por exemplo: "Controle de Restaurantes".

    Poderíamos escrever esse texto manualmente, mas vamos aproveitar essa necessidade para conhecer um pouco sobre Partials.

    Partials são fragmentos de html.erb que podem ser incluídas em uma view. Eles permitem que você reutilize sua lógica de visualização.

    Para criar um Partial, basta incluir um arquivo no seu diretório de views (app/views/restaurantes) com o seguinte nome: _meupartial. Repare que Partials devem obrigatoriamente começar com _.

    Para utilizar um Partial em uma view, basta acrescentar a seguinte linha no ponto que deseja fazer a inclusão:

    render partial: "meupartial"


    9.29 - Exercícios: Reaproveitando fragmentos de ERB

    1. Vamos criar um partial para reaproveitar o formulário que se repete nos templates new.html.erb e edit.html.erb:
      1. Crie o arquivo: app/views/restaurantes/_form.html.erb
      2. Coloque o seguinte conteúdo:
        1. <ul>
        2. <% @restaurante.errors.full_messages.each do |msg| %>
        3.  <li><%= msg %></li>
        4. <% end %>
        5. </ul>
        6.  
        7. <%= form_for @restaurante do |f| %>
        8.  Nome: <%= f.text_field :nome %><br/>
        9.  Endereço: <%= f.text_field :endereco %><br/>
        10.  Especialidade: <%= f.text_field :especialidade %><br/>
        11. <%= f.submit %>
        12. <% end %>
    2.  
      1. Abra a view new.html.erb. (app/views/restaurantes/new.html.erb)
      2. Substitua a lista de erros e o formulário por:
        1. <%= render partial: "form" %>
    3. Repita o processo acima com a view edit.html.erb.
    4. Teste novamente as actions new e edit acessandohttp://localhost:3000/restaurantes.

    Você pode também fazer o curso RR-71 dessa apostila na Caelum

     

    Querendo aprender ainda mais sobre a linguagem Ruby e o framework Ruby on Rails? Esclarecer dúvidas dos exercícios? Ouvir explicações detalhadas com um instrutor?
    A Caelum oferece o curso RR-71 presencial nas cidades de São Paulo, Rio de Janeiro e Brasília, além de turmas incompany.

    Consulte as vantagens do curso Desenv. Ágil para Web com Ruby on Rails.


    9.30 - Respondendo em outros formatos como XML ou JSON

    Um controlador pode ter diversos resultados. Em outras palavras, controladores podem responder de diversas maneiras, através do método respond_to:

    class RestaurantesController < ApplicationController

      def index

        @restaurantes = Restaurante.all

        respond_to do |format|

          format.html {render "index"}

          format.xml {render xml: @restaurantes}

        end

      end

    def

    Dessa forma, conseguimos definir uma lógica de resposta diferente para cada formato.

    Também é possível omitir o bloco de código:

    class RestaurantesController < ApplicationController

      def index

        @restaurantes = Restaurante.all

        respond_to do |format|

          format.html

          format.xml {render xml: @restaurantes}

        end

      end

    def

    Por convenção, quando o bloco de código é omitido o Rails vai uma view que atenda ao seguinte padrão:

    app/views/:controller/:action.:format.:handler

    No caso de omitirmos para o formato HTML, o Rails irá renderizar a view:app/views/restaurantes/index.html.erb


    9.31 - Para saber mais: Outros handlers

    O Rails já vem com suporte a outros handlers para geração de views. Além do ERB, podemos também usar o Builder.

    Builder é adequado quando a view a ser gerada é um arquivo XML, já que permite a criação de um xml usando sintaxe Ruby. Veja um exemplo:

    # app/views/authors/show.xml.builder

    xml.author do

      xml.name('Alexander Pope')

    end

    O xml resultante é:

    <author>

     <name>Alexander Pope</name>

    </author>

    Outra alternativa muito popular para a geração das views é o HAML:

    http://haml.hamptoncatlin.com

    #content

      .left.column

        %h2 Welcome to our site!

        %p= print_information

      .right.column= render partial: "sidebar"

    E o equivalente com ERB:

    <div id='content'>

     <div class='left column'>

     <h2>Welcome to our site!</h2>

     <p>

    <%= print_information %>

     </p>

     </div>

     <div class="right column">

    <%= render partial: "sidebar" %>

     </div>

    </div>


    9.32 - Exercícios: Disponibilizando restaurantes como XML e JSON

    1. Vamos deixar explícito que a action index do controller de restaurantes responder com html:
      1. Abra o controller de restaurantes. (app/controllers/restaurantes_controller.rb)
      2. Altere a action index para:
        1. def index
        2.   @restaurantes = Restaurante.order :nome
        3.  
        4.   respond_to do |format|
        5.     format.html
        6.   end
        7. end
    2. Agora que temos a forma explícita de declarar formatos de resposta, será simples capacitar a action index para responder com XML e JSON:
      1. Ainda no controller de restaurantes. (app/controllers/restaurantes_controller.rb)
      2. Altere a action index para:
        1. def index
        2.   @restaurantes = Restaurante.order :nome
        3.  
        4.   respond_to do |format|
        5.     format.html
        6.     format.xml {render xml: @restaurantes}
        7.     format.json {render json: @restaurantes}
        8.   end
        9. end
    3. Teste os novos formatos acessando as urls:
      1. http://localhost:3000/restaurantes.xml
      2. http://localhost:3000/restaurantes.json

    Tire suas dúvidas no novo GUJ Respostas

     

    O GUJ é um dos principais fóruns brasileiros de computação e o maior em português sobre Java. A nova versão do GUJ é baseada em uma ferramenta de perguntas e respostas (QA) e tem uma comunidade muito forte. São mais de 150 mil usuários pra ajudar você a esclarecer suas dúvidas.

    Faça sua pergunta.


    9.33 - Exercícios Opcionais: Outras actions respondendo XML e JSON

    Já ensinamos o controller de restaurantes a responder um conjunto de restaurantes. Vamos implementar para que ele conseguir responder com um JSON ou XML representando apenas um restaurante.

    1.  
      1. Abra o controller de restaurantes. (app/controllers/restaurantes_controller.rb)
      2. Altere a action show para:
        1. def show
        2.   @restaurante = Restaurante.find params[:id]
        3.  
        4.   respond_to do |format|
        5.     format.html
        6.     format.json {render json: @restaurante}
        7.     format.xml {render xml: @restaurante}
        8.   end
        9. end
    2. Para testar, procure pelo id de algum restaurante e acesse:http://localhost:3000/restaurantes/<id>.json.


    9.34 - Filtros

    O módulo ActionController::Filters define formas de executar código antes e depois de todas as actions.

    Para executar código antes das actions:

    class ClientesController < ApplicationController

      before_filter :verifica_login

     

      private

      def verifica_login

        redirect_to controller: 'login' unless usuario_logado?

      end

    end

    De forma análoga, podemos executar código no fim do tratamento da requisição:

    class ClientesController < ApplicationController

      after_filter :avisa_termino

     

      private

      def avisa_termino

        logger.info "Action #{params[:action]} terminada"

      end

    end

    Por fim, o mais poderoso de todos, que permite execução de código tanto antes, quanto depois da action a ser executada:

    class ClientesController < ApplicationController

      around_filter :envolvendo_actions

     

      private

      def envolvendo_actions

        logger.info "Antes de #{params[:action]}: #{Time.now}"

        yield

        logger.info "Depois de #{params[:action]}: #{Time.now}"

      end

    end

    Os filtros podem também ser definidos diretamente na declaração, através de blocos:

    class ClientesController < ApplicationController

      around_filter do |controller, action|

        logger.info "#{controller} antes: #{Time.now}"

        action.call

        logger.info "#{controller} depois: #{Time.now}"

      end

    end

    Caso não seja necessário aplicar os filtros a todas as actions, é possível usar as opções :except e :only:

    class ClientesController < ApplicationController

      before_filter :verifica_login, :only => [:create, :update]

     

      # ...

    end

    Logger

    As configurações do log podem ser feitas através do arquivoconfig/environment.rb, ou especificamente para cada environment nos arquivos da pasta config/environments. Entre as configurações que podem ser customizadas, estão qual nível de log deve ser exibido e para onde vai o log (stdout, arquivos, email, ...).

    Rails::Initializer.run do |config|

      # ...

      config.log_level = :debug

      config.log_path = 'log/debug.log'

      # ...

    end

    Mais detalhes sobre a customização do log podem ser encontrados no wiki oficial do Rails:

    http://wiki.rubyonrails.org/rails/show/HowtoConfigureLogging

     

     
    • 125842 posts
    • 125842 posts
    5 de novembro de 2020 12:57:02 ART
    http://audiobookkeeper.ru href="http://cottagenet.ru">http://cottagenet.ru href="http://eyesvision.ru">http://eyesvision.ru href="http://eyesvisions.com">http://eyesvisions.com href="http://factoringfee.ru">http://factoringfee.ru href="http://filmzones.ru">http://filmzones.ru href="http://gadwall.ru">http://gadwall.ru href="http://gaffertape.ru">http://gaffertape.ru href="http://gageboard.ru">http://gageboard.ru href="http://gagrule.ru">http://gagrule.ru href="http://gallduct.ru">http://gallduct.ru href="http://galvanometric.ru">http://galvanometric.ru href="http://gangforeman.ru">http://gangforeman.ru href="http://gangwayplatform.ru">http://gangwayplatform.ru href="http://garbagechute.ru">http://garbagechute.ru href="http://gardeningleave.ru">http://gardeningleave.ru href="http://gascautery.ru">http://gascautery.ru href="http://gashbucket.ru">http://gashbucket.ru href="http://gasreturn.ru">http://gasreturn.ru href="http://gatedsweep.ru">http://gatedsweep.ru href="http://gaugemodel.ru">http://gaugemodel.ru href="http://gaussianfilter.ru">http://gaussianfilter.ru href="http://gearpitchdiameter.ru">http://gearpitchdiameter.ru href="http://geartreating.ru">http://geartreating.ru http://generalizedanalysis.ru href="http://generalprovisions.ru">http://generalprovisions.ru href="http://geophysicalprobe.ru">http://geophysicalprobe.ru href="http://geriatricnurse.ru">http://geriatricnurse.ru href="http://getintoaflap.ru">http://getintoaflap.ru href="http://getthebounce.ru">http://getthebounce.ru href="http://habeascorpus.ru">http://habeascorpus.ru href="http://habituate.ru">http://habituate.ru href="http://hackedbolt.ru">http://hackedbolt.ru href="http://hackworker.ru">http://hackworker.ru href="http://hadronicannihilation.ru">http://hadronicannihilation.ru href="http://haemagglutinin.ru">http://haemagglutinin.ru href="http://hailsquall.ru">http://hailsquall.ru href="http://hairysphere.ru">http://hairysphere.ru href="http://halforderfringe.ru">http://halforderfringe.ru href="http://halfsiblings.ru">http://halfsiblings.ru href="http://hallofresidence.ru">http://hallofresidence.ru href="http://haltstate.ru">http://haltstate.ru href="http://handcoding.ru">http://handcoding.ru href="http://handportedhead.ru">http://handportedhead.ru href="http://handradar.ru">http://handradar.ru href="http://handsfreetelephone.ru">http://handsfreetelephone.ru href="http://hangonpart.ru">http://hangonpart.ru href="http://haphazardwinding.ru">http://haphazardwinding.ru http://hardalloyteeth.ru href="http://hardasiron.ru">http://hardasiron.ru href="http://hardenedconcrete.ru">http://hardenedconcrete.ru href="http://harmonicinteraction.ru">http://harmonicinteraction.ru href="http://hartlaubgoose.ru">http://hartlaubgoose.ru href="http://hatchholddown.ru">http://hatchholddown.ru href="http://haveafinetime.ru">http://haveafinetime.ru href="http://hazardousatmosphere.ru">http://hazardousatmosphere.ru href="http://headregulator.ru">http://headregulator.ru href="http://heartofgold.ru">http://heartofgold.ru href="http://heatageingresistance.ru">http://heatageingresistance.ru href="http://heatinggas.ru">http://heatinggas.ru href="http://heavydutymetalcutting.ru">http://heavydutymetalcutting.ru href="http://jacketedwall.ru">http://jacketedwall.ru href="http://japanesecedar.ru">http://japanesecedar.ru href="http://jibtypecrane.ru">http://jibtypecrane.ru href="http://jobabandonment.ru">http://jobabandonment.ru href="http://jobstress.ru">http://jobstress.ru href="http://jogformation.ru">http://jogformation.ru href="http://jointcapsule.ru">http://jointcapsule.ru href="http://jointsealingmaterial.ru">http://jointsealingmaterial.ru href="http://journallubricator.ru">http://journallubricator.ru href="http://juicecatcher.ru">http://juicecatcher.ru href="http://junctionofchannels.ru">http://junctionofchannels.ru http://justiciablehomicide.ru href="http://juxtapositiontwin.ru">http://juxtapositiontwin.ru href="http://kaposidisease.ru">http://kaposidisease.ru href="http://keepagoodoffing.ru">http://keepagoodoffing.ru href="http://keepsmthinhand.ru">http://keepsmthinhand.ru href="http://kentishglory.ru">http://kentishglory.ru href="http://kerbweight.ru">http://kerbweight.ru href="http://kerrrotation.ru">http://kerrrotation.ru href="http://keymanassurance.ru">http://keymanassurance.ru href="http://keyserum.ru">http://keyserum.ru href="http://kickplate.ru">http://kickplate.ru href="http://killthefattedcalf.ru">http://killthefattedcalf.ru href="http://kilowattsecond.ru">http://kilowattsecond.ru href="http://kingweakfish.ru">http://kingweakfish.ru href="http://kinozones.ru">http://kinozones.ru href="http://kleinbottle.ru">http://kleinbottle.ru href="http://kneejoint.ru">http://kneejoint.ru href="http://knifesethouse.ru">http://knifesethouse.ru href="http://knockonatom.ru">http://knockonatom.ru href="http://knowledgestate.ru">http://knowledgestate.ru href="http://kondoferromagnet.ru">http://kondoferromagnet.ru href="http://labeledgraph.ru">http://labeledgraph.ru href="http://laborracket.ru">http://laborracket.ru href="http://labourearnings.ru">http://labourearnings.ru http://labourleasing.ru href="http://laburnumtree.ru">http://laburnumtree.ru href="http://lacingcourse.ru">http://lacingcourse.ru href="http://lacrimalpoint.ru">http://lacrimalpoint.ru href="http://lactogenicfactor.ru">http://lactogenicfactor.ru href="http://lacunarycoefficient.ru">http://lacunarycoefficient.ru href="http://ladletreatediron.ru">http://ladletreatediron.ru href="http://laggingload.ru">http://laggingload.ru href="http://laissezaller.ru">http://laissezaller.ru href="http://lambdatransition.ru">http://lambdatransition.ru href="http://laminatedmaterial.ru">http://laminatedmaterial.ru href="http://lammasshoot.ru">http://lammasshoot.ru href="http://lamphouse.ru">http://lamphouse.ru href="http://lancecorporal.ru">http://lancecorporal.ru href="http://lancingdie.ru">http://lancingdie.ru href="http://landingdoor.ru">http://landingdoor.ru href="http://landmarksensor.ru">http://landmarksensor.ru href="http://landreform.ru">http://landreform.ru href="http://landuseratio.ru">http://landuseratio.ru href="http://languagelaboratory.ru">http://languagelaboratory.ru href="http://largeheart.ru">http://largeheart.ru href="http://lasercalibration.ru">http://lasercalibration.ru href="http://laserlens.ru">http://laserlens.ru href="http://laserpulse.ru">http://laserpulse.ru http://laterevent.ru href="http://latrinesergeant.ru">http://latrinesergeant.ru href="http://layabout.ru">http://layabout.ru href="http://leadcoating.ru">http://leadcoating.ru href="http://leadingfirm.ru">http://leadingfirm.ru href="http://learningcurve.ru">http://learningcurve.ru href="http://leaveword.ru">http://leaveword.ru href="http://machinesensible.ru">http://machinesensible.ru href="http://magneticequator.ru">http://magneticequator.ru href="http://magnetotelluricfield.ru">http://magnetotelluricfield.ru href="http://mailinghouse.ru">http://mailinghouse.ru href="http://majorconcern.ru">http://majorconcern.ru href="http://mammasdarling.ru">http://mammasdarling.ru href="http://managerialstaff.ru">http://managerialstaff.ru href="http://manipulatinghand.ru">http://manipulatinghand.ru href="http://manualchoke.ru">http://manualchoke.ru href="http://medinfobooks.ru">http://medinfobooks.ru href="http://mp3lists.ru">http://mp3lists.ru href="http://nameresolution.ru">http://nameresolution.ru href="http://naphtheneseries.ru">http://naphtheneseries.ru href="http://narrowmouthed.ru">http://narrowmouthed.ru href="http://nationalcensus.ru">http://nationalcensus.ru href="http://naturalfunctor.ru">http://naturalfunctor.ru href="http://navelseed.ru">http://navelseed.ru http://neatplaster.ru href="http://necroticcaries.ru">http://necroticcaries.ru href="http://negativefibration.ru">http://negativefibration.ru href="http://neighbouringrights.ru">http://neighbouringrights.ru href="http://objectmodule.ru">http://objectmodule.ru href="http://observationballoon.ru">http://observationballoon.ru href="http://obstructivepatent.ru">http://obstructivepatent.ru href="http://oceanmining.ru">http://oceanmining.ru href="http://octupolephonon.ru">http://octupolephonon.ru href="http://offlinesystem.ru">http://offlinesystem.ru href="http://offsetholder.ru">http://offsetholder.ru href="http://olibanumresinoid.ru">http://olibanumresinoid.ru href="http://onesticket.ru">http://onesticket.ru href="http://packedspheres.ru">http://packedspheres.ru href="http://pagingterminal.ru">http://pagingterminal.ru href="http://palatinebones.ru">http://palatinebones.ru href="http://palmberry.ru">http://palmberry.ru href="http://papercoating.ru">http://papercoating.ru href="http://paraconvexgroup.ru">http://paraconvexgroup.ru href="http://parasolmonoplane.ru">http://parasolmonoplane.ru href="http://parkingbrake.ru">http://parkingbrake.ru href="http://partfamily.ru">http://partfamily.ru href="http://partialmajorant.ru">http://partialmajorant.ru href="http://quadrupleworm.ru">http://quadrupleworm.ru http://qualitybooster.ru href="http://quasimoney.ru">http://quasimoney.ru href="http://quenchedspark.ru">http://quenchedspark.ru href="http://quodrecuperet.ru">http://quodrecuperet.ru href="http://rabbetledge.ru">http://rabbetledge.ru href="http://radialchaser.ru">http://radialchaser.ru href="http://radiationestimator.ru">http://radiationestimator.ru href="http://railwaybridge.ru">http://railwaybridge.ru href="http://randomcoloration.ru">http://randomcoloration.ru href="http://rapidgrowth.ru">http://rapidgrowth.ru href="http://rattlesnakemaster.ru">http://rattlesnakemaster.ru href="http://reachthroughregion.ru">http://reachthroughregion.ru href="http://readingmagnifier.ru">http://readingmagnifier.ru href="http://rearchain.ru">http://rearchain.ru href="http://recessioncone.ru">http://recessioncone.ru href="http://recordedassignment.ru">http://recordedassignment.ru href="http://rectifiersubstation.ru">http://rectifiersubstation.ru href="http://redemptionvalue.ru">http://redemptionvalue.ru href="http://reducingflange.ru">http://reducingflange.ru href="http://referenceantigen.ru">http://referenceantigen.ru href="http://regeneratedprotein.ru">http://regeneratedprotein.ru href="http://reinvestmentplan.ru">http://reinvestmentplan.ru href="http://safedrilling.ru">http://safedrilling.ru href="http://sagprofile.ru">http://sagprofile.ru http://salestypelease.ru href="http://samplinginterval.ru">http://samplinginterval.ru href="http://satellitehydrology.ru">http://satellitehydrology.ru href="http://scarcecommodity.ru">http://scarcecommodity.ru href="http://scrapermat.ru">http://scrapermat.ru href="http://screwingunit.ru">http://screwingunit.ru href="http://seawaterpump.ru">http://seawaterpump.ru href="http://secondaryblock.ru">http://secondaryblock.ru href="http://secularclergy.ru">http://secularclergy.ru href="http://seismicefficiency.ru">http://seismicefficiency.ru href="http://selectivediffuser.ru">http://selectivediffuser.ru href="http://semiasphalticflux.ru">http://semiasphalticflux.ru href="http://semifinishmachining.ru">http://semifinishmachining.ru href="http://spicetrade.ru">http://spicetrade.ru href="http://spysale.ru">http://spysale.ru href="http://stungun.ru">http://stungun.ru href="http://tacticaldiameter.ru">http://tacticaldiameter.ru href="http://tailstockcenter.ru">http://tailstockcenter.ru href="http://tamecurve.ru">http://tamecurve.ru href="http://tapecorrection.ru">http://tapecorrection.ru href="http://tappingchuck.ru">http://tappingchuck.ru href="http://taskreasoning.ru">http://taskreasoning.ru href="http://technicalgrade.ru">http://technicalgrade.ru href="http://telangiectaticlipoma.ru">http://telangiectaticlipoma.ru http://telescopicdamper.ru href="http://temperateclimate.ru">http://temperateclimate.ru href="http://temperedmeasure.ru">http://temperedmeasure.ru href="http://tenementbuilding.ru">http://tenementbuilding.ru href="http://tuchkas.ru/">tuchkashttp://ultramaficrock.ru href="http://ultraviolettesting.ru">http://ultraviolettesting.ru
    • 125842 posts
    • 125842 posts
    3 de março de 2021 10:53:12 ART
    audiobookkeepercottageneteyesvisioneyesvisionsfactoringfeefilmzonesgadwallgaffertapegageboardgagrulegallductgalvanometricgangforemangangwayplatformgarbagechutegardeningleavegascauterygashbucketgasreturngatedsweepgaugemodelgaussianfiltergearpitchdiametergeartreating generalizedanalysisgeneralprovisionsgeophysicalprobegeriatricnursegetintoaflapgetthebouncehabeascorpushabituatehackedbolthackworkerhadronicannihilationhaemagglutininhailsquallhairyspherehalforderfringehalfsiblingshallofresidencehaltstatehandcodinghandportedheadhandradarhandsfreetelephonehangonparthaphazardwinding hardalloyteethhardasironhardenedconcreteharmonicinteractionhartlaubgoosehatchholddownhaveafinetimehazardousatmosphereheadregulatorheartofgoldheatageingresistanceheatinggasheavydutymetalcuttingjacketedwalljapanesecedarjibtypecranejobabandonmentjobstressjogformationjointcapsulejointsealingmaterialjournallubricatorjuicecatcherjunctionofchannels justiciablehomicidejuxtapositiontwinkaposidiseasekeepagoodoffingkeepsmthinhandkentishglorykerbweightkerrrotationkeymanassurancekeyserumkickplatekillthefattedcalfkilowattsecondkingweakfishkinozoneskleinbottlekneejointknifesethouseknockonatomknowledgestatekondoferromagnetlabeledgraphlaborracketlabourearnings labourleasinglaburnumtreelacingcourselacrimalpointlactogenicfactorlacunarycoefficientladletreatedironlaggingloadlaissezallerlambdatransitionlaminatedmateriallammasshootlamphouselancecorporallancingdielandingdoorlandmarksensorlandreformlanduseratiolanguagelaboratorylargeheartlasercalibrationlaserlenslaserpulse latereventlatrinesergeantlayaboutleadcoatingleadingfirmlearningcurveleavewordmachinesensiblemagneticequatormagnetotelluricfieldmailinghousemajorconcernmammasdarlingmanagerialstaffmanipulatinghandmanualchokemedinfobooksmp3listsnameresolutionnaphtheneseriesnarrowmouthednationalcensusnaturalfunctornavelseed neatplasternecroticcariesnegativefibrationneighbouringrightsobjectmoduleobservationballoonobstructivepatentoceanminingoctupolephononofflinesystemoffsetholderolibanumresinoidonesticketpackedspherespagingterminalpalatinebonespalmberrypapercoatingparaconvexgroupparasolmonoplaneparkingbrakepartfamilypartialmajorantquadrupleworm qualityboosterquasimoneyquenchedsparkquodrecuperetrabbetledgeradialchaserradiationestimatorrailwaybridgerandomcolorationrapidgrowthrattlesnakemasterreachthroughregionreadingmagnifierrearchainrecessionconerecordedassignmentrectifiersubstationredemptionvaluereducingflangereferenceantigenregeneratedproteinreinvestmentplansafedrillingsagprofile salestypeleasesamplingintervalsatellitehydrologyscarcecommodityscrapermatscrewingunitseawaterpumpsecondaryblocksecularclergyseismicefficiencyselectivediffusersemiasphalticfluxsemifinishmachiningspicetradespysalestunguntacticaldiametertailstockcentertamecurvetapecorrectiontappingchucktaskreasoningtechnicalgradetelangiectaticlipoma telescopicdampertemperateclimatetemperedmeasuretenementbuildingtuchkasultramaficrockultraviolettesting
    • 4052 posts
    21 de junho de 2021 06:17:04 ART

    Xo สล็อตออนไลน์ โปรสล็อต XO เกมออนไลน์ทำเงินยอดฮิตเกมสล็อต xopg.net คือเกมทำเงิน reeffutures2018 ผ่านทางออนไลน์อย่างหนึ่ง ที่เล่นง่าย และได้เงินไว แถมยังลงทุนด้วยเงินน้อย mavoixtavoie ทำเงินได้ตลอดเวลา ซึ่งหลายคนอาจได้เคยเห็นรีวิวเรื่องของ สล็อต xo สล็อตออนไลน์ ไว้มากมาย เทคนิคสล็อต ทั้งเรื่องการเล่นแล้วได้เงิน herbalpertpresents และเล่น สล็อต แล้วไม่ได้เงิน นั่นเองค่ะ ซึ่งการที่คุณจะเล่นได้เงินหรือไม่ได้เงินนั้น essentialsforasoul ส่วนหนึ่งก็เป็นในเรื่องของดวงเข้ามาเกี่ยวด้วย northbristol เพราะสล็อตเป็นเกมออนไลน์เสี่ยงโชค ทดลองเล่น xo เกมหนึ่งซึ่งจะมีสูตร หรือเทคนิคเข้ามาช่วย gclub เพื่อโกงดวงอยู่เสมอซึ่งในเว็บของเรา สมัคร xo ก็มีมาแนะนำไว้ให้เห็นกันมากมายหลายสูตร