scambra/devise_invitable

User.new.invite! skips validations

boardfish opened this issue · 3 comments

In my Devise initializer, I have config.validate_on_invite set to true. So I'd expect validations are always run when I invite a user.

So far, I've only been inviting using User.invite!. But in this instance, I want to build a User instance before inviting them, and not invite them if they're not valid. However, when I tried to use User#invite!, it saved a new User that would otherwise fail validations.

> User.invite!(email: 'hello@world.com').persisted? # name is also a required field on User, so this User would not be valid
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["email", "hello@world.com"], ["LIMIT", 1]]
  User Exists? (0.3ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "hello@world.com"], ["LIMIT", 1]]
false
> User.new.tap { |u| u.invite! }.persisted? # This user is missing all required attributes, so they're definitely not valid
... # returns ActionMailer message sent as invite, hence `tap`
true

I understand that those docs say that method should be used after creation, but I would expect them to work after building the object (before persistence) too.

validate_on_invite is called when you use class method, it prevents calling instance method. If you use User.new and invite! instance method you can check if resource is valid, no need to use setting for that:

User.new.tap { |u| u.invite! if u.valid? }.persisted?

I'm not sure this issue should have been closed. I know that it's possible that way, but the better thing to do would be to have the method respect DeviseInvitable's settings, so as to make it more intuitive. I may be able to open a PR to make this change.

Class method is recommended way, if you want to do something before invitation is sent you can use block:

User.invite!(email: 'hello@world.com') { |u| ... }.persisted?

If you want to use instance method instead, and want instance method to honor validate_on_invite setting, you can send PR, and I will check it doesn't break current behaviour, but I don't think it's worth it. I think settings are useful to change behaviour with provided controllers, if you are writting your own code, I don't think validate_on_invite setting is very useful, I think it's even more readable u.invite! if u.valid?