Rails: creating a form of several models at n levels of association

Can someone tell me why the form at the end of this question is not working as it should?

  • Save does not work.
  • Select helper doesn't select value according to @kid object

All this is based on Rails 2.2.2 and no, upgrading to Rails 2.3 to solve this problem is not an option. :-)

I used this recipe to create a diverse model shape.

 # CLASS GRANDPARENT class Grandparent < ActiveRecord::Base has_many :parents end # CLASS PARENT class Parent < ActiveRecord::Base belongs_to :grandparent, :class_name => "Grandparent", :foreign_key => "grandparent_id" has_many :kids end # CLASS KID class Kid < ActiveRecord::Base belongs_to :parent, :class_name => "Parent", :foreign_key => "parent_id" # Virtual attribute setter for new self.parent.grandparent (Grandparent) attributes def new_grandparent_attributes=(_gp_attributes) self.parent.build_grandparent(_gp_attributes) end # Virtual attribute setter for existing self.parent.grandparent (Grandparent) attributes def existing_grandparent_attributes=(_gp_attributes) unless self.parent.grandparent.new_record? attributes = _gp_attributes[self.parent.grandparent.id.to_s] if attributes self.parent.grandparent.attributes = attributes else self.parent.grandparent.delete(grandparent) end end end end # CONTROLLER KIDS class KidsController < ApplicationController def new @kid = Kid.new end def edit @kid = Kid.find(params[:id]) end def create params[:kid][:new_grandparent_attributes] ||= {} @kid = Kid.new(params[:kid]) end def update params[:kid][:existing_grandparent_attributes] ||= {} @kid = Kid.find(params[:id]) end end # THIS IS THE MULTI-MODEL FORM USED IN THE VIEW <% form_for(@kid) do |f| %> <p> <% new_or_existing = @kid.parent.grandparent.new_record? ? 'new' : 'existing' %> <% prefix = "kid[#{new_or_existing}_grandparent_attributes][]" %> <% fields_for prefix, @kid.parent.grandparent do |g_f| -%> <p> <%= g_f.label :, 'Grandparent Name' %><br /> <!-- THE FOLLOWING FORM DOESN'T CHANGE ACCORDING TO EXISTING @child --> <%= @grandparents = Entity.find(:all, :order => :name) g_f.collection_select(:name ,@grandparents, :id, :name) %> </p> <% end %> </p> <p> <%= f.label :name, "Kid Name" %><br /> <%= f.text_field :name %> </p> <%= submit_tag 'Go' %> <% end %> 
+4
source share
1 answer

Ok, correct me if I'm wrong, but it doesn't seem like you are actually saving the object anywhere. In your create and update actions, you call new and then do not save it.

To fix this, you can do:

 def create params[:kid][:new_grandparent_attributes] ||= {} @kid = Kid.new(params[:kid]) if @kid.save # successful save logic here else #failed save logic here end end def update params[:kid][:existing_grandparent_attributes] ||= {} @kid = Kid.find(params[:id]) if @kid.update_attributes(params[:kid]) #successful save logic here else #failed save logic here end end 

Then, in your selection field, you try to find each Entity entry, not the Entity fields that are associated with @kid. To do this, you will need to establish a relationship between the child and grandparents.

 # CLASS GRANDPARENT class Grandparent < ActiveRecord::Base has_many :parents has_many :grand_kids, :through => :parents end # CLASS PARENT class Parent < ActiveRecord::Base belongs_to :grandparent, :class_name => "Grandparent", :foreign_key => "grandparent_id" has_many :kids end # CLASS KID class Kid < ActiveRecord::Base belongs_to :parent, :class_name => "Parent", :foreign_key => "parent_id" belongs_to :grandparent # ... 

This way you can access your @kid.grandparents through @kid.grandparents . Then you can generate a selection box:

 <%= g_f.collection_select(:name ,@kid.grandparents, :id, :name) %> 
+1
source

All Articles