Re: Editing Multiple Models in One Form
Cool idea of using negative numbers for the index, I'll have to try that sometime.
You are not logged in. Please login or register.
Rails Forum - Ruby on Rails Help and Discussion Forum » Tutorials » Editing Multiple Models in One Form
Cool idea of using negative numbers for the index, I'll have to try that sometime.
Can you explain how you would put the form into a partial? I am having problems with the section
<% for @task in @project.tasks %>
<%= error_messages_for :task %>
<% fields_for "task[]" do |f| %>
<p><%= f.text_field :name %></p>
<% end %>
<% end %>
Great tutorial!
Thanks,
Dennis
Which part specifically are you attempting to move into a partial? The instance variables (@task or @project) should be accessible from the partial (I think). Are you not able to access them?
You could pass variables to the partial using the :locals parameter, however, some of these methods (such as error_messages_for) rely on the use of an instance variable instead of a local variable so it makes things a little more difficult. It's hard to say the best approach without knowing which part of the form you would like in the partial.
Anyone know the best way to combine the creating and editing multiple models into one form partial? I'm looking to be able to add multiple models in the form for the create action, then edit and/or add multiple models for the update action. Any help would be greatly appreciated.
I am using acts_as_attachment to upload 4 images and everything works great on that side. But I also want to be able to edit the form and the images. I have went through the tutorial but can not seem to get this to work. Does anyone know how I can go about doing this?
Thanks,
This was a helpful tutorial. However, when I ran my version of your code, I noticed in the development log that each part of the update query ran inside its own transaction. So the parent record got updated in one transaction and then each child record was updated inside its own transaction. What's the proper way to put the whole group into a single transaction?
Re: Transactions
From playing around with the code, this apparently will wrap everything into one transaction:
Project.transaction do
@project.save!
@project.tasks.each(&:save!)
end
Last edited by boone (2007-04-29 18:30:59)
Hello there,
Thank you for this great tutorial. It really helped me.
However I have a problem and I was wondering if you could help me.
I have 3 models. Scholar, Professor and Researcher. Scholar is related to the other models with many-to-many relationship and I want to update them all in one form. I'm a totally newbie and I don't know if I have followed the right way. The update function that I have built is:
def update
@scholar = scholar.find(params[:id])
@scholar.attributes = params[:scholar]
@scholar.researchers.each { |t| t.attributes = params[:researcher][t.id.to_s] }
@scholar.professors.each { |p| p.attributes = params[:professor][p.id.to_s] }@scholar.researchers.each(&:valid?)
@scholar.professors.each(&:valid?)
if @scholar.valid? && @scholar.researchers.all? { |t| t.errors.empty? } && @scholar.professors.all? { |p| p.errors.empty? }
@scholar.save!
@scholar.researchers.each(&:save!)
@scholar.professors.each(&:save!)
redirect_to :action => 'show', :id => @scholar
else
render :action => 'edit'
end
end
<% form_tag :action => 'update', :id => @scholar do %>
<%= render :partial => 'form1' %>
<% for @researcher in @scholar.researchers %>
<%= error_messages_for :researcher %>
<% fields_for "researcher[]" do |f| %>
<tr><td><br/><br/></td></tr>
<tr>
<td><div align="right">?????</div></td>
<td><div align="left"><%= f.text_field :name %></div></td>
</tr>
<tr>
<td><div align="right">???????</div></td>
<td><div align="left"><%= f.text_field :surname %></div></td>
</tr>
<tr>
<td><div align="right">???????</div></td>
<td><div align="left"><%= f.text_field :level %></div></td>
</tr>
<tr>
<td><div align="right">??????????</div></td>
<td><div align="left"><%= f.text_field :organisation %></div></td></tr>
<tr>
<td><div align="right">????????</div></td>
<td><div align="left"><%= f.text_field :phone %></div></td>
</tr>
<tr>
<td><div align="right">e-mail</div></td>
<td><div align="left"><%= f.text_field :email %></div></td>
</tr>
<% end %>
<% end %><% for @professor in @scholar.professors %>
<%= error_messages_for :professor %>
<% fields_for "professor[]" do |f| %>
tr><td><br/><br/></td></tr>
<tr>
<td><div align="right">?????</div></td>
<td><div align="left"><%= f.text_field :name %></div></td>
</tr>
<% end %>
<% end %><%= render :partial => 'form3' %>
<%= submit_tag 'Edit' %>
Thanks and sorry for my bad English ![]()
You are missing an opening bracket on the "tr" tag here:
<% fields_for "professor[]" do |f| %>
tr><td><br/><br/></td></tr>
<tr>
<td><div align="right">?????</div></td>
<td><div align="left"><%= f.text_field :name %></div></td>
</tr>
<% end %>
<tr><td><br/><br/></td></tr>
I've cut and pasted this entire tutorial, but get this error message:
Showing app/views/projects/edit.rhtml where line #13 raised:
Mysql::Error: Unknown column 'tasks.project_id' in 'where clause': SELECT * FROM tasks WHERE (tasks.project_id = 1)
10: </p>
11:
12: <h2>Tasks</h2>
13: <% for @task in @project.tasks %>
14: <%= error_messages_for :task %>
15: <% fields_for "task[]" do |f| %>
16: <p><%= f.text_field :name %></p>
How did you generate the tasks table? Does it have a project_id column?
sorry I didn't reply to you earlier. My problem has been solved.
Thanks
thanks for the response, and the great tutorial. I didn't have product_id added. Have you included your migrations somewhere, or explicitly indicated what the database should look like? If not, I think it might be an important addition which would complete your lessons nicely...perhaps I've just missed it...
The first, I assumed, looks like this:
class Projects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.column :project_id, :integer
t.column :name, :string
end
end
def self.down
drop_table :projects
end
end
....and the second, like:
class Tasks < ActiveRecord::Migration
def self.up
create_table :tasks do |t|
t.column :name, :string
end
end
def self.down
drop_table :tasks
end
end
....am I close?
Almost, the project_id column needs to go into the tasks table, not the projects table:
create_table :tasks do |t|
t.column :name, :string
t.column :project_id, :integer
end
I don't understand this line:
@project.tasks.each { |t| t.attributes = params[:task][t.id_to_s] }
The request has "params" hash. That hash contains an array of tasks. Hence, params[:task] refers to that array and the [t.id_to_s] indicates which task in the array. HOWEVER, the array indices should be 0 to # of tasks. It's not the task ID. That's why I don't understand why t.id_to_s would work.
For one, in my code, I get an error: undefined method `id_to_s` Secondly, if this is changed to id.to_s, it doesn't work either. What is the problem here?
Last edited by robertl (2007-07-07 20:56:43)
params[:task] is not an array, it is a hash. so params[:task]["1"] will give the Task with id=1. That's t.id.to_s not t.id_to_s.
@project.tasks.each checks for all the tasks of @project, so make sure all those tasks are available in the params[:task] hash.
Check your views if you have something like task[1][name].
Hi, I'm having a problem with my application when following the steps in the tutorial.
Basically I have this update method in my controller:
def update
@recipe = Recipe.find(params[:id])
@recipe.attributes = params[:recipe]
@recipe.directions.each { |d| d.attributes = params[:directions][d.id.to_s] }if @recipe.valid? && @recipe.directions.all?(&:valid?)
@recipe.save!
@recipe.directions.each(&:save!)
redirect_to :action => 'show', :id => @recipe
else
render :action => 'edit'
end
end
<p><label for = 'direction'>Directions</label><br/ ></p>
<table>
<% @recipe.directions.each_with_index do |direction, index| %>
<tr>
<% fields_for "directions[#{index}]", direction do |d| %>
<td><%= d.text_field :direction, :size => 80 %></td>
<% end %>
</tr>
<% end %>
I got the forms to work using this tutorial within my controller. But, I can't get the index action to work. I can't figure out if my problem is in the controller or the view. How would one make this @project.tasks display in the index?
The author of this series of tutorials is a life saver. I would like to show you all what my update method looks like and its helper methods
Here is the update method.
----------------------------
def update
@person = Person.find(params[:id])
@person.attributes = params[:person]
redefine_save_to_destroy_removed_associations(params, @person, :emails)
redefine_save_to_destroy_removed_associations(params, @person, :phone_numbers)
redefine_save_to_destroy_removed_associations(params, @person, :addresses)
update_existing_associations(params, @person, :emails)
update_existing_associations(params, @person, :phone_numbers)
update_existing_associations(params, @person, :addresses)
build_populated_associations(params, @person, :emails, [:address])
build_populated_associations(params, @person, :phone_numbers, [:phone_number])
build_populated_associations(params, @person, :addresses, [:street1, :street2, :city, :zip])
if @person.valid?
Person.transaction do
@person.save!
@person.emails.each(&:save!)
@person.addresses.each(&:save!)
@person.phone_numbers.each(&:save!)
end
redirect_to :action => 'show', :id => @person
elsif
render :action => 'edit'
end
end
def build_populated_associations(params, model, association, fields)
singular = Inflector.singularize(association)
unless params[singular].nil?
params[singular].delete_if do |key, value|
blanks = fields.collect { |field| value[field].blank? }
!blanks.include?(false)
end
params[singular].each_value do |value|
model.send(association).build(value) if value[:id].blank?
end
end
end
def update_existing_associations(params, model, association)
singular = Inflector.singularize(association)
model.send(association).each do |assoc|
attrs = assoc.attributes
unless params[singular].nil?
params[singular].each_value do |value|
if value[:id] == assoc.id.to_s
attrs = value
break
end
end
assoc.attributes = attrs
end
end
end
def redefine_save_to_destroy_removed_associations(params, model, association)
singular = Inflector.singularize(association)
param_ids = []
unless params[singular].nil?
param_ids = params[singular].values.collect do |value|
value[:id]
end
end
model.send(association).each do |a|
id = a.id.to_s
unless param_ids.include?(id)
def a.save!
destroy
end
end
end
end
Last edited by jwheeler (2007-07-20 23:10:39)
I'm having this exact same problem. Anyone know what is happening here?
Hi, I'm having a problem with my application when following the steps in the tutorial.
Basically I have this update method in my controller:
def update
@recipe = Recipe.find(params[:id])
@recipe.attributes = params[:recipe]
@recipe.directions.each { |d| d.attributes = params[:directions][d.id.to_s] }if @recipe.valid? && @recipe.directions.all?(&:valid?)
@recipe.save!
@recipe.directions.each(&:save!)
redirect_to :action => 'show', :id => @recipe
else
render :action => 'edit'
end
end
And this is how my view looks:<p><label for = 'direction'>Directions</label><br/ ></p>
<table>
<% @recipe.directions.each_with_index do |direction, index| %>
<tr>
<% fields_for "directions[#{index}]", direction do |d| %>
<td><%= d.text_field :direction, :size => 80 %></td>
<% end %>
</tr>
<% end %>
I am able to save a list of directions, but when trying to update or add new directions to an existing list, nothing ever gets updated. I checked the SQL statements in the log and it only seems to be updating the list with the old contents. I've spent a while playing around with this, but I don't know what's going on or how to debug it. Any help would be greatly appreciated!
Hosting provided by aTech Media