Newbie's problem with a nil object he didn't expect!

Dear Rubyists/Rails gurus,
Though I’ve successfully completed the various Rails tutorials online
and the Depot application from the Agile Web D. with Rails
book, I’m still pretty much a Ruby/Rails newbie. I’m trying to learn by
writing my own simple blogging application, but I’ve run into a problem
that has had me scratching my head for a few days now. I was wondering
if somebody might be able to help.

This is the error:

NoMethodError in Blog#friends_entries
ActionView::TemplateError (You have a nil object when you didn’t expect
it!
You might have expected an instance of Array.
The error occured while evaluating nil.each) on line #2 of
app/views/blog/_my_contacts.rhtml:
1:


2: <% for contact in @contacts %>

This is the method from the controller:
def contacts
@contacts = Contact.find(:all, :conditions => [“user_id = ?”,
@session[‘user’].id])
end

Some possible problems I considered:

  1. Can’t access the contacts table in the database? - I don’t think this
    is the case because I can access it in the console. a =
    Contact.find(:all), for example, works fine. HOWEVER,
    Contact.find(:all, :conditions => [“user_id = ?”, @session[‘user’].id])
    returns NoMethodError: You have a nil object when you didn’t expect it!
    You might have expected an instance of Array.
    The error occured while evaluating nil.[]
    from (irb):25
    from :0

  2. Session problem? - The session dump looks fine and the rest of the
    app that depends on the session works fine. I also tried running the app
    without the user id from the session, looking up records directly by
    their id, for example, @contacts = Contact.find(18,19), but that
    returned the same error.

  3. Can’t access model? - See #1. In the console–but not in the app, I
    can do Contact.find(:all) successfully.

  4. Can’t access method in controller? - Not sure. Per p.86 of Agile Web
    Development with Rails, I have added model :contact to application.rb

  5. Any conventions violated? - Nothing that I noticed!

Another thing that might have to do with it–though I’m not sure how–is
my database definition. I’ve been using the migrations feature with its
schema.rb, but I’ve noticed that you can’t impose foreign key
constraints using migrations or schema.rb. When I ran rake it generated
development_structure.sql, which allowed me to compare my new database
tables created using migrations against my old tables created using
create.sql. The ones created using create.sql show the foreign key
constraints but the contact table, which I created using the migrations
feature, doesn’t show any foreign key constraints. I assumed that
making the belongs_to and has_many declarations would make it all look
the same in the back end. Guess not. But again, I don’t know if this
has to do with my nil object problem.

I would really appreciate any suggestions.

Thank you!
Rick

rick wrote:

This is the method from the controller:
def contacts
@contacts = Contact.find(:all, :conditions => [“user_id = ?”,
@session[‘user’].id])
end

Hi Rick,

If you avoid the placeholder syntax and just have

:conditions => “user_id = #{@session[‘user’].id}”

does that work ?

Alan

Try this:

@contacts = Contact.find_all_by_user_id session[‘user’].id

(We’ll use a dynamic finder here instead of conditions.)

Also, you shouldn’t be using @session because it references a variable.
There’s a session method you should go through instead… see
http://weblog.rubyonrails.org/2006/4/25/use-params-not-params for more
information.

And if you still get no luck, show me your contacts table (migration),
the
code where you save your user object to session, and then show me your
contacts model.

Alan F. wrote:

rick wrote:

This is the method from the controller:
def contacts
@contacts = Contact.find(:all, :conditions => [“user_id = ?”,
@session[‘user’].id])
end

Hi Rick,

If you avoid the placeholder syntax and just have

:conditions => “user_id = #{@session[‘user’].id}”

does that work ?

Alan

Hi Alan,
Thanks for the help. I tried what you suggested, and here’s what
happened:

@contacts = Contact.find(:all, :conditions => “user_id =#{@session[‘user’].id}”)
NoMethodError: You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.[]
from (irb):3
from :0

One interesting thing is that if i do @contacts = Contact.find(:all,
:conditions => [“user_id = 2”])
it works in the console but not in the application, which returns the
same NoMethodError…nil object.

I wonder what’s going on. Let me know if you have another suggestion.
Thanks!
Rick

Hi Brian,
Thanks so much for the help. Please see below.

Brian H. wrote:

Try this:

@contacts = Contact.find_all_by_user_id session[‘user’].id

(We’ll use a dynamic finder here instead of conditions.)

@contacts = Contact.find_all_by_user_id session[‘user’].id
NameError: undefined local variable or method `session’ for
#Object:0x4ec91f8
from (irb):11
from :0

if I do it with @session

@contacts = Contact.find_all_by_user_id @session[‘user’].id
NoMethodError: You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.[]
from (irb):12
from :0

Also, you shouldn’t be using @session because it references a variable.
There’s a session method you should go through instead… see
http://weblog.rubyonrails.org/2006/4/25/use-params-not-params for more
information.

Thanks for the tip! I’ll keep that in mind.

And if you still get no luck, show me your contacts table (migration),

I had to run a few migrations before I got the table I wanted (my first
time with migrations–sorry!). First I added the table, then I got rid
of contact_id because I remembered that I get id for free, then I tried
to add a foreign key constraint, realized that I couldn’t and ended up
adding an index.

class AddContactsTable < ActiveRecord::Migration

def self.up
create_table :contacts do |t|
t.column :contact_id, :integer
t.column :contact_guid, :integer
t.column :contact_first_name, :string
t.column :contact_email, :string
t.column :user_id, :integer
t.column :in_address_book, :boolean
end
end

def self.down
drop_table :contacts
end

end

class RemoveContactId < ActiveRecord::Migration
def self.up
remove_column “contacts”, “contact_id”
end

def self.down
add_column “contacts”, “contact_id”, :integer
end
end

class AddFkToContacts < ActiveRecord::Migration
def self.up
remove_column :contacts, :user_id
add_column :contacts, “user_id”, :integer, :limit => 10, :default =>
0, :null => false
add_index “contacts”, [“user_id”], :name => “user_id_ind”
end

def self.down
remove_column :contacts, :user_id
add_column :contacts, “user_id”
remove_index :contacts, :name => :user_id_ind
end
end

So those are my embarassing migrations.

here’s what it looks like now in schema.rb:

create_table “contacts”, :force => true do |t|
t.column “contact_guid”, :integer
t.column “contact_first_name”, :string
t.column “contact_email”, :string
t.column “in_address_book”, :boolean
t.column “user_id”, :integer, :limit => 10, :default => 0, :null =>
false
end

add_index “contacts”, [“user_id”], :name => “user_id_ind”

the code where you save your user object to session,

I used the Salted Hash Login Generator. I thought it handles the
authentication stuff, including saving the user object to session. Is
there something else I need to do? Here’s the login method from the
generated user controller:

def login
return if generate_blank
@user = User.new(@params[‘user’])
if @session[‘user’] = User.authenticate(@params[‘user’][‘login’],
@params[‘user’][‘password’])
flash[‘notice’] = l(:user_login_succeeded)
redirect_back_or_default :controller => ‘blog’, :action => ‘index’
else
@login = @params[‘user’][‘login’]
flash.now[‘message’] = l(:user_login_failed)
end
end

and then show me your contacts model.

class Contact < ActiveRecord::Base
belongs_to :user, :foreign_key => “user_id”
end

The :foreign_key declaration is probably superfluous but it doesn’t seem
to make things worse.

Thanks!
Rick

Do you have any records in your table?

Brian H. wrote:

Do you have any records in your table?

Yes!