Model validation dependent upon session data being set?

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   end end

Actually, I'm not so sure if post creation is passing the validation test either :slight_smile:

Sorry for being confusing.

Have you tried using ruby-debug to break into the validation code and see what is happening? See the rails guide on debugging at

Colin

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? :wink: 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

*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

Hey, that did the trick. Thanks for that!