Search code examples
ruby-on-railsjsonrespond-to

At the controller level, how to prevent an anonymous user from posting?


The following is a standard posts#create action (app/controllers/posts_controller.rb).

At the controller level, I want to prevent an anonymous user (a user who is not signed in) from being able to save a post. As a secondary objective, I don't even want to execute the Post.new line if the user is not signed in. I want to know what is the best practice for accomplishing this.

Also, as a side note, I am unsure of how to write the json portion of the response. If I am redirecting with an alert message in the HTML context, what would be a good thing to respond with in JSON world?

def create

  @posting = Post.new(posting_params)

  respond_to do |format|

    if @posting.save
      format.html { redirect_to @posting, notice: 'Post was successfully created.' }
      format.json { render action: 'show', status: :created, location: @posting }
    else
      format.html { render action: 'new' }
      format.json { render json: @posting.errors, status: :unprocessable_entity }
    end
  end
end

For the time being I have the following line in my code, above the Post.new line:

redirect_to home_path, warning: 'You must be logged in to post.' and return unless user_signed_in?

I suppose another option is something like the following, placed above the if @posting.save line. But really, I am looking to see what other folks would do.

unless user_signed_in?
    format.html { redirect_to home_path, alert: 'You must be logged in to post.' and return }
    format.json { render json: .....not sure what to put here..... }
end

Your advice is greatly appreciated.


Solution

  • A before_filter is good for this sort of thing:

    before_filter :confirm_user_signed_in, only: [:new, :create]
    
    def confirm_user_signed_in
      unless user_signed_in?
        respond_to do |format|
          format.html { redirect_to home_path, alert: 'You must be logged in to post.' and return }
          format.json { render json: .....not sure what to put here..... }
        end
      end
    end
    

    As far as what to render in the JSON scenario, you can render nothing at all, but with a 403 (Forbidden) status. You can optionally include some data explaining why the 403 occurred, but there's no standard for how that data will be displayed. Some frameworks (Backbone, I think) will look for a hash containing an errors key, which can be set to the reason.

    Something like:

    format.json { render json: { errors: ["Login required."] }, status: 403 }