I am using devise for authentication in rails app, and my app can have many subdomains. Currently it is using email as authentication, and email should be unique for the whole app.
Now is there any way I can scope uniqueness of email address to subdomain, not the whole app? I tried:
validates_uniqueness_of :email, :scope => :account_id
But didn't work. It still seeks uniqueness of email to whole app, not the specific subdomain when registering a new user.
Any help would be highly appreciated.
In today's post, we'll learn how to build a Rails app that can support multiple subdomains. Let's assume that we have a gaming website funkygames.co and we want to support multiple subdomains such as app.funkygames.co, api.funkygames.co, and dev.funkygames.co with a single Rails application.
You’re now able to run your app and it should include pages like /users/sign_up and /users/sign_in. In theory Devise should work now but, unfortunately, the view links and redirects used by Devise won’t work in Rails 7. Let’s fix that.
To define routes for multiple subdomains, we just have to add multiple constraints blocks in our routes.rb file. Rails routing provides request constraints and segment constraints. Segment constraints add rules on the request path whereas request constraints add conditions on the incoming request.
We need to alter the code that Devise generates for us to deal with Turbo. So, once you’ve run rails generate devise:install we need to alter the Devise initializer config in several places beyond what the Devise README instructs us to do and add a controller as Devise’s parent controller.
Ok I did this way.
Edited config.authentication_keys in devise.rb as
config.authentication_keys = [ :login, :account_id ]
Also I created hidden field to include account_id in login form
<%= f.hidden_field :account_id, :value => @account.id %>
Here @account hold the account related to current subdomain.
And added the following protected method in user.rb to override find_for_database_authentication class method
protected
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
login = conditions.delete(:login)
account_id = conditions.delete(:account_id)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).where("account_id = ?", account_id).first
end
If there is better solution then feel free to comment guys..
Cheers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With