dynamic check_box using field_for in rails
I have a many-to-many relationship with a link box, and I want to pull those models together into one form so I can update from the same page. I开发者_运维技巧'm really struggling with getting the check_box to even show all the elements of my array - I've scoured the net and been working on this literally all day, and I'm finding it difficult to apply the information I'm reading to my problem. I'm also extremely new to RoR and I've been following a bit of an outdated video tutorial (pre 2.0) so apologies for my code. So far, I've got it to output only one key pair in the array (the last one) - although outside the form, the code used in the tutorial works exactly how it should. Thats of little use though! Host is the model for which the main form is for, and Billing is the outside model that I'm trying to add to the form.
This is the code that works outside of the form from the tutorial:
<% for billing in @billings -%>
<%= check_box_tag('billing_title[]', billing.id, @host.billings.collect
{|obj| obj.id}.include?(billing.id))%> <%= billing.title %><br />
<% end -%>
I just need to know how to make it work inside the form. This is the aforementioned code that only retrieves the last array keypair after looping through them:
<% f.fields_for :billings do |obj| %><br />
<%= check_box_tag('billing_title[]', billing.id, @billings.collect
{|obj| obj.id}.include?(billing.id))%> <%= billing.title %><br />
<% end %>
The debug(@billings) :
---
- !ruby/object:Billing
attributes:
title: Every Month
id: "1"
attributes_cache: {}
- !ruby/object:Billing
attributes:
title: 12 Months
id: "2"
attributes_cache: {}
- !ruby/object:Billing
attributes:
title: 6 Months
id: "5"
attributes_cache: {}
Any help really appreciated.
Craig, it sounds like what you are looking for is accepts_nested_attributes_for which is a much better way of handling nested models in a form.
Rather than just steal all of Ryan's work and repost it here, I'll just give you a link to his screencast:
http://railscasts.com/episodes/196-nested-model-form-part-1
This is based off his complex forms series.
You should be able to taylor this tutorial to what you are trying to do, but if not I'd be happy to help.
EDIT:
Alright, after looking at your code, there are a few things causing you problems. :)
First of all, with associations, you don't need to pull an extra collection for billings, i.e.:
@host = Host.find(params[:id])
@voips = Voip.find(:all)
@custsupps = Custsupp.find(:all)
@payments = Payment.find(:all)
@billings = Billing.find(:all) # <-- This is not needed and causing your problems
The association setup in the model does this all for you. This is part of the magic of rails. :D
Now, it is important to note that when using associations you need to make sure that the objects are actually associated. In other words, if you have 3 Billings objects in your database and they are not associated with your Host object, they won't show up in the form.
If you are trying to associate a billing TO a Host using a checkbox you are going to want to take a different approach, because your form with only display Billings already associated with your Host.
If your just trying to edit or modify existing Billings that are associated to the Host, where the checkbox represents a 'paid' attribute (a boolean) for instance, then this approach is fine and your form code would look something like this:
<% f.fields_for :billings do |b| %><br />
<%= b.check_box :paid %> <%= b.title %>
<% end %>
So perhaps clarify what your trying to accomplish from a functionality standpoint and we can find a better solution.
i'm not sure about my answer, but i'll try...
<% f.fields_for :billings, @billings do |obj| %>
# ...
<% end %>
Looks to me like it's a problem with the for-loops...
In your example code, you are looping through the @billings
(an array of billings objects passed from your controller), and calling the current one billing
.
In your form code, you are looping through the :billings
(symbol referencing the billings ActiveRecords) and calling the current one obj
. Then, confusingly, your code re-uses the variable name obj
again in the @billings.collect function... but this should have local private scope and not effect your main loop, but it is hard to interpret on sight.
Anyway, since the stuff inside your form loop doesn't reference obj
, it is using the variable billing
--which does not change when you loop through, but keeps the last value it had: the last item from the previous loop! This explains why you only see the last tag. (Also, the debug(@billings)
function does its own looping through the records of sorts--it is not inside the fields_for do loop.)
I would start with changing the first line of your form code to re-use the variable name billing
again, like this:
<% f.fields_for :billings do |billing| %><br />
Ruby's block syntax can be pretty confusing at first--or, heck, anytime you're reading code you didn't write yourself--but when you break it all down to the basic components, it's usually just looping through a set of items and performing some function on each one. Also watch out for the confusion between similar-looking names: @billing, @billings, :billings and billings are all different things to Ruby and Rails. Good luck!
精彩评论