Problem with has_many :through association

I have the following models

  1. class Caregiver < ActiveRecord::Base
  2. has_many :call_orders
  3. has_many :users, :through => :call_orders
  4. end
  5. class User < ActiveRecord::Base
  6. has_many :call_orders, :order => :position
  7. has_many :caregivers, :through => :call_orders
  8. end
  9. class CallOrder < ActiveRecord::Base
  10. belongs_to :user
  11. belongs_to :caregiver
  12. acts_as_list :scope => :user
  13. end

When I run the following commands, I get an error:

  1. @call_list = User.find(params[:id])
  2. @call_list.call_orders.each do |call_order|
  3. puts call_order.caregiver.first_name

This is the error:

You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.first_name

chirag wrote:

  1. end
  2. @call_list = User.find(params[:id])
  3. @call_list.call_orders.each do |call_order|
  4. puts call_order.caregiver.first_name

This is the error:

You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.first_name

What do your tables/migrations look like?


Michael W.

class CreateCaregivers < ActiveRecord::Migration
def self.up
create_table :caregivers do |t|
t.column :first_name, :string
t.column :last_name, :string
t.column :address, :string
t.column :city, :string
t.column :state, :string
t.column :home_phone, :string
t.column :work_phone, :string
t.column :cell_phone, :string
t.column :relationship, :string
t.column :email, :string
end
end

def self.down
drop_table :caregivers
end
end

class CreateCallOrders < ActiveRecord::Migration
def self.up
create_table :call_orders do |t|
t.column :user_id, :integer
t.column :caregiver_id, :integer
t.column :position, :integer
end
end

def self.down
drop_table :call_orders
end
end

class CreateUsers < ActiveRecord::Migration
def self.up
create_table “users”, :force => true do |t|
t.column :login, :string
t.column :email, :string
t.column :crypted_password, :string, :limit => 40
t.column :salt, :string, :limit => 40
t.column :created_at, :datetime
t.column :updated_at, :datetime
t.column :remember_token, :string
t.column :remember_token_expires_at, :datetime

  t.column :activation_code, :string, :limit => 40
  t.column :activated_at, :datetime
end

end

def self.down
drop_table “users”
end
end

Thanks for the help!
Chirag

Migrations look fine and it’s working for me:

call_list = User.find(1)
=> #<User:0x3447480 @attributes={“salt”=>nil, “activated_at”=>nil,
“updated_at”=>“2007-10-03 22:25:01”, “crypted_password”=>nil,
“activation_code”=>nil, “remember_token_expires_at”=>nil, “id”=>“1”,
“remember_token”=>nil, “login”=>“test”, “created_at”=>“2007-10-03
22:25:01”, “email”=>nil}>

call_list.call_orders.each do |call_order|
?> puts call_order.caregiver.first_name

end
John

call_list.call_orders[0].caregiver
=> #<Caregiver:0x3441634 @attributes={“work_phone”=>nil, “city”=>nil,
“id”=>“1”, “relationship”=>nil, “cell_phone”=>nil, “home_phone”=>nil,
“first_name”=>“John”, “address”=>nil, “last_name”=>“Smith”,
“email”=>nil, “state”=>nil}>

My guess is you have some bad data somewhere.


Michael W.

Im agree with Michael.

Btw, you can improve your code with a nested :include option like
this:
@call_list = User.find(params[:id], :include => [ { :call_orders
=> :caregiver } ])

Take a look at this: http://snippets.dzone.com/posts/show/2089 for a
better
explanation.

Regards.
Pablo C…

On 3 Oct 2007, at 02:50, chirag wrote:

You have a nil object when you didn’t expect it!
The error occurred while evaluating nil.first_name

Is that just the way the data is? caregiver is belongs_to of
callorder: call_order.caregiver can be nil (unless you’ve got other
contraints that forbid it)

Fred

Is that just the way the data is? caregiver is belongs_to of
callorder: call_order.caregiver can be nil (unless you’ve got other
contraints that forbid it)

Freederick mades a good point here. If nil values are accepted as your
model definition suggests, then you should use a “compacted” list of
caregivers like:

@call_list.call_orders.collect(&:caregiver).compact.each do |
caregiver|
puts caregiver.first_name
end

if nil values are not accepted you should add valitadates_presence_of
and validates_associated to force a caregiver to be present:

class CallOrder < ActiveRecord::Base
belongs_to :user
belongs_to :caregiver
acts_as_list :scope => :user

validates_presence_of :caregiver_id
validates_associated :caregiver
end

Regards
Pablo C…