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? |



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