devise_token_auth: User tokens don't properly deserialize
I am having trouble integrating devise_token_auth v0.1.31.beta9 into an existing Rails 4.2 app that already uses Devise.
I first ran the install. The user model was missing a few columns that devise_token_auth uses, so I edited down the generated migration to:
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration
def change
add_column :users, :provider, :string, :null => false, :default => ""
add_column :users, :uid, :string, :null => false, :default => ""
add_column :users, :tokens, :text
User.all.each do |user|
user.provider = 'email'
user.uid = user.email
user.save!
end
add_index :users, [:uid, :provider], :unique => true
end
end
Attempting to perform the migration results in the following:
== 20150126183919 DeviseTokenAuthCreateUsers: migrating =======================
-- add_column(:users, :provider, :string, {:null=>false, :default=>""})
-> 0.0218s
-- add_column(:users, :uid, :string, {:null=>false, :default=>""})
-> 0.0164s
-- add_column(:users, :tokens, :text)
-> 0.0012s
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
undefined method `delete_if' for "{}":String/usr/local/Cellar/rbenv/0.4.0/versions/2.2.0/lib/ruby/gems/2.2.0/gems/devise_token_auth-0.1.31.beta9/app/models/devise_token_auth/concerns/user.rb:238:in `destroy_expired_tokens'
/Users/sam/Code/goals/db/migrate/20150126183919_devise_token_auth_create_users.rb:11:in `block in change'
/Users/sam/Code/goals/db/migrate/20150126183919_devise_token_auth_create_users.rb:7:in `change'
-e:1:in `<main>'
NoMethodError: undefined method `delete_if' for "{}":String
/usr/local/Cellar/rbenv/0.4.0/versions/2.2.0/lib/ruby/gems/2.2.0/gems/devise_token_auth-0.1.31.beta9/app/models/devise_token_auth/concerns/user.rb:238:in `destroy_expired_tokens'
/Users/sam/Code/goals/db/migrate/20150126183919_devise_token_auth_create_users.rb:11:in `block in change'
/Users/sam/Code/goals/db/migrate/20150126183919_devise_token_auth_create_users.rb:7:in `change'
-e:1:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
It seems that for some reason Rails isn’t deserializing the tokens JSON column into a Ruby hash. DeviseTokenAuth::Concerns::User is included in my user modal as it should be. It if makes a difference, I am running Postgres 9.4 as my database.
Any idea what could be causing this?
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 18 (5 by maintainers)
Commits related to this issue
- Fix devise token auth migration https://github.com/lynndylanhurley/devise_token_auth/issues/121 — committed to singularities/circular-work by atd 7 years ago
- Fix devise token auth migration https://github.com/lynndylanhurley/devise_token_auth/issues/121 — committed to singularities/circular-work by atd 7 years ago
Just in case anyone else stumbles upon this issue, instead of overriding destroy_expired_tokens you can simply set user tokens to nil during the initial migration. The User model will then call the set_empty_token_hash callback defined in the provided model concern.
This was run on rails 4.2.4, devise_token_auth 0.1.34, mysql server 5.5.40. Here’s my modified migration:
I dont believe that simply having a
jsoncolumn fixes this issue entirely. I had a tough time this afternoon trying to figure out how to get a seeded User to work with this gem. CLI generated User, and one created through the application (POST registrations…) work fine.The above will always result in some kind of String value that throws the error in the OP on login. I also tried overriding
#destroy_expired_tokens, but that led to another error due to expectation of a JSON/Hash object. I found a way around that, but was not comfortable with 2 hacks (overrides…) to make this work.Any form of one-line or block-based
#createon my User, when run through./bin/rails db:seed, will always result in some invalid value that throws an error on login (usually, the value is'{}', where it should be{}).What does work for me, is to first create the User record, then reload it, set
#tokenstonil, and then save again:This actually sets
#tokenstonil, which in turn allows thedevise_token_authinternals to set it to{}correctly.