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().