ruby-on-railsrubymodel-view-controlleractioncontrollerclearance

How to lock down an entire Rails app until a User completes their account set up


I have a rails app that uses the Clearance for signup and login. After signup the user is redirected to accounts/new to complete their account setup. The Account belongs_to User and the user has_one account. (The Account and User models are separate because there are attributes, such as "Company Name" that I don't want to put into the User model.)

I'd like to lock down everything in the application and redirect them to accounts/new if they try to access anything other than marketing pages, signup, and login pages before they've created an Account.

I'm thinking that adding a before_action to the ApplicationController is the right approach and then using :skip_before_action on any controller#action that they need access before creating their Account (such as /signup or /login or marketing pages).

This seems like the right approach since the entire application will be locked down by default if the User hasn't created an account. By explicitly using using :skip_before_action as needed it seems like there is less of a chance of creating holes in the application by mistake.

But I can't get the before_action on the ApplicationController to work because I keep getting this error when I visit a page like /signup:

NoMethodError in Clearance::UsersController#new
undefined method `account' for nil:NilClass

I'm trying to do something like this:

class ApplicationController < ActionController::Base
  include Clearance::Controller
  before_action :require_login
  before_action :require_account

  private

  def require_account
    if current_user.account != nil
      redirect_to dashboard_path
    end
  end
end

That syntax worked when I was inside my AccountsController and just redirecting my accounts#new action, but now I'm having trouble figuring out how to get the same behavior across my entire application. Note: current_user is a method supplied by Clearance.

What is the "Rails way" to do this?


Solution

  • If I understood correctly, I consider you're in the right way to do it in 'Ruby on Rails way'!

    The error NoMethodError is caused because inside some contexts of your application you don't have the current_user method.

    If you want to redirect the user to dashboard_path when the current_user already have the account, you should try the following:

    class ApplicationController < ActionController::Base
      include Clearance::Controller
      before_action :require_login
      before_action :require_account
    
      private
    
      def require_account
        if current_user && current_user.account.present?
          redirect_to dashboard_path
        end
      end
    end
    

    This way you can get the redirect when current_user is present AND current_user have one account, no skip_before_action is needed.