Comments on blogs

So I'm building a blog application using Ruby on Rails, and when it
comes to implementing comments I follow the example laid down in the
blog example screencast. I've run into the same problem as several
others; that I can't work out how I'm supposed to set parameters in my
comment creation method that aren't given to it by the form view. So my
comment controller has a method like this:

def create
    @post = Post.find(params[:id])
    @comment = @post.comments.create(params[:comment])
    @comment.datetime = Time.now # Doesn't work!
    @comment.user_id = @user.id # Doesn't work!
    if @comment.save
      flash[:note] = 'Comment was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
end

The post ID is established correctly, my relationships are set up as
they should be in my models, and the :comment params are being passed
successfully, but the two lines after I create my @comment instance
variable don't seem to have any effect. I'm getting database errors
saying there are NULL values where there shouldn't be.

The only solutions I've found are to pass the values I want as hidden
fields in my form (a security risk), or add them using :before_create
hooks. Am I missing something or can what I want not be done through
the controller?

hello,
i don´t know what went wrong with the @comment.datetime line, would have
to see your model/db for that.
but the @comment.user_id is pretty obvious.
if you store the user id in a session for example, you would have to do
something like this:

def create
  <snip>
  @user = User.find(:session["user_id"])
  @comment.user_id = @user.id
  <snip>
end

cheers,
alexander

revlob@gmail.com wrote:

I assume @post.comments.create() tries to save the the comment right
away, which fails because it isn't fully initialized.

AR tends to write updates as you manipulate associations, so you can't
really build the object graph in memory and then save/update it all
with a single call to save, as I (too?) assumed when I got started
with rails. :confused:

Either way, read your stack trace carefully, it tells you everything
you need to know about where things blow up.

If my guess is correct, try to create a free-standing comment first,
using Comment.new, then add it to the post once you've set all
required fields. (@post.comments << my_comment)

You could also try @post.comments.build() to create an associated
instance that isn't saved right away, but i think the former approach
is cleaner.

More info under ActiveRecord::Associations::ClassMethods in the API docs.

HTH,
Isak

Hey Isak, you're right that create() tries to save the object right
away, however, there's build, which doesnt save the object,
so you get a comment object back with the post association already in
filled, and you can then add further stuff and save it afterwards:

def create
    @post = Post.find(params[:id])
    @comment = @post.comments.build(params[:comment])
    @comment.datetime = Time.now # Doesn't work!
    @comment.user_id = @user.id # Doesn't work!
    if @comment.save
      flash[:note] = 'Comment was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
end

So changing create to build should do the trick, assuming @user already
exists by initializing it in the applications before_filter or some
other way ...
As a sidenote, i would prefer to allow the datetime property to be nil,
and have the Database set it with a default value if empty....

Isak Hansen wrote:

<snip>
If my guess is correct, try to create a free-standing comment first,
using Comment.new, then add it to the post once you've set all
required fields. (@post.comments << my_comment)

Ah, that approach helped:

@post = Post.find(params[:id])
@user = User.find(session[:user_id])
@comment = Comment.new(params[:comment])
@comment.datetime = Time.now
@comment.user_id = @user.id
@comment.post_id = @post.id

Works!

I hadn't realised the create method was trying to save the instance,
that's why my database was throwing up errors, because the INSERT was
getting called prematurely.

Also a good idea, I've edited my database schema so my timestamps
default to now().