Super Engineer
Super Engineer

Reputation: 1976

Multi tenant rails app with devise

I'm trying to build a multi tenanted app in which which different banks are separated by subdomain. This part is working fine. Now there is one more level of multitenancy for bank products.

This is how I'm trying to implement above solution

around_filter :scope_current_bank, :scope_current_product
before_filter :authenticate_user!

helper_method :current_bank, :current_product

def current_bank
  @current_bank = Bank.find_by_subdomain!(request.subdomains.first)
end

def current_product
  if user_signed_in?
    @current_product = current_bank.products.find_by_id(params[:product_id])
  else
    @current_product = current_user.product
  end
end

def scope_current_bank
  Bank.current_id = current_bank.id
  yield
ensure
  Bank.current_id = nil
end

def scope_current_product
  Product.current_id = (current_product.id rescue nil)
  yield
ensure
  Product.current_id = nil
end

Now the problem is while user is sigining in, the scope_current_product method calls user_signed_in?, obviously it fails because product_id is nil. Now it enters the else block after which I expect it to call authenticate_user! as its a before_filter but it does not happen as authentication was already done. So I get a message saying authentication failed.

Is their any way to call authenticate_user again?

Upvotes: 1

Views: 1366

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

Although not a direct answer, hopefully this will give you some ideas:


Authorization

Perhaps you should look at - Is there a difference between authentication and authorization? - there's a good RailsCast about this

I think your issue comes down to the idea you need to authenticate the user once (login / logout), but should then authorize that user to work with different resources


Code

A devise user can belong to only on product - I would recommend this:

#app/models/product_user.rb
Class ProductUser < ActiveRecord::Base
    belongs_to :product
    belongs_to :user
end

#app/models/product.rb
Class Product < ActiveRecord::Base
    has_many :product_users
    has_many :users, through: :product_users
end

#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :product_users
    has_many :products, through: :product_users
end

This is a typical has_many :through association:

@user.products
@product.users

CanCan

It means you can use CanCan to do something like this:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user
      can :manage, Product, users.exists?(user.id)
    else
      can :read, :all
    end
  end
end

This allows you to control which products the user can edit / access. Obviously my code needs to be tweaked, but I hope it shows you the value of authorization over trying to do multiple authentications

Upvotes: 1

Related Questions