How to go about instantiating child model associations in controllers?
When I try to run my functional tests on a controller for a resource called "Programs", a majority of my tests result in a NoMethodError:
NoMethodError: undefined method `programs' for nil:NilClass
The Program resource has a belongs_to relationship on a Camp resource, which has_many programs. From my experience in researching this issue, everything works fine in the rails console, in the UI, and my model tests all pass.
Why am I getting this issue and how can I go about fixing it?
Here is the code I am using:
The Camp Model
class Camp < ActiveRecord::Base
has_many :contacts
has_many :sessions
has_many :programs
has_many :parents
has_and_belongs_to_many :campers
has_one :address, :as => :addressable
accepts_nested_attributes_for :address, :allow_destroy => true
validates :name, :presence => true
validates :uri, :presence => true, :uniqueness => true
validates :email_address, :email => true, :allow_nil => true
end
The Program Model
class Program < ActiveRecord::Base
belongs_to :camp
has_many :program_populations
has_many :sessions, :through => :program_populations
has_and_belongs_to_many :campers, :join_table => "campers_sessions_programs"
accepts_nested_attributes_for :program_populations
validates :camp, :presence => true
v开发者_JAVA百科alidates :name, :presence => true
validates :min_age, :presence => true, :numericality => {:only_integer => true}
validates :price, :presence => true, :numericality => true
end
Programs Controller Create Method
def create
@camp = Camp.find_by_uri(params[:camp_id])
@program = @camp.programs.build(params[:program]) #THIS IS THE PROBLEM AREA
respond_to do |format|
if @program.save
format.html { render :text => "program created!", :status => :created }
format.xml {render :xml => @program, :status => :created, :location => @program}
else
format.html { render :action => "new", :status => :bad_request }
format.xml { render :xml => @program.errors, :status => :bad_request }
end
end
end
My Test Case
test "should create program" do
assert_difference('Program.count') do
post :create, :program => {
:camp => camps(:bolo),
:name => "Test Program",
:min_age => 10,
:price => 100.00
}
end
assert_response :created
assert_not_nil assigns(:program)
get :show, :id => assigns(:program).to_param
assert_response :success
end
You're getting this error message because @camp
is nil
. This means that the actual failure is in the previous line, Camp.find_by_uri(params[:camp_id])
. Simply put, Rails can't find the camp.
Looking at your test, you're not actually passing param[:camp_id]
. Instead, you have a param[:program][:camp]
param, which (I assume) is the entire camp object. Change your test to this instead:
test "should create program" do
assert_difference('Program.count') do
post :create,
{:program => {
:name => "Test Program",
:min_age => 10,
:price => 100.00
},
:camp_id => camps(:bolo).id}
end
assert_response :created
assert_not_nil assigns(:program)
get :show, :id => assigns(:program).to_param
assert_response :success
end
And see if that works.
The reason your test is failing is that it can't find a @camp
.
Try passing this to your test
post :create, :program => {
:name => "Test Program",
:min_age => 10,
:price => 100.00
},
:camp_id => camps(:bolo).id
Also, maybe you mean to call Camp.find(params[:camp_id])
in your controller?
精彩评论