Ok so I have a few models that need to interact with each other -
Blog, Post, and User. I’ll get their relationships out of the way:
Blog
has_many :posts
has_and_belongs_to_many :users (by way of a join table, a blog can
have many contributing users)
Post
belongs_to :blog
belongs_to :user (the author of the post)
User
has_and_belongs_to_many :blogs (a user can contribute to many blogs)
has_many :posts
I’m running into a problem when validating posts; I want to ensure
that the logged in user we find in the session is listed as a
contributor to the blog they are trying to post to. I added some
validation to my Post model, that appears to be failing when editing
an existing post. Post creation, curiously, seems to pass the
validation test.
I should note that @user is a variable set by my ApplicationController
using a before_filter. really sure what’s going on here, so any help
is appreciated. I’m guessing the @user set by my app controller
probably isn’t accessible by the Post class.
Anyhow, here’s my Post model:
class Post < ActiveRecord::Base
belongs_to :blog
belongs_to :user
has_many :comments
validate :user_can_contribute
private
def user_can_contribute
if @user.nil?
logger.info("@user hasn’t been set yet!")
end
if !blog.users.include?(@user)
errors.add(:user, "You cannot contribute to this blog.")
end
So you need to create a method on your controller that will return the @user object. The convention for this method seems to be to call it
“current_user”.
ahem Of course… an instance of a model doesn’t have access to
application_controller’s methods… I was getting carried away with
myself.
You will also need to pass this to the Post directly… so declare
an “attr_writer :current_user” on your Post model, and in the
controller, when you instanciate the Post, pass it the variable:
post = Post.find(params[:post_id] # or whatever…
post.current_user = current_user
I should note that @user is a variable set by my ApplicationController
using a before_filter. really sure what’s going on here, so any help
is appreciated. I’m guessing the @user set by my app controller
probably isn’t accessible by the Post class.
Yup - you’ve identified your problem perfectly… here’s a suggested
solution:
@user is a instance variable; that is, only available to the instance
of a class (in this instance, the controller). So you can’t access it
from an instance of a different class.
So you need to create a method on your controller that will return the @user object. The convention for this method seems to be to call it
“current_user”.
def current_user @user
end
Simple, huh?
Now you can get rid of that before_filter call, and do the operation
when/if somewhere calls “current_user” - so it’ll look more like this:
def current_user @user ||= the_method_for_the_logic_that_works_out_the_logged_in_user
end
An other solution would be to use a wrapped-up plugin to do
authentication (there are lots to choose from), which would take all
you user/password management woes and deal with them for you (and most
likely give you a “current_user” method!)
HTH
Michael
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.