So, I have a nested form where Shelter has many Cats (just using cats as an example to melt the hearts of those eager to help).
So, in my nested form I can use:
<%= f.object.shelter_id %>
which gives a value when I run the application. But, and here is the cute cat's but:
<%= f.object.shelter.name %>
doesn't work, nor does:
<%= Shelter.find(f.object.shelter_id).name %>
Above statement gives an error can't find Shelter where 'id'=
One would think the value would be passed to the query as it is displayed when the app is run? How do I access the associated values in the form? (Its only in Edit, my Show and other controllers and views work fine.)
And yes, the associations are declared in my models.
I'm using simple form with my rails 4 app.
I have 3 models in the app. One called Project, one for Scope and one for Data (the model is called datum but the view is called data).
There is a has and belongs to many association between Project and Scope. Data belongs to Scope.
I ask users to outline the scope of the project in general (by asking high level questions in the scope form) and then depending on the answers to the true/false questions in the scope form, I render partials which are forms created in the Data view.
In my scope form I have a question:
<%= f.input :data, :as => :boolean, :label => false, :inline_label => true %>
Those partials from the data view are rendered in the new project view. I have written this line to try to show the data form if the answer to the question about data (asked in the scope form) is true.
In my new project view I have:
<% if #project.scopes.data == true %>
<%= render "data/form" %>
<% end %>
In my schema I have a join table form projects_scopes. I also have a foreign key for scope_id in my data model.
However, I get this error:
`enter code here`undefined method `data' for #<ActiveRecord::Associations::CollectionProxy []>
Does anyone know what I've done wrong?
Thank you
You need to do a nested form. Basically, you end up doing another simple form inside of your simple form for the nested object, then allow your primary object to accept the nested attributes for the nested object. Here is a reference that goes into detail on implementation. I believe you can find it on youtube as well.
http://railscasts.com/episodes/196-nested-model-form-revised?view=comments
Also depending on how complex your form gets, you may look at doing a form object.
Background: My goal is for a view to display a list of "condition" has_many objects, which are themselves STI subclasses of a StateDescription. I want a user to be able to pick what type of state description they are from a drop down menu (which will conditionally display a different type of form, eventually)
Inside of my main forms, I am doing a nested form like this:
<%= f.fields_for :conditions do |e| %>
<li>
<%= e.select(:type, StateDescription.subclasses.collect{|x| x.to_s}, options_for_select(StateDescription.subclassSelectForms)) %>
<br>
<%= e.label :title %>
<%= e.text_field :title %>
</li>
<% end %>
This works just fine with the text field at the bottom there (I can change values and save them, etc). But when I try to do a select statement, it explodes.
Specifically, if I don't use e.select and just do:
<%= select(:type, StateDescription.subclasses.collect{|x| x.to_s}, options_for_select(StateDescription.subclassSelectForms)) %>
it renders just fine, but doesn't actually change any values as it is not associated with a model.
If I get rid of trying to have it display a value different than it submits and just do
<%= e.select(:type, StateDescription.subclasses.collect{|x| x.to_s}) %>
Then it works just fine(I can submit, the value is saved to the database, I can retrieve it, etc).
I can LEAVE it like this, but I had wanted to have my more human readable string display instead of a rails class thing (which might look like gibberish to a non-programmer end user).
So, my question is: Why do options_for_select break when nested and associated with a form, but dont' seem to when not associated with a form? Is it just a known bug? Am I doing something wrong?
Edit:
.subclasses is a standard rails calls which returns a list of subclasses for an object.
.subclassSelect forms goes through each subclass, and turns it into a hash of the form:
{subclass.to_s => subclass.human_readable_string} and compiles all of them into an array.
I know this array of hashes works, because if I do NOT put "e" on the front, it displays correctly and works "right" for what I have done (i.e. the subclass is returned correctly based on which human readable string I select from the drop down menu, but since it's not actually associated with any form, it doesn't get set in the controller).
I have a table that lists all users. Instead of opening each user and then editing, I want to edit certain fields within that table.
- #users.each do |u|
%tr
%td= u.name
%td= best_in_place u, :email_flag, :type => :checkbox
The issue seems to be that the only param getting passed back is the checkbox field:
Processing by UsersController#update as
Parameters: {"user"=>{"email_flag"=>"true"}
Am I approaching this the wrong way? Why isn't the user object 'u' getting passed back?
best_in_place is working correctly here. The entire set of attributes from that you're editing need not be transferred each time. That's what the HTTP PUT (or PATCH depending on your version of Rails) is used for -- updating attributes on existing instances of models. It's like in SQL, when you run UPDATE users SET email='something#example.com' WHERE id=1, you don't have to list every field every time. Only the specified columns are touched.
When you add another field for last_name or country as you said in your comment, it will work the same way.
I have a pretty standard use-case. I have a parent object and a list of child objects. I want to have a tabular form where I can edit all the children at once, as rows in the table. I also want to be able to insert one or more new rows, and on submit have them be created as new records.
When I use a fields_for to render a series of sub-forms for nested records related by has-many, rails generates field names e.g. parent[children_attributes][0][fieldname], parent[children_attributes][1][fieldname] and so on.
This causes Rack to parse a params hash that looks like:
{ "parent" => {
"children" => {
"0" => { ... },
"1" => { ... } } }
When passed a new (un-persisted) object, the same fields_for will generate a field name that looks like:
parent[children_attributes][][fieldname]
Note the [] with no index in it.
This cannot be posted in the same form with the fields containing [0], [1], etc. because Rack gets confused and raises
TypeError: expected Array (got Rack::Utils::KeySpaceConstrainedParams)
"OK", thinks I. "I'll just make sure all the fields use the [] form instead of the [index] form. But I can't figure out how to convince fields_for to do this consistently. Even if I give it an explicit field name prefix and object:
fields_for 'parent[children_attributes][]', child do |f| ...
So long as child is persisted, it will automatically modify the fieldnames so that they become e.g. parent[children_attributes][0][fieldname], while leaving fieldnames for new records as parent[children_attributes][][fieldname]. Once again, Rack barfs.
I'm at a loss. How the heck do I use standard Rails helpers like fields_for to submit multiple new records, along with existing records, have them be parsed as an array in the params, and have all the records lacking IDs be created as new records in the DB? Am I out of luck and I just have to generate all the field names manually?
As others have mentioned, the [] should contain a key for new records because otherwise it is mixing a hash with an array type. You can set this with the child_index option on fields_for.
f.fields_for :items, Item.new, child_index: "NEW_ITEM" # ...
I usually do this using the object_id instead to ensure it is unique in case there are multiple new items.
item = Item.new
f.fields_for :items, item, child_index: item.object_id # ...
Here's an abstract helper method that does this. This assumes there is a partial with the name of item_fields which it will render.
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
You can use it like this. The arguments are: the name of the link, the parent's form builder, and the name of the association on the parent model.
<%= link_to_add_fields "Add Item", f, :items %>
And here is some CoffeeScript to listen to the click event of that link, insert the fields, and update the object id with the current time to give it a unique key.
jQuery ->
$('form').on 'click', '.add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
That code is taken from this RailsCasts Pro episode which requires a paid subscription. However, there is a full working example freely available on GitHub.
Update: I want to point out that inserting a child_index placeholder is not always necessary. If you do not want to use JavaScript to insert new records dynamically, you can build them up ahead of time:
def new
#project = Project.new
3.times { #project.items.build }
end
<%= f.fields_for :items do |builder| %>
Rails will automatically insert an index for the new records so it should just work.
So, I was not happy with the solution I saw most often, which was to generate a pseudo-index for new elements, either on the server or in client-side JS. This feels like a kludge, especially in light of the fact that Rails/Rack is perfectly capable of parsing lists of items so long as they all use empty brackets ([]) as the index. Here's an approximation of the code I wound up with:
# note that this is NOT f.fields_for.
fields_for 'parent[children_attributes][]', child, index: nil do |f|
f.label :name
f.text_field :name
# ...
end
Ending the field name prefix with [], coupled with the index: nil option, disables the index generation Rails so helpfully tries to provide for persisted objects. This snippet works for both new and saved objects. The resulting form parameters, since they consistently use [], are parsed into an array in the params:
params[:parent][:children_attributes] # => [{"name" => "..."}, {...}]
The Parent#children_attributes= method generated by accepts_nested_attributes_for :children deals with this array just fine, updating changed records, adding new ones (ones lacking an "id" key), and removing the ones with the "_destroy" key set.
I'm still bothered that Rails makes this so difficult, and that I had to revert to a hardcoded field name prefix string instead of using e.g. f.fields_for :children, index: nil. For the record, even doing the following:
f.fields_for :children, index: nil, child_index: nil do |f| ...
...fails to disable field index generation.
I'm considering writing a Rails patch to make this easier, but I don't know if enough people care or if it would even be accepted.
EDIT: User #Macario has clued me in to why Rails prefers explicit indices in field names: once you get into three layers of nested models, there needs to be a way to discriminate which second-level model a third-level attribute belongs to.
The common solution is to add a placeholder into [], and replace it with a unique number on inserting the snippet to the form. Timestamp works most of the time.
Maybe you should just cheat. Put the new records in a different faux attribute that is a decorator for the actual one.
parent[children_attributes][0][fieldname]
parent[new_children_attributes][][fieldname]
It's not pretty, but it should work. It might take some extra effort to support round-trips to the form for validation errors.
I've came across this user case in all my last proyects, and I expect this to continue, as julian7 pointed, it is necesary to provide a unique id inside the []. In my opinion this is better done via js. I've been dragging and improving a jquery plugin for dealing with this situations. It works with existing records and for adding new records but expects a certain markup and it degrades gracefully, heres the code and an example:
https://gist.github.com/3096634
Caveats for using the plugin:
The fields_for call should be wrapped in a <fieldset> with data-association attribute equal to the pluralized name of the model, and a class 'nested_models'.
an object should be built in the view just before calling fields_for.
the object fields perse should be wrapped in a <fieldset> with class "new" but only if the record is new (cant remember if I removed this requirement).
A checkbox for the '_destroy' attribute inside a label must exist, the plugin will use the label text to create a destroy link.
A link with class 'add_record' should exist within the fieldset.nested_models but outside the fieldset enclosing the model fields.
Appart from this nuisances its been working wonders for me.
After checking the gist this requirements must be clearer.
Please let me know if you improve on the code or if you use it :).
BTW, I was inspired by Ryan Bates first nested models screencast.
long post deleted
Ryan has an episode on this:
http://railscasts.com/episodes/196-nested-model-form-revised
It looks like you need to generate the unique index manually. Ryan uses the object_id for this.
I think you can make it work by including the id of the record as a hidden field
There is a gem called cocoon for doing this, I would go for a leaner mor DIY aproach but it was specifically built for this cases.