Remington Charles
Remington Charles

Reputation: 123

Administration of a Multi-Tenant Rails App

We have a multi-tentant rails app that very closely resembels the "from scratch" approach that Ryan Bates explains/teaches.

Authentication from scratch.

Multi-tenancy from scratch.

We have an account model that has a sub-domain attribute and uses scoping to separate the data.

#ApplicationController
around_filter :scope_current_account  

private

  def current_account
    if request.subdomain.present? && request.subdomain != 'www' && request.subdomain != 'ndt-staging'
      @account ||= Account.find_by_subdomain!(request.subdomain)
    end
  end
  helper_method :current_account

  def scope_current_account
    if request.subdomain.present? && request.subdomain != 'www' && request.subdomain != 'ndt-staging'
      Account.current_id = current_account.id   
    end
    yield
  ensure
    Account.current_id = nil
  end

The models:

#Account.rb
has_many :users, :inverse_of => :account, :dependent => :destroy

#User.rb
belongs_to :account, :inverse_of => :users
default_scope { where(account_id: Account.current_id) }

My questino is: What is the best way to manage users application wide.. meaning User.scoped and User.unscoped?

The first thing that comes to mind is to add an admin_password attribute to the User model. Set the password with an environment variable, and at User/Account creation add the admin password value into a hidden field.

(the account new action also builds a user and creates a user account)

#AccountsController
def new
  @account = Account.new
  @account.users.build(params[:user])
end

The biggest problem I see with this approach is the authentication. I would need to re-write things so that if the admin_password is correct, the normal password attribute will not be checked. If the admin_password is incorrect the password attribute will be used.

As a side note, I've looked at plugins like acts_as_tenant and devise, but would rather build these parts myself.

I could be going down the wrong path here, that is why I am asking for recommended solutions/ideas. Thank you in advance for those :)

#SessionsController
def create
  user = User.find_by_email(params[:email].downcase)
  if user && user.authenticate(params[:password])
    sign_in user
    redirect_to welcome_path
  else
    flash.now[:error] = 'Invalid email/password combination' # Not quite right!
    render 'new'
  end
end

Upvotes: 1

Views: 833

Answers (1)

Remington Charles
Remington Charles

Reputation: 123

I solved this using the cancan gem, and creating an admin user in the account create action.

Upvotes: 1

Related Questions