Similar to this question for the regular devise gem, using devise_token_auth gem is showing the same result - validation errors appearing twice in the json response!?
From log:
Processing by DeviseTokenAuth::RegistrationsController#create as JSON
Parameters: {"name"=>"Mickey Mouse", "email"=>"mickeymouse@gmail.com", "password"=>"[FILTERED]", "confirmPassword"=>"[FILTERED]", "confirm_success_url"=>"http://localhost:4200/register", "registration"=>{"name"=>"Mickey Mouse", "email"=>"mickeymouse@gmail.com", "password"=>"[FILTERED]", "confirmPassword"=>"[FILTERED]", "confirm_success_url"=>"http://localhost:4200/register"}}
Unpermitted parameters: :confirmPassword, :confirm_success_url, :registration
Unpermitted parameters: :confirmPassword, :confirm_success_url, :registration
(0.2ms) BEGIN
User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "mickeymouse@gmail.com"], ["LIMIT", 1]]
(0.8ms) SELECT COUNT(*) FROM "users" WHERE "users"."provider" = $1 AND "users"."email" = $2 [["provider", "email"], ["email", "mickeymouse@gmail.com"]]
(0.3ms) ROLLBACK
Completed 422 Unprocessable Entity in 247ms (Views: 0.7ms | ActiveRecord: 6.9ms)
Notice that the unpermitted_parameters line is shown twice - which seems to indicate something odd (those lines don't show via Postman).
My user model has nothing extra from the standard guide so I definitely do not have 2 uniqueness or presence validations on my model, and examining the gem's source code it also does not appear to have that.
Here is the model:
class User < ActiveRecord::Base
# Include default devise modules.
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable
include DeviseTokenAuth::Concerns::User
end
If I call this endpoint from Postman, I get the same result, here is the returned json:
{
"status": "error",
"data": {
"id": null,
"account_id": null,
"provider": "email",
"uid": "",
"name": null,
"nickname": null,
"image": null,
"email": "mickeymouse@gmail.com",
"created_at": null,
"updated_at": null
},
"errors": {
"email": [
"has already been taken",
"has already been taken"
],
"full_messages": [
"Email has already been taken",
"Email has already been taken"
]
}
}
The Rails API is called from Angular2 using the angular2-token library, but that is clearly not the issue (give the result from Postman).
How can I either find the cause of this OR how can I monkey-patch the gem to remove the 2nd error?
UPDATE
If I remove :validatable
from the model and put my own validation:
validates_uniqueness_of :email
I get the same result, which is odd.
Edit: This issue has been fixed, just upgrade your gem! > v0.1.43.beta1
I found the issue is reported on github.
The workaround is to remove :validatable (email uniqueness will still fire) and then roll your own validation for password confirmation as shown in that issue (see the response there by stephanebruckert) and reproduced here:
Quote: "validatable validates both the email and the password, which is why we shouldn't do any of those in models, otherwise it would be validated twice. In my case, only the email was validated twice, whereas I wasn't adding any extra validation in my model. So I ended up removing validatable and made my own validation on password and password_confirmation:"
validates_presence_of :password, on: :create
validates :password,
length: { minimum: 8 },
allow_blank: true
validate :password_complexity
validates_confirmation_of :password
validates_presence_of :password_confirmation, if: lambda {| u| u.password.present? }
private
def password_complexity
return unless password
if password.include?(username) || !password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)./)
errors.add(:password, "Must include at least one lowercase letter, one uppercase letter and one digit")
end
end
Although this does solve the duplicate email error, I now get a 'password_confirmation can't be blank error' ... which leads down a rabbit hole to discover this issue. You will need to read it all but basically, an api should not enforce the presence of password confirmation value (only needed in the form itself) :)