-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add email_scope option for email uniqueness validator #5094
base: main
Are you sure you want to change the base?
Conversation
Sorry guys, I wasn't able to look at this yet, but I'll definitely take a look as soon as I can. |
@tegon scoping the email makes totally sense in a multi tenant scenario. |
For multi tenancy the email validation scoping is crucial. This enhancement is actually based on the currently open PR: heartcombo#5094 As soon as the feature is merged, one should use the Devise trunk again.
Scoping email validations is HUGE - thanks so much for this! |
test/rails_app/lib/shared_user.rb
Outdated
@@ -7,7 +7,7 @@ module SharedUser | |||
devise :database_authenticatable, :confirmable, :lockable, :recoverable, | |||
:registerable, :rememberable, :timeoutable, | |||
:trackable, :validatable, :omniauthable, password_length: 7..72, | |||
reconfirmable: false | |||
reconfirmable: false, email_scope: [:username] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather create another test model with this option so that we can keep both behaviors being tested. Something similar to https://github.com/plataformatec/devise/blob/master/test/rails_app/lib/shared_user_without_email.rb
@@ -124,7 +124,9 @@ def user_sign_up | |||
# https://github.com/mongoid/mongoid/issues/756 | |||
(pending "Fails on Mongoid < 2.1"; break) if defined?(Mongoid) && Mongoid::VERSION.to_f < 2.1 | |||
|
|||
create_user | |||
user = create_user | |||
user.update_attribute(:username, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind to explain why this change was needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember now...I'll pick this back up in the next few days along with the other comments you made.
test/models/validatable_test.rb
Outdated
@@ -26,6 +26,18 @@ class ValidatableTest < ActiveSupport::TestCase | |||
assert user.valid? | |||
end | |||
|
|||
test 'should allow duplicate email when email_scope attribute does not match' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe something like this should be enough:
existing_user = create_user
user = new_user(email: existing_user.email, username: "New username")
assert user.valid?
@flynfish Did you have the chance to push this change forward? We certainly should get it done. |
I didn't have a chance, but thanks for the reminder. I'm gonna set a goal to get the comments addressed in the next week. |
@flynfish we're looking to enable this in our project. Would you recommend forking for now? |
any news? |
11ab701
to
bd4580f
Compare
Hey @carlosantoniodasilva , I noticed you were actively merging PRs, could you help us get this one across the finish line? I think the community would appreciate this feature! |
@xhocquet hey, yes! Appreciate the ping. I've recently started to catch up on some of the issues/PRs here, just want to wrap up a few things on the other projects and then Devise is next. I'm putting this one high in the list to follow-up on first, please stay put for a little longer, I should get to it soon. |
Hello @carlosantoniodasilva, I was taking a look at this PR and I haven't found where these changes impact the migration generated to create users. As far as I know, the migration generated by Devise adds a database index to ensure email uniqueness. Without changing this index, this feature will not work since the new user creation will be blocked at the database layer. Another thing to take into consideration is that the recoverable module may not work well because of the duplicated e-mails.
I'm not so sure about all of this, but can you take a look when reviewing this PR? Thank you |
Thanks for the feedback @danzanzini , some thoughts - By following the referenced wiki post, the migration created by Devise generators would already be insufficient since they would not contain the 'username' for example. One option could be to add a commented out row with the scoped index in the migration to guide developers to the right usage? Given the migration gotcha and the incompatibility with the recoverable module, maybe it makes sense to create a new wiki for scoped emails outlining the caveats? |
@xhocquet creating a wiki article is a good idea and should solve all these problems, I think it will also remove the need for the commented line in the migration since it would be noise for most users. I'll work on a first version and then bring it here for discussion. Thank you :) |
@xhocquet Here is the Since this feature is not merged, I haven't added it to the wiki index. |
@danzanzini Small typo fix but otherwise the wiki looks great! I'm not sure if there's other considerations for this change, but the existing page seems to reflect the two you mentioned succinctly. Edit: Realized I changed the title and therefore the link above became invalid. New wiki link |
On the other hand, we have next 2 options in config/initializers/devise.rb # ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating a user. The default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating a user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# You can also supply a hash where the value is a boolean determining whether
# or not authentication should be aborted when the value is not present.
# config.authentication_keys = [:email]
# Configure parameters from the request object used for authentication. Each entry
# given should be a request method and it will automatically be passed to the
# find_for_authentication method and considered in your model lookup. For instance,
# if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
# The same considerations mentioned for authentication_keys also apply to request_keys.
# config.request_keys = [] I'm not yet understand why we need request_keys, but we can use: What do you think? |
@vickodin I think your suggestion is not directly related to the problem this PR is trying to solve. The problem we are trying to solve is that multiple users with the same email cannot be created because of Devise validations. The configs you point to could be used to lookup these users after they are created. Personally we would not use this and would instead use domain-based scoping to load our user records. |
@xhocquet Thank you for explanations! Then when this PR will be merged? Thanks in advance! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Hey @carlosantoniodasilva, happy new year! Hoping to bump this in your notifications 😄 |
@xhocquet happy new year! Consider it bumped 😉 There may be more to it than just the validation so I need to look into it a bit more carefully in the coming weeks. |
+1, we need this please :) |
Although this request seems to be dragging for morethan 3 years now, i don't see anyone venting out any frustration, kudos to everyone for that. :) |
@carlosantoniodasilva I noticed @poetry-like-code brought up this PR recently, but didn't see any changes. Is there any update on getting this merged? Thanks! |
@stephenpassero appreciate the ping, unfortunately no updates at this time yet. This is still where it stands:
Unfortunately 3+ months and I haven't stopped to look into this carefully yet, but I'm bumping it again in my list here. First I have to get a release out there. 😅 |
Until this is merged, what is the recommendation for people like me who wants to implement this (email uniqueness on a scope) in our app today? 😄 |
Hi @akshaysmurthy, I did these steps to implement it in my app:
Hope it helps |
when is this due to be merged please? thanks |
@tegon @vickodin @carlosantoniodasilva it would be really helpful to the community if we could get this merged or if you could provide any insight into what we can do to help out further |
@danzanzini thanks for the detailed steps there. @akshaysmurthy the simplest thing you can do if you need any further customization: don't use validatable, write your own email/password validations that include the uniqueness scope. @mrabetr there's no due date for merging PRs. ;) @flynfish at this point I cannot provide any insights, without actually stopping to look into the problem and think about it more carefully, my apologies. Like I said above, multi tenancy might be more than just the validation so I want to consider the problem better, it's just not been high in my priority list, all things considered. In any case, validatable is composed of just a few validations that you can easily add to your model to customize things further for now. I am unfortunately not in a position to provide any timeline for when I can work on this. Again, I apologize to everyone for not having given this proper attention yet, but I want to reassure that I'm keeping an eye on each and every comment. ❤️💜💛💚💙 |
Yeah, another year and a tad have passed, making this probably the longest outstanding PR in this project with the most interest. Any update? (i.e. bump!) |
This is a great workaround, however redifining will_save_change_to_email? will also mess with the Confirmable plugin. Instead of redefining will_save_change_to_email? I think it's better to disable the validatable plugin. Just make sure you add all the validators you need (for email and password columns) in the User model. |
@carlosantoniodasilva if you aren't willing to implement this, please be honest enough to at least give an explanation and close this PR. |
A word of caution: I just found out that the workaround mentionned in this thread will also mess badly with the password reset function. If the same email address is associated with two or more tenants, the password reset link in the email may point to the WRONG tenant. (e.g. wrongsubdomain.myapp.com/reset-password?token=blablabla...) |
As this just hit us again, @carlosantoniodasilva - any news and/or decisions on how to move forward with this? |
@flamontagne In my case, I just needed to support soft-deleted users, so I was able to fix the password reset link by hacking class User < ApplicationRecord
def self.send_reset_password_instructions(attributes = {})
recoverable = where(deleted_at: nil).find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
recoverable.send_reset_password_instructions if recoverable.persisted?
recoverable
end
end |
@justwiebe thank you for the hint. I've updated the wiki subdomain tutorial to add a password reset instruction: see: https://github.com/heartcombo/devise/wiki/How-to:-Scope-login-to-subdomain @flamontagne you can have a look at it. It should help you to find a solution. Maybe it is a good idea, to fill up attributes for the method based on |
This is a reboot of the closed PR #4793 with some tests. Issue #4767 has a lot of information about why this would be useful.
Description from #4793