Usando checkboxes em uma relação habtm no Rails

Uma dúvida muito comum entre quem está começando a programar em Rails é como colocar uma série de checkboxes que representam uma relação habtm (has_and_belongs_to_many, ou muitos-para-muitos) entre dois modelos. É sobre isso que vou falar neste artigo. Este exemplo foi executado no Rails 2.1.

Vamos tomar um exemplo simples: Livros e Categorias. Um livro pode estar presente em várias categorias, e uma categoria pode conter diversos livros. Seus models ficam mais ou menos assim:

#Model Livro
has_and_belongs_to_many :categorias

#Model Categoria
has_and_belogns_to_many :livros

Agora suponhamos que na sua view você vai mostrar um formulário para cadastro ou edição de um livro, que deve mostrar um checkbox para cada categoria. O form ficaria mais ou menos assim (não vou entrar na questão da utilização de partials, para poder ir direto ao assunto):

# Controller livros_controller

# Action new
def new
	@livro = Livro.new
end

#View
<% form_for(@livro) do |f| %>
	<p>Título<br />
	<%= f.text_field :titulo </p>

	<p>Categorias<br />
	<% Categoria.find(:all).each do |c| %>
		<%= check_box_tag 'livro[categoria_ids][]', c.id, @livro.categorias.include?(c) %><%= c.nome %><br /></p>
	<% end %>
<% end %>

Em condições normais de temperatura e pressão, isso deverá funcionar. Veja onde está a mágica: quando você cria um checkbox usando check_box_tag 'livro[categoria_ids][]', você está dizendo pro Rails que aquele checkbox faz parte de um array (por isso os colchetes vazios no final da string) de ids de categorias daquele livro. Então o segredo está nos colchetes vazios.

Só que aí aparece um novo problema: depois de verificar que tudo funciona como esperado, experimente atualizar o cadastro de um livro desmarcando todas as categorias que estiverem salvas para ele. Desconsiderando o fato de que provavelmente você vai inserir alguma forma de controle no sistema para que isso não aconteça, perceba que o Rails não salva as alterações quando nenhuma categoria é selecionada através dos checkboxes, mantendo as seleções como estavam anteriormente, apesar de salvar as alterações nos outros campos. Isso acontece porque, por padrão, os browsers não enviam os campos dos formulários quando estes são checkboxes não selecionados. Então o Rails “pensa” que não houve modificação neste campo. Se você der uma olhada no log do servidor, verá que “categoria_ids” não faz parte do hash enviado na requisição.

Para resolver esse problema, você precisa adicionar uma linha de código no início da action update do controller livros_controller, para verificar se params[:livro][:categoria_ids] é nulo. Em caso afirmativo, atribua a essa variável um array vazio, assim:

params[:livro][:categoria_ids] ||= []

Essa única linha, colocada no início da action update, é suficiente para resolver o problema citado anteriormente.

Have fun!


Poderia avaliar este artigo, por favor?

1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas
Loading ... Loading ...

Posts relacionados

  • Alexandre

    Olá, estou fazendo algo parecido, porém com Projetos e Membros. No meu project.rb esttá assim:

    has_and_belongs_to_many :members, :class_name => “User”,
    :join_table => “projects_members”,
    :association_foreign_key => “member_id”

    E na minha view…

    Não sei porque, mas só funciona quando estou EDITANDO um projeto já cadastrado. Se tentar criar um novo projeto, selecionando os check-boxes dos Membros, o Rails gera um erro “members is invalid” e não grava nada.

    Você sabe o que pode ser ?

  • Alexandre

    Olá, estou fazendo algo parecido, porém com Projetos e Membros. No meu project.rb esttá assim:

    has_and_belongs_to_many :members, :class_name => “User”,
    :join_table => “projects_members”,
    :association_foreign_key => “member_id”

    E na minha view…

    Não sei porque, mas só funciona quando estou EDITANDO um projeto já cadastrado. Se tentar criar um novo projeto, selecionando os check-boxes dos Membros, o Rails gera um erro “members is invalid” e não grava nada.

    Você sabe o que pode ser ?

  • http://www.elvis.eti.br/ Elvis Fernandes

    Olá, Alexandre!

    O engine do blog não permite caracteres do html, portanto não recebi o seu código. Mas pelo erro, acredito que vale a pena você verificar através dos logs o que está chegando para o servidor. Pode ser que os valores não estejam chegando corretamente.

    Visualizar o html gerado no browser também vai ajudar a encontrar o problema.

    Obrigado pelo comentário!

    Elvis Fernandes

  • http://www.elvis.eti.br Elvis Fernandes

    Olá, Alexandre!

    O engine do blog não permite caracteres do html, portanto não recebi o seu código. Mas pelo erro, acredito que vale a pena você verificar através dos logs o que está chegando para o servidor. Pode ser que os valores não estejam chegando corretamente.

    Visualizar o html gerado no browser também vai ajudar a encontrar o problema.

    Obrigado pelo comentário!

    Elvis Fernandes

  • Pingback: Vários Checkboxs ( HBTM ) « Diego Nogueira

  • Paulorof_ce

    Show de bola o tutorial, pra quem nunca tinha testado isso é muito simples, a cada dia mais me surpreendo com o Rails.

  • r2rails.com.br

    PARABÉNS… SALVOU MINHA VIDA HEHEHE :) ABRAÇO E SUCESSO AO BLOG!