Strange error. Don't know what to ask....

Hi guys,

I'm puzzled by an error I'm getting in my app.

I have some declarations in my show method:

# GET /tabs/1 # GET /tabs/1.xml def show   @tab = Tab.find(params[:id])   @videos = Video.find(:all, :conditions => ["tab_id = ?", params[:id]])   @video = @tab.videos.build   @comment = @tab.comments.build

   respond_to do |format|     format.html # show.html.erb     format.xml { render :xml => @tab }   end end

I have objects called tab. Users can add comments and videos to tabs. From the show view I want to be able to create a video and comment. It goes fine for the videos. That's why the @tab.videos/comments.build are there.

Now. As said everything is ok with the videos.

In the view I have one part with this:

<p id="comment_list">   <% for comment in @tab.comments.reverse %>     <b><%=h comment.created_by %></b> <%=h comment.created_at.to_s(:short) %> <%=h comment.body %><br>   <% end %> </p>

So I can simply list the comments for a tab.

But but, when I have the line @comment = @tab.comments.build in the controller. I get the next error:

wrong number of arguments (1 for 0)

In the line: <b><%=h comment.created_by %></b> <%=h comment.created_at.to_s(:short) %> <%=h comment.body %><br>

The strange thing is that if I remove the .to_s(:short) in that line there is no problem.

I can't find a reason why the .to_s(:short) and @comment = @tab.comments.build cause that.

Do you have any hints?

Thanks.

That comment has yet to be saved and thus has no created_at. Well, to be precise, comment.created_at is nil. Now, NilClass#to_s exists, but takes no arguments. The Time#to_s has be redefined by ActiveSupport to take a format symbol. Your error is from a call to nil.to_s(:short)

In your view you could either test for nil? or do something like: <%= comment.new_record? ? '(unsaved)' : comment.created_at.to_s(:short) %> a test of comment.created_at.nil? would be an equally valid condition, but this seems more intention-revealing.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

comopasta Gr wrote:

  @comment = @tab.comments.build

At this point, @tab.comments now contains a new, uninitialised comment with nil valued attributes (including the timestamps).

comment.created_at.to_s(:short)

One of the comments is the above mentioned uninitialised one so for this one comment.created_at is nil which responds to #to_s but not with an argument.

If the @comment instance variable is there for a form, then use:

@comment = Comment.new

instead.

It’s probably because whatever object is being sent “to_s” isn’t the object you think it is.

It’s probably nil, which would mean to_s would work, but to_s(:short) won’t.

After you’ve built, created_at will be nil, which will set up the case that I just described.

Set an initial value for it in the controller, and all will be good.

@comment = @tab.comments.build(:created_at => Time.now)

or

@comment = @tab.comments.build; @comment.created_at = Time.now

Julian.

Learn Ruby on Rails! Check out the FREE VIDS (for a limited time) VIDEO #3 out NOW!

http://sensei.zenunit.com/

Ok. Now your comments helped me spotting an error in my code. The point is that in the same "show" view I can list the existing comments for that tab and also create a new comment for the tab. Separate issues.

So I use one object to read the existing ones: @comments = Comment.find(:all, :conditions => ["tab_id = ?", params[:id]])

And another to be able to create new one: @comment = @tab.comments.build