views:

1298

answers:

1

Can anyone tell me why the form at the end of this question isn't working like it should?

  • Save doesn't work
  • The select-helper doesn't select the value according to the object @kid

The whole thing is based on Rails 2.2.2 and no, upgrading to Rails 2.3 to solve this problem isn't an option. :-)

I used this recipe to build the multiple model form.

# 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 %>
+1  A: 

Well, correct me if I am wrong but it doesn't appear that you are actually saving the object anywhere. In your create and update actions you are calling new and then not saving it.

To rectify this you could 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 select box you are trying to find every record of Entity, not those fields of Entity that are related to @kid. In order to do this you'll have to set up a relationship between kid and grandparent.

# 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 a kid's grandparents through by @kid.grandparents. Then you can generate the select field:

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