There are a few strategies that work fairly well. You can have a call in the controller that staples the User on to the created comment:
def create
@comment = @post.comments.build(params[:comment])
@comment.user = session_user
@comment.save!
redirect_to(post_path(@post))
rescue ActiveRecord::RecordInvalid
# Take appropriate action, such as show comment create form
render(:action => 'new')
end
Another way is to use something like model_helper (http://github.com/theworkinggroup/model_helper/) to provide access to controller properties within the model environment:
class ApplicationController < ActionController::Base
# Makes the session_user method callable from the ActiveRecord context.
model_helper :session_user
end
class Comment < ActiveRecord::Base
before_validation :assign_session_user
protected
def assign_session_user
if (self.user.blank?)
self.user = session_user
end
end
end
This method is more automatic, but at the price of transparency and possibly complicating your unit test environment.
A third approach is to merge in the parameters on the create call:
@comment = @post.comments.build((params[:comment] || { }).merge(:user => session_user))
This has the disadvantage of not working very well if some of the properties of your model are protected, as they probably should be in any production environment.
Another trick is to create a class method that helps build things for you:
class Comment < ActiveRecord::Base
def self.create_for_user(user, params)
created = new(params)
created.user = user
created.save
created
end
end
This is called on the relationship and will build in the correct scope:
@comment = @post.comments.create_for_user(session_user, params[:comment])