Artigos com a tag ‘ActionPack’

Edge Rails: Gerando rotas polimórficas a partir da classe de um modelo

7 de setembro de 2009  |  Edge Rails  |  Nenhum comentário  | 
# Exemplo do uso de rotas polimórficas para gerar a URL à partir
# da classe de um modelo

polymorphic_url(Comment) # é equivalente ao comments_url()
# => "http://example.com/comments"

Rails 2.3: Nested Attributes

4 de fevereiro de 2009  |  Rails 2.3  |  7 Comentários  | 

Durante muito tempo a funcionalidade mais requisitada ao core team do Rails era a simplificação do gerenciamento de múltiplos modelos em apenas um formulário. Eu mesmo cheguei a comentar sobre uma nova opção chamada :accessible que facilitaria atribuições em massa em objetos ActiveRecord (aqui e aqui).

Infelizmente este recurso foi incluído ao Rails cedo demais, já que ele só dava suporte a nested models (é como chamamos os modelos que estão “acoplados” a um outro modelo, como quando usamos belongs_to ou has_many) durante a criação dos objetos e por isto ele foi removido afim de ser aprimorado.

No Rails 2.3 esta funcionalidade volta a existir, mas de uma maneira diferente. A primeira coisa que devemos fazer é informar ao modelo que ele se beneficiará deste recurso incluindo uma chamada ao método accept_nested_attributes_for, como no exemplo:

class Project < ActiveRecord::Base
  has_many :tasks

  accept_nested_attributes_for :tasks, :allow_destroy => true
end

Como visto acima estou “ligando” a atribuição em massa para o modelo Task via o modelo Project. Isto também vale para qualquer tipo de relacionamento, como belongs_to, has_one, has_many e has_and_belongs_to_many.

Uma vez feito isto, agora eu posso criar, editar e apagar tarefas (tasks) através do objeto Project:

# Adicionando uma nova tarefa ao projeto
@project.task_attributes = { 'new_1' => { :name => 'Task 1' } }
@project.task #=> [ <#Task: name: 'Task 1'> ]
@project.task.clear

# Adicionando duas tarefas ao projeto
@project.task_attributes =
  { 'new_1' => { :name => 'Task 1' }, 'new_2' => { :name => 'Task 2' } }
@project.save
@project.task #=> [ <#Task: name: 'Task 1'>, <#Task: name: 'Task 2'> ]

# Alterando a primeira tarefa (assumindo o id == 1)
@project.task_attributes = { '1' => { :name => 'My Task' } }
@project.save

# Alterando a segunda tarefa (id == 2) e incluindo uma nova
@project.task_attributes = {
  '2' => { :name => 'My Second Task' },
  'new_1' => { :name => 'Task 3' } }
@project.save

# Apaga o último registro (id == 3)
@project.task_attributes = { '3' => { '_delete' => '1' } }
@project.save

Talvez neste momento você esteja se questionando sobre estes formatos estranhos, como ao apagar um registro. Sim, estes hashs são meio confusos mesmo, mas eles não foram criados para serem usados desta maneira. O uso prático deste novo recurso está na criação de formulários:

<% form_for @project do |project_form| %>
  <div>
    <%= project_form.label :name, 'Project name:' %>
    <%= project_form.text_field :name %>
  </div>

  <!-- PRESTE ATENÇÃO AQUI -->
  <% project_form.fields_for :tasks do |task_form| %>
      <p>
        <div>
          <%= task_form.label :name, 'Task:' %>
          <%= task_form.text_field :name %>
        </div>

        <% unless task_form.object.new_record? %>
          <div>
            <%= task_form.label :_delete, 'Remove:' %>
            <%= task_form.check_box :_delete %>
          </div>
        <% end %>
      </p>
    <% end %>
  <% end %>

  <%= project_form.submit %>
<% end %>

Ao definir project_form.fields_for :tasks estamos dizendo que aquele trecho do formulário deve usar o recurso de atribuição em massa para criar, editar ou apagar uma tarefa (task) já existente.

Caso uma das validações da classe Task não passe (imagine que esta tenha um validates_presence_of :name e que eu deixei o campo name em branco), a mensagem correspondente a esta validação será copiada para a classe pai, no caso para a classe Project e estará acessível através do método error_messages_for dela.

Este novo sistema também conta com o recurso de transações. Isto significa que ao realizar uma série de operações de uma só vez, se uma der errado, nenhuma delas será efetivada. Lembre-se apenas que como toda transação no Rails, embora no banco de dados nada aconteça, na instancia do seu objeto ele ainda continuará com as alterações marcadas.

O mais importante em tudo isto é que o código em seus controllers continuarão exatamente da mesma forma como já é hoje. Nenhuma alteração é necessária. Seguindo os exemplos acima, veja como ficaria meu controller:

class ProjectController < ApplicationController

  def create
    @project = Project.new(params[:project])
    if @project.save
      redirect_to(project_path(@project))
    else
      render(:action => :new)
    end
  end

  def update
    @project = Project.find(params[:id])
    @project.update_attributes(params[:project]) ?
      redirect_to(project_path(@project)) : render(:action => :edit)
  end

end

Nada mudou correto?

Eloy Duran, o programador responsável por este novo recurso, tem um projeto no GitHub mostrando mais detalhes sobre o seu funcionamento. Recomendo que você dê uma olhada neste formulário em especial, onde ele mostra como incluir múltiplas tarefas no mesmo projeto.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Rails 2.3.

Rails 2.3: Formatted Routes

3 de fevereiro de 2009  |  Rails 2.3  |  6 Comentários  | 

No Rails 2.3, ao acessar nossas rotas nomeadas não teremos mais métodos como formatted_post_path ou formatted_new_user_path. Estes métodos dinâmicos foram removidos com o objetivo de melhorar o consumo de memória no Rails.

Mas isto não significa que não teremos mais a funcionalidade de rotas formatadas. Elas continuam existindo, mas devem ser acessadas de outra maneira. Vejamos alguns exemplos comparando a forma atual e a nova forma:

# atual
formatted_post_path(post, :xml)
# novo
post_path(post, :format => :xml)

# atual
formatted_new_user_path(:json)
# novo
new_user_path(:format => :json)

É uma mudança muito pequena, mas que internamente tem um impacto significativo no consumo de memória dos processos Rails, principalmente se você possui muitas rotas em seu projeto.

Caso você esteja em um processo de migração deve atentar a esta alteração.

O Rails 2.3 já está em sua versão RC1 e em poucos dias devemos ter sua versão final lançada, mas esta série continuará expondo algumas das novidades que encontraremos nesta versão.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: render_component

29 de janeiro de 2009  |  Rails 2.3  |  Nenhum comentário  | 

O método render_component já havia sido marcado como deprecated em versões anteriores do Rails, mas na versão 2.3 ele será totalmente removido do framework.

Este método tem a finalidade de fazer com que uma outra action renderize a action em execução. É meio complicado de explicar, então vamos aos famosos exemplos:

class WeblogController < ActionController::Base
  # Performs a method and then lets hello_world output its render
  def delegate_action
    do_other_stuff_before_hello_world

    render_component :controller => "greeter",
      :action => "hello_world",
      :params => { :person => "david" }
  end
end

class GreeterController < ActionController::Base
  def hello_world
    render :text => "#{params[:person]} says, Hello World!"
  end
end

No exemplo acima estou executando a action delegate_action, mas estou fazendo uso do método render_component para que a resposta da minha action seja criada pela action hello_world que está em um outro controller.

Um outro uso mais prático deste recurso, é usá-lo de dentro de uma view:

<%= render_component :controller => "greeter", :action => "hello_world" %>

Neste caso o render_component agiria como se eu estivesse chamando um partial, quando na verdade estou executando uma action em um controller.

Por que um método tão legal está sendo removido do Rails? A resposta é muito simples: ele é muito lento e tem a mania de deixar as coisas um pouco confusas. Partials e filtros podem ser usados para a mesma finalidade e oferecem uma performance muito melhor, além de mais clareza ao código.

Se ainda assim, você desejar usar render_component ou se já está usando e deseja migrar seu projeto, foi criado um plugin que devolve esta funcionalidade ao Rails.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: Simplificando o uso de partials

28 de janeiro de 2009  |  Rails 2.3  |  Nenhum comentário  | 

A cada nova versão do Rails o método render tem se tornado mais esperto, e no Rails 2.3 isto não será diferente.

Até hoje se nenhuma opção fosse informada ao método ele usaria a opção :file como padrão. Isto mudou já que agora a opção padrão, para quando nenhuma outra for informada, será renderizar uma partial. Além disso, por convenção, o último parâmetro informado ao método sempre será o hash de variáveis locais (local_assigns).

Isto muda um pouco a forma de usar partials. Vejamos alguns exemplos comparando a sintaxe antiga com a nova sintaxe. Primeiro um exemplo simples:

# Antes
render :partial => "account"

# Rails 2.3 em diante
render "account"

Agora um exemplo informando uma variável local:

# Antes
render :partial => "account", :locals => { :account => @buyer }

# Rails 2.3 em diante
render "account", :account => @buyer

No exemplo abaixo a variável @account é uma instancia da classe Account, desta forma o Rails usa o RecordIdentifier para fazer a mágica:

# Antes
render :partial => "accounts/account", :locals => { :account => @account }

# Rails 2.3 em diante
render(@account)

Um último exemplo, onde a variável @posts é um array com instâncias da classe Post. Mais mágica:

# Antes
render :partial => "posts/post", :collection => @posts

# Rails 2.3 em diante
render(@posts)

Caso você esteja migrando seu projeto para o Rails 2.3, tome o cuidado de verificar se não está usando o método render com a opção padrão em algum lugar do seu projeto. Se estiver, será necessário alterar para especificar a opção :file, assim:

render :file => 'greeting'

Como você pode ver, tivemos uma boa diminuição na quantidade de código necessário ao usar partials.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: Date Helpers

21 de janeiro de 2009  |  Rails 2.3  |  Nenhum comentário  | 

Uma nova opção foi adicionada aos date helpers do Rails. Métodos como o date_select, time_select, datetime_select, select_minute e outros receberam a opção :prompt.

Com esta opção é possível definir um valor padrão como o primeiro elemento da lista. Veja um exemplo:

<%= date_select("post", "written_on", :prompt => true) %>

O código acima devolverá os campos com as seguintes mensagens:

exemplo1

Exemplo com os valores padrão

Também é possível personalizar a mensagem de cada campo:

<%= date_select("post", "written_on",
      :prompt => {
        :day => 'Select day',
        :month => 'Select month',
        :year => 'Select year'
      }) %>

Com o código acima teremos algo assim:

exemplo2

Exemplo com valores personalizados

Esta é uma opção muito bem-vinda, já que para conseguir o mesmo efeito antes era necessário um truquezinho.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: observe_field

20 de janeiro de 2009  |  Rails 2.3  |  2 Comentários  | 

O método observe_field tem a finalidade de observar um determinado campo de um formulário e executar uma chamada Ajax quando houver alguma alteração em seu valor.

Até hoje, este método possuía também a opção :on que permitia identificar qual evento deveria ser observado. No exemplo abaixo ele deveria disparar uma chamada Ajax assim que o campo book_title perdesse o foco (blur):

observe_field 'book_title',
  :url => 'http://example.com/books/edit/1',
  :on => 'blur'

Mas a funcionalidade que define a opção :on foi removida do Prototype (o framework utilizado pelo Rails para manipulação de JavaScript) há mais ou menos dois anos atrás. Ou seja, já faz dois anos que esta opção não funciona e foi ignorada, por isto ela foi removida definitivamente do Rails.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: assert_valid (deprecated)

29 de dezembro de 2008  |  Rails 2.3  |  Nenhum comentário  | 

O método assert_valid foi marcado como deprecated. Embora ele ainda continue existindo no Rails 2.3, não estará mais presente no Rails 3.

Este método era útil para garantir que um registro era válido e que não possuía nenhuma mensagem de erro. A sugestão é que usemos o seguinte código em seu lugar:

assert record.valid?
# ou
assert @model.valid?, @model.errors

Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Edge Rails: Backtrace Cleaner

23 de dezembro de 2008  |  Rails 2.3  |  Nenhum comentário  | 

Já ouviu falar do plugin Quiet Backtrace criado pela Thoughtbot, a mesma galera por trás do Paperclip e Shoulda? Este plugin é muito interessante porque ele permite que você remova certas linhas do backtrace do Rails, tornando o log muito menor e simplificando a localização de problemas.

O conceito por trás deste plugin foi adicionado ao Rails. Um novo initializer chamado backtrace_silencers.rb foi criado e virá com algumas linhas de exemplo comentadas, assim:

# Be sure to restart your server when you modify this file.

# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }

# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code.
# Rails.backtrace_cleaner.remove_silencers!

Neste arquivo você pode incluir silenciadores e filtros para o backtrace. Por exemplo o seguinte silenciador removerá do backtrace qualquer linha que contenha a palavra mongrel:

Rails.backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }

Os filtros funcionam de uma maneira um pouco diferente, não removendo a linha, mas substituindo trechos do backtrace por alguma outra coisa. No exemplo abaixo estou fazendo com que toda vez que a palavra mongrel aparecer no backtrace ela seja substituída por ‘aeiou’:

Rails.backtrace_cleaner.add_filter { |line| line.gsub("mongrel", 'aeiou') }

Para desligar esta funcionalidade temporariamente basta tirar o comentário da linha abaixo:

Rails.backtrace_cleaner.remove_silencers!

Usado com sabedoria, este novo recurso pode se tornar uma ferramenta poderosa.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.3/3.0 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades acompanhando a série Edge Rails.

Rails 2.2: Suporte a XHTML no atom_feed

9 de dezembro de 2008  |  Rails 2.2  |  Nenhum comentário  | 

O helper atom_feed agora possui um builder interno que permite a criação de XHTML simplesmente acrescentando :type=>”xhtml” em qualquer elemento content, rights, title, subtitle ou summary. Assim:

entry.summary(:type => 'xhtml') do |xhtml|
  xhtml.p "A XHTML summary"
  xhtml.p post.body
end

Veja como este bloco se encaixa dentro do atom_feed:

atom_feed do |feed|
  feed.title("My great blog!")
  feed.updated((@posts.first.created_at))

  for post in @posts
    feed.entry(post) do |entry|
      entry.title(post.title)

      entry.summary(:type => 'xhtml') do |xhtml|
        xhtml.p "A XHTML summary"
        xhtml.p post.body
      end

      entry.author do |author|
        author.name("DHH")
      end
    end
  end
end

Desta forma o builder interno do atom_feed irá incluir o XHTML gerado dentro de uma tag DIV.

Claro que ainda podemos fazer da forma antiga passando todo o HTML dentro de uma string, mas desta forma nosso código fica mais limpo.


Todos os exemplos dados aqui funcionarão somente no Ruby on Rails 2.2 ou superior. Você pode encontrar mais detalhes sobre esta e outras novidades do Rails 2.2 no e-book “Ruby on Rails – O que há de novo?“.