Re: Creating Variable Number of Models in One Form

I figured it out, and I'm able to add a new phone number.  I had a naming problem in my model.  After the new phone number field appears, I am getting a javascript popup error now that says:

RJS Error:

TypeError: element has no properties


Then, the output of the new Insertion.Bottom javascript appears in another popup after I click OK. 

Any idea what I can do to eliminate the javascript error?

Re: Creating Variable Number of Models in One Form

Hmm, what browser are you using? You might want to try FireBug in Firefox for debugging these javascript issues.

I'm wondering which "element" it is referring to. You might want to try using divs instead of table elements since some browsers don't like replacing parts of a table.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

I think the index isn't incrementing properly either because every time I click "Add another", the index remains at 2.

Re: Creating Variable Number of Models in One Form

Hmm, sounds like the link isn't getting updated. You may want to try a different browser and see if it behaves any differently.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

Thank you for the excellent tutorial.  It works wonderfully with a has many/belongs to association between tasks and project.

I am unable to get this to work on a has many through (many to many) association.  How can I build tasks from projects through say an "assignment" association table?

Last edited by usernameallan (2007-05-21 12:05:52)

Re: Creating Variable Number of Models in One Form

You'll need to create the Assignment model at the same time you build the Task. Sorry I can't post any code at the moment. If you post this in a separate thread and go into more detail I may be able to post some code.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

The problem I'm having is with collection_select, when there is a validation error,the controller renders back the view, but the selected drop down is not the one i've selected before, it defaults back to the first value.

It only happens in the build model(eg. task) not the main one(eg. project). Is there fix?

Re: Creating Variable Number of Models in One Form

Hmm, it should default to the proper value. Can I see the code?

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

Thank you for replying ryanb, it was the data type problem. i was going for a male and female collection_select and using tinyint, when i change it to int then can it default back to the proper value.

Another quick question if i wanna do simple yes/no select for the build model, can i do it without doing a table in mysql for just yes and no. i've done a simple select yes/no in the view but when it renders back, the value defaults back to the first value.

Thank you.

Last edited by nobit (2007-06-06 23:11:17)

Re: Creating Variable Number of Models in One Form

If you don't have a model/table backing the select menu, you should use select_tag and options_for_select like this:

<%= select_tag :foo, options_for_select(['Yes', 'No'], params[:foo]) %>

Notice the params[:foo]? That should default the select box to whatever value was previously selected.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

Is it possible to implement the following structure:

Project has many task. Task has many resources and resources has whatever.

Build a tree like structure where project, task and resource are different models and create a variable number of all of them with technique showed in the tutorial ?

Re: Creating Variable Number of Models in One Form

Yes, it's possible. But you'd have to adjust a few things. You'll need to nest fields_for for the resources and mention the task in that nesting as well:

<% task.resources.each_with_index do |task, resource_index| %>
  <% fields_for "tasks[#{task_indexindex}][resources][#{resource_index}]", resource do |r| %>
  #...

Then you'll be able to loop through the resources for each task in the resulting controller. Sorry it's too complicated to post a full code snippet.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

Thanks for the hint in the right direction. I forgot the nesting in "task...[resources]". I did not expect a complete solution but I may come again with some further questions.. wink

Re: Creating Variable Number of Models in One Form

This error has caused me some frustration, so I thought I would post more info about it here.

The following works just fine and displays the field.

    <% fields_for("anything_and_everything", nil) do |f| -%>
    <%= f.text_field(:id) %>
    <% end -%>

However, change it to this:
    <% fields_for("anything_and_everything[0]", nil) do |f| -%>
    <%= f.text_field(:id) %>
    <% end -%>

And you get this:

`@anything_and_everything[0]' is not allowed as an instance variable name

If, the object passed into the helper function is nil and you are trying to use an array for the first argument, object_name, then you will get the error. This usually happened because of errors in the model or my forgetting to instantiate the object in the add_anything_and_everything function in the controller. Hopefully this info will save some people time debugging.

Re: Creating Variable Number of Models in One Form

So making sure the nested object is not nil does not fix the error:

`@anything_and_everything[0]' is not allowed as an instance variable name

I have a similar object:

@resume.education_histories[0].address

But in my case, I'm doing a deeper nesting of objects with a mix of collections.
My model:
class Resume < ActiveRecord::Base
  has_and_belongs_to_many :education_histories
end

class EducationHistory < ActiveRecord::Base
  has_and_belongs_to_many :resumes
  has_one :address
end


In my controller I have
def new
  @resume = Resume.new
  @resume.education_histories << EducationHistory.new(:address=>Address.new)
end

In my view I have:
<% @resume.education_histories.each_with_index do |education_history,index| %>
<% fields_for "resume.education_histories[#{index}]", education_history do |education_history_fields| %>
.... education history fields...
       
<% fields_for "resume.education_histories[#{index}][address]", education_history.address do |address_fields| %>
<p>
Street 1:<br/>
<%= address_fields.text_field :street_1 %>
</p>
<% end -%>

<% end -%>
<% end -%>


So, this doesn't appear to work, even after I specifically assign the address to the new education_history object in the zeroth position of my people collection. Anyone have any ideas?

Re: Creating Variable Number of Models in One Form

Are you getting this error on the initial form page or only after submitting the form?

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

ryanb wrote:

Are you getting this error on the initial form page or only after submitting the form?

It was on the initial form page. However, I changed up a few things (trial and error) and now I don't have that issue. I'm instead (of course) having another problem building the object arrays from the form in the controller. It all stems from how the naming in my fields_for tag is. To me, nothing seems clear on this.
So if I have a field tag that looks like this:

<% fields_for 
"resume.education_histories[#{index}][address]",
@resume.education_histories[index].address do |@address_fields| %>

I get an address input tag like so:
<input id="resume.education_histories[0][address]_street_1"
name="resume.education_histories[0][address][street_1]" size="30" type="text" />

But, if I look how the form params were submitted, I don't get the proper object graph set up and instead have params like this for the resume histories (dunno why the left '[' char gets dropped):
resume.education_histories"=>
{"0].[end_date(2i)"=>"6", "0].[degree_level"=>"-- Please select --", "0].[key_achievements"=>"",
"0].[end_date(3i)"=>"19",
"0].[start_date(1i)"=>"2007", "0].[start_date(2i)"=>"6",
"0].[start_date(3i)"=>"19", "0"=>{"address"=>{"city"=>"", "zip"=>"",
"street_1"=>"", "country"=>"United States", "street_2"=>"", "state"=>""}}

and params like this for the parent resume object:
"resume"=>
{"dreamjob_status"=>"Full time", "dreamjob_description"=>"",
"dreamjob_title"=>"", "html_resume_link"=>"", "title"=>""}

Clearly, the education_histories should be nested properly in the resume object *and* the address should be nested properly in each education_histories obj.
The error Rails comes back with is

You have a nil object when you didn't expect it!
The error occured while evaluating nil.each_value

I've been playing around with different fields_for names with no luck yet.

Re: Creating Variable Number of Models in One Form

After more playing, here's what I has so far after another change.

Controller:

def create
    @resume = Resume.new(params[:resume])
    params[:education_histories].each_value { |history| @resume.education_histories.build(history) }
end

View:
<% fields_for "education_histories[#{index}][address]",
@resume.education_histories[index].address do |@address_fields| %>
<%= render :partial => 'address'%>
<%end -%>

Relevant params:
"education_histories"=>{"0"=>{"end_date(3i)"=>"19", 
"start_date(1i)"=>"2007", "start_date(2i)"=>"6",
"start_date(3i)"=>"19", "degree_level"=>"-- Please select --",
"key_achievements"=>"", "address"=>{"city"=>"", "zip"=>"",
"street_1"=>"", "country"=>"United States",
"street_2"=>"", "state"=>""}, "end_date(1i)"=>"2007",
"end_date(2i)"=>"6"}}}

So the params look correct now and it seems like the problem is in how I'm doing the build in the controller. The error I'm getting is now:

Address expected, got HashWithIndifferentAccess

Maybe I should try the build() differently...?

Re: Creating Variable Number of Models in One Form

Try this:

<% fields_for
"resume[education_histories][#{index}][address]",
@resume.education_histories[index].address do |@address_fields| %>

Also make sure there's no missing open/close square brackets in any of the names. Hopefully that will format it properly in the params.

Edit: nevermind. You have it right in your last post. Instead try creating an accessor method in the education histories model to handle the address:

# in EducationHistories
def address_attr=(attributes)
  build_address if address.nil?
  address.attributes = attributes
end

Then change the name to match this:

<% fields_for
"education_histories[#{index}][address_attr]",
@resume.education_histories[index].address do |@address_fields| %>

Last edited by ryanb (2007-06-19 14:34:20)

Railscasts - Free Ruby on Rails Screencasts

Re: Creating Variable Number of Models in One Form

Thanks, so now the params look like they're created properly - I get the whole graph from the resume object down. However, my controller now doesn't seem to like this and I get this error:

EducationHistory expected, got Array

In my controller, I'm using just this line now

@resume = Resume.new(params[:resume])

The stack for the objects looks like it's traversing correctly and I can see an attempt to call the education_histories method:

... /active_record/associations/association_proxy.rb:134:in `raise_on_type_mismatch'
... /activerecord-1.14.4/lib/active_record/associations/association_collection.rb:118:in `replace'
... /activerecord-1.14.4/lib/active_record/associations/association_collection.rb:118:in `replace'
... /activerecord-1.14.4/lib/active_record/associations.rb:895:in `education_histories='
....

So, I can't figure out why it's not creating each EducationHistory object from the array submitted in the params.