I know there are a couple of different posts on here with folks trying to get their Rails 3 Forms with Nested Models to “work.” I’ve look at a bunch of them, including Subclass Isn’t Saving, and Nested Model with Polymorphic Association, along with watching Ryan Bates’ Railscasts on Nested Model Forms and his two tutorials on Complex Forms.
That said, I’m stumped as to why the Object in my form isn’t saving.
Here are my Models:
course.rb
class Course < ActiveRecord::Base
attr_accessible :course_name, :course_semester, :course_summary, :course_year, :objectives_attributes
has_many :objectives, as: :objectiveable
accepts_nested_attributes_for :objectives, :reject_if => lambda { |a| a[:objective].blank? }, :allow_destroy => true
objective.rb
class Objective < ActiveRecord::Base
attr_accessible :objective
belongs_to :objectiveable, polymorphic: true
My Form:
new.html.erb
<%= form_for [current_user, @course] do |course| %>
<%= course.label "Course Name" %>
<%= course.text_field :course_name, id:"course_name" %>
<%= course.label "Semester" %>
<%= course.select(:course_semester,[['Fall', 'Fall'], ['Spring', 'Spring'], ['Summer', 'Summer'], ['Winter','Winter']] ) %>
<%= course.label "Course Year" %>
<%= course.text_field :course_year, id:"course_year" %>
<p>Course Objectives</p>
<%= course.fields_for :objectives do |objective| %>
<%= objective.text_field :objective, name: "objective" %>
<% end %>
<%= course.label "Course Summary" %>
<%= course.text_area :course_summary, id:"course_summary" %>
<%= course.submit "Save and Return", name: "save_and_return" %>
<%= course.submit "Create a Unit", name: "course_to_unit" %>
<% end %>
My Controller:
courses_controller.rb
class CoursesController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def new
@course = current_user.courses.new
@course.objectives.build
end
def create
@course = current_user.courses.new(params[:course])
if @course.save && params[:save_and_return]
redirect_to user_path(current_user)
elsif @course.save && params[:course_to_unit]
redirect_to new_course_unit_path(@course)
else
flash[:notice] = "Sorry, there was a mistake with the form"
render 'new'
end
end
My Log:
test.log
Started POST "/users/1/courses" for 127.0.0.1 at 2012-11-27 22:23:00 -0500
Processing by CoursesController#create as HTML
Parameters: {"utf8"=>"✓", "course"=>{"course_name"=>"Physics 1", "course_semester"=>"Fall", "course_year"=>"2012", "course_summary"=>"This is a valid course summary."}, "objective"=>"An objective", "save_and_return"=>"Save and Return", "user_id"=>"1"}
[1m[36mUser Load (0.2ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1[0m
[1m[35m (0.0ms)[0m begin transaction
[1m[36mSQL (0.7ms)[0m [1mINSERT INTO "courses" ("course_name", "course_semester", "course_summary", "course_year", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?)[0m [["course_name", "Physics 1"], ["course_semester", "Fall"], ["course_summary", "This is a valid course summary."], ["course_year", 2012], ["created_at", Wed, 28 Nov 2012 03:23:00 UTC +00:00], ["updated_at", Wed, 28 Nov 2012 03:23:00 UTC +00:00], ["user_id", 1]]
[1m[35m (6.1ms)[0m commit transaction
Redirected to http://www.example.com/users/1
Completed 302 Found in 17ms (ActiveRecord: 7.0ms)
I can see the objective in the parameters hash in my log, but nothing is being inserted in the Objective table when the data is being committed. In my console, I’m able to create objectives using @course.objectives.create or @course.objectives.build, so I know the association is working (plus I’ve tested the models in Rspec). But I can’t figure out what I’m doing wrong here, at the Form level.
I should also note that I’m running this as a test in Rspec, which looks like this:
courses_pages_spec.rb
it "Adds at least one objective to the course" do
expect {
fill_out_course_form_with_valid_info
click_button save_button
}.to change(Course, :count).by_at_least(1)
Course.last.objectives.count.should == 1
end
Although I’ve also fired up Rails Server, input values in the form and get the same result.
Thanks in advance for your help.
So, the answer was way easier than I thought it’d be. In my Nested Form, I had the following:
It turns out that by defining “name” as “objective”, I was over-writing the default “name”, “course[objectives_attributes][0][objective]”, which is where/how the parameter is passed.
According to the Rails Docs,
The reason I had the “name” attribute in the first place was to give Capybara something to latch on to in my tests. Guess that wasn’t such a good idea 🙂
(What I did instead was use Firebug to figure out what the ID of the form field was and test against that instead.)