Time objects aren't properly coerced back when using the JSON cookie serialization,
so we need to do it ourselves.
To avoid any new JSON serialization issues, we now store the `generated_at` as
an String with the timestamp seconds + miliseconds in the cookie but still the
previous JSON encoded format.
Thanks to @boblail at https://github.com/plataformatec/devise/pull/3917 for the
initial patch.
This solves the issue where a package might do:
```
user = User.new
user.email = 'test@test.com'
token = user.generate_reset_token
user.save
send_reset_email(token)
```
Since the save clears the reset token, the user will receive a stale token that no longer works.
Closes#3774
The current implementation is opinionated about the resource should have
an "email" column on it if it is to be recoverable, which isn't
necessarily the case. For example, developers may decide to pull emails
out into their own model or have some other way of communicating
password resets to their users (e.g. text message)
I'm not sure there's an easy test to put together for this case, as
minitest doesn't make it very easy to stub the "email_changed?" to raise
an error. Happy to look into building another model in the
"test/rails_app" if you want to have this properly tested though? Or for
a nice way to get calls to "email_changed?" to raise; minitest isn't
a test framework I'm overly familiar with :).
As a side note, it would be nice if the Validatable module also took
this into account, I may raise another PR for that.
This comes off the back of comments on this commit:
e641b4b7b9
* Replace "the instance variable name in controller" with "the helper methods
names in controller".
Devise dose not define instance variable for controllers but define helper
methods for controllers.
* Replace "the name in routes" with "the scope name in routes".
`singular` is used as an argument of `devise_scope`.
* Add sample codes of routing and controller.
If a new user is created with a reset password token, the previous behavior
would automatically clear the token even when it was desired for setting
the password for the first time.