Object lost in memory/trashed?

Hi,

I've got a problem on which I've spent many hours, and I can't get a
clue on what is happening... I hope someone here will be able to help
me.

Here is the situation : my Rails app uses acts_as_commentable and
acts_as_bookmarkable on a Diagram model. Everything's working OK
individually: I can create a comment on a Diagram, bookmark it, and so
on.
Now, I'd like to have a list in the "show" view of a diagram, which
shows all comments and a line per bookmark saying something like "John
added this diagram as a favorite".

I've got an action in a comments controller fetching the data:
    # Get bookmarked class from params and fetch the wanted instance
    model_class =
Kernel.const_get(params[:commentable][:type].capitalize)
    instance = model_class.find params[:commentable][:id]
    report_error("Cannot find " << model_class.to_s << " with id " <<
params[:commentable][:id].to_s) if instance.nil?
    @comments = instance.comments

    # Include bookmarks if model is bookmarkable, and sort bookmarks and
comments all together
    if
BookmarksController::BOOKMARKABLE_MODELS.include?(model_class.to_s)
      @comments += instance.bookmarks
      @comments = @comments.sort_by {|obj| obj.created_at}
    end

So I fetch all comments for the commentable model (Diagram in my
example), then add the bookmarks to the collection and sort everything
by creation date. This works fine.

I'm displaying this list with a view and some partials:

## index.html.haml
= render :partial => "comment", :collection => @comments

## _comment.html.haml (called for each item in @comments)
= debug comment
= debug comment.user

-# The 'comment' might be a bookmark. Handle it first.
- if comment.instance_of?(Bookmark)
  .bookmark
    = render :partial => "/comments/comment_bookmark", :locals => {
:bookmark => comment }
- else
  .comment{:class => cycle("odd", "even")}
    = render :partial => "/comments/comment_content", :locals => {
:comment => comment}

## _comment_bookmark.html.haml
= image_tag "/images/iLight/icon.png"
== #{bookmark.user.display_name} lit this diagram
<small>(#{time_ago_in_words bookmark.created_at} ago)</small>

The problem happens in this last file, when calling
bookmark.user.display_name. It raises a Template error:
ActionView::TemplateError (You have a nil object when you didn't expect
it!
You might have expected an instance of Array.
The error occurred while evaluating nil.include?) on line #2 of
app/views/comments/_comment_bookmark.html.haml:
1: = image_tag "/images/iLight/icon.png"
2: == #{bookmark.user.display_name} lit this diagram
<small>(#{time_ago_in_words bookmark.created_at} ago)</small>

First thing, I just can't see where does this "include?" call comes from
:\
I've tried calling other attributes/methods on bookmark.user and never
get any error. If I just try to output bookmark.user it works and
displays "#".

As you can see, I've got two debug calls in my view.
When the partial is called for a Comment, debug displays the following:
--- !ruby/object:Comment
attributes:
  comment: pouet
  created_at: 2010-10-11 00:44:02
  title: ""
  commentable_type: Diagram
  commentable_id: "29"
  updated_at: 2010-10-11 00:44:02
  id: "41"
  user_id: "2"
attributes_cache:
  created_at: 2010-10-11 00:44:02 Z

--- !ruby/object:User
attributes:
  created_at: 2010-05-23 18:31:02
  activated_at: 2010-06-08 22:23:19
  send_news: "1"
  remember_token_expires_at:
  updated_at: 2010-09-19 22:36:42
  activation_code:
  old_email:
  id: "2"
  saved_once: "1"
  email_hash: 672585615_3008d2bf2e8e7f4455d48212f99a9343
  remember_token:
  short_name: olance
  diagrams_count: "16"
  display_name: Olivier Lance
attributes_cache: {}

When it's a Bookmark object, it displays:
--- !ruby/object:Bookmark
attributes:
  bookmarkable_type: Diagram
  bookmarkable_id: "29"
  created_at: 2010-10-11 01:18:41
  title: new items
  updated_at: 2010-10-11 01:18:41
  id: "253"
  user_id: "2"
attributes_cache:
  created_at: 2010-10-11 01:18:41 Z

#<User id: 2, created_at: "2010-05-23 18:31:02", updated_at: "2010-09-19
22:36:42", remember_token: nil, remember_token_expires_at: nil,
activation_code: nil, activated_at: "2010-06-08 22:23:19", email_hash:
"672585615_3008d2bf2e8e7f4455d48212f99a9343", display_name: "Olivier
Lance", short_name: "olance", send_news: true, saved_once: true,
diagrams_count: 16, old_email: nil, changed_email: nil>

I'm suspicious about this difference in the User object output.
When I restart my dev server (Mongrel) and refresh the page, the output
for the Bookmark's user looks exactly like the comments ones, and
bookmark.user.display_name doesn't raise any error.
Then, if I refresh the page again, I get the above output and the
TemplateError exception.

I've tried to debug using ruby-debug, but couldn't succeed in breaking
on TemplateError or NoMethodError exceptions....
I've just spent hours on this, I really don't get and don't have a lot
of experience in dealing with that kind of issues...
I'd really appreciate if someone had an idea on how to fix this or at
least to track the bug down!

By the way, I'm using Rails 2.3.8 with Ruby 1.8.7

Thanks a lot for reading this and for any help!
Olivier
Olivier

Sorry there's a mistake in my previous post:

Olivier Lance wrote:

First thing, I just can't see where does this "include?" call comes from
:\
I've tried calling other attributes/methods on bookmark.user and never
get any error. If I just try to output bookmark.user it works and
displays "#".

I don't know what I had in mind... this should read:

I've tried calling other attributes/methods on bookmark.user and **always
get the same error**. If I just try to output bookmark.user it works and
displays "#".

Hope somebody can help!
Olivier

I've tried to debug using ruby-debug, but couldn't succeed in breaking
on TemplateError or NoMethodError exceptions....
I've just spent hours on this, I really don't get and don't have a lot
of experience in dealing with that kind of issues...
I'd really appreciate if someone had an idea on how to fix this or at
least to track the bug down!

Does still happen in production mode? If it doesn't then you've got a
class reloading issue.

Fred

Frederick Cheung wrote:

Does still happen in production mode? If it doesn't then you've got a
class reloading issue.

Fred

Oh okay, thanks!
That's actually part of a feature currently in development so I haven't
tried it in production yet. I'll try that and check that.

I've just found an old topic where you mentioned this too, and it seems
it's the exact same problem (http://www.ruby-forum.com/topic/209224)…
The ticket mentioned in this post by the OP was last updated one week
ago, and it seems nothing's been really settled yet… should I just set
cache_classes=true ? …

Olivier

Frederick Cheung wrote:
> Does still happen in production mode? If it doesn't then you've got a
> class reloading issue.

> Fred

Oh okay, thanks!
That's actually part of a feature currently in development so I haven't
tried it in production yet. I'll try that and check that.

Just setting cache_classes = true is enough for the purpose of this.
You're probably hitting this because you're bypassing the rails code
loading stuff. You might try using the constantize method provide by
rails rather than rolling your own or (depending on the nature of the
problem) you might want to mark some of the plugins you're using as
reloadable (most issues like this occur when a non reloading plugin
ends up hanging on to reloadable bits of your app)

Fred

Thanks Fred for this help!
I can confirm now the problem was indeed a class reloading issue...

My solution here was to move bookmark.rb out from acts_as_bookmarkable
plugin directory to my models directory, just like it's done with
acts_as_commentable... doing so, the model is reloaded correctly without
having to put any "trick" in place :slight_smile:

But thanks to you I've found many resources about this issue and several
possible solutions, just in case I would stumble upon that again!

so many thanks again :slight_smile:
Olivier