Can't get RegistrationsController#update to work when called via JSON

795 views
Skip to first unread message

Tom Harrison

unread,
May 18, 2012, 1:22:19 PM5/18/12
to plataforma...@googlegroups.com
I'm building an API that allows registration (and everything else) via JSON.  I can successfully log in, create a user, show, and so on.

But I can't get request to PUT /users.json (RegistrationsController#update method) to work.  The error is 

NoMethodError (undefined method `to_key' for nil:NilClass)

from the first line of RegistrationsController

self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)

so it seems that current_user method is returning nil.

Details:
  • RoR 3.2.2, Ruby 1.9.3, Devise 2.1.0rc
  • testing like this with curl from the command line:
  • > curl --cookie _myapp_session=BAh7B0kiGXdhcmRlbi51c2VyLnVzZXIua2V5BjoGRVRbCEkiCVVzZXIGOwBGWwZpBkkiIiQyYSQxMCRFYi5BNUJ4Mm5pWFdUTDVib0FuMWdPBjsAVEkiD3Nlc3Npb25faWQGOwBGSSIlN2NiOGQzMjg4MjliMzU4OGM4OGQ5NThhYjI2NWZmNTAGOwBU--908914a94a21985f26cf70e72890a30efd6230e7 http://myapp.com/users/edit.json
  • => {"id":1,"account_id":2,"name":"Administrator"} (This seems to work fine, and I can do POSTs, for example to sign_in)
  • but
  • curl --include --request PUT --data 'user[account_id]=2&user[name]=Admin&user[email]=ad...@example.com&user[password]=&user[password_confirmation]=&user[current_password]=please' --cookie _myapp_session=BAh7B0kiGXdhcmRlbi51c2VyLnVzZXIua2V5BjoGRVRbCEkiCVVzZXIGOwBGWwZpBkkiIiQyYSQxMCRFYi5BNUJ4Mm5pWFdUTDVib0FuMWdPBjsAVEkiD3Nlc3Npb25faWQGOwBGSSIlN2NiOGQzMjg4MjliMzU4OGM4OGQ5NThhYjI2NWZmNTAGOwBU--908914a94a21985f26cf70e72890a30efd6230e7 http://myapp.com/users.json
  • => (from Rails log) 
  • Started PUT "/users.json" for 127.0.0.1 at 2012-05-18 13:14:08 -0400
  • Processing by Devise::RegistrationsController#update as JSON
  •   Parameters: {"user"=>{"account_id"=>"2", "name"=>"Admin", "email"=>"ad...@example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}}
  • ...
  • NoMethodError (undefined method `to_key' for nil:NilClass):
  •   devise (2.1.0.rc) app/controllers/devise/registrations_controller.rb:40:in `update'

I assume I need to override this method and somehow force login before returning to the controller.  But I am not sure how to do this, or why it only seems to be necessary is this case.

Thanks in advance for any pointers or guidance.

Tom


José Valim

unread,
May 18, 2012, 1:26:58 PM5/18/12
to plataforma...@googlegroups.com
This is weird. The update action should enforce a user exists:


Unless you are using a custom controller that is somehow changing Devise semantics, your examples were supposed to be working.


On Friday, May 18, 2012 7:22:19 PM UTC+2, Tom Harrison wrote:
I'm building an API that allows registration (and everything else) via JSON.  I can successfully log in, create a user, show, and so on.

But I can't get request to PUT /users.json (RegistrationsController#update method) to work.  The error is 

NoMethodError (undefined method `to_key' for nil:NilClass)

from the first line of RegistrationsController

self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)

so it seems that current_user method is returning nil.

Details:
  • RoR 3.2.2, Ruby 1.9.3, Devise 2.1.0rc
  • testing like this with curl from the command line:
  • > curl --cookie _myapp_session=BAh7B0kiGXdhcmRlbi51c2VyLnVzZXIua2V5BjoGRVRbCEkiCVVzZXIGOwBGWwZpBkkiIiQyYSQxMCRFYi5BNUJ4Mm5pWFdUTDVib0FuMWdPBjsAVEkiD3Nlc3Npb25faWQGOwBGSSIlN2NiOGQzMjg4MjliMzU4OGM4OGQ5NThhYjI2NWZmNTAGOwBU--908914a94a21985f26cf70e72890a30efd6230e7 http://myapp.com/users/edit.json
  • => {"id":1,"account_id":2,"name":"Administrator"} (This seems to work fine, and I can do POSTs, for example to sign_in)
  • but
  • curl --include --request PUT --data 'user[account_id]=2&user[name]=Admin&user[email]=admin@example.com&user[password]=&user[password_confirmation]=&user[current_password]=please' --cookie _myapp_session=BAh7B0kiGXdhcmRlbi51c2VyLnVzZXIua2V5BjoGRVRbCEkiCVVzZXIGOwBGWwZpBkkiIiQyYSQxMCRFYi5BNUJ4Mm5pWFdUTDVib0FuMWdPBjsAVEkiD3Nlc3Npb25faWQGOwBGSSIlN2NiOGQzMjg4MjliMzU4OGM4OGQ5NThhYjI2NWZmNTAGOwBU--908914a94a21985f26cf70e72890a30efd6230e7 http://myapp.com/users.json
  • => (from Rails log) 
  • Started PUT "/users.json" for 127.0.0.1 at 2012-05-18 13:14:08 -0400
  • Processing by Devise::RegistrationsController#update as JSON
  •   Parameters: {"user"=>{"account_id"=>"2", "name"=>"Admin", "email"=>"ad...@example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}}
  • ...
  • NoMethodError (undefined method `to_key' for nil:NilClass):
  •   devise (2.1.0.rc) app/controllers/devise/registrations_controller.rb:40:in `update'

I assume I need to override this method and somehow force login before returning to the controller.  But I am not sure how to do this, or why it only seems to be necessary is this case.

Tom Harrison

unread,
May 18, 2012, 1:45:54 PM5/18/12
to plataforma...@googlegroups.com
Thanks for your reply, José!  Wow.

So yeah, the prepend_before_filter was what I was just looking at -- it's also doing calling current_user -- one would think it would blow up there instead of in the #update method.  As of now, I haven't done anything in a custom controller -- all straight from the gem code.

I'll try a subclass to override the method and see if I can get some logging to help.  Any ideas would be most welcome :-)

And thanks again.

Tom

Tom Harrison

unread,
May 18, 2012, 1:48:50 PM5/18/12
to plataforma...@googlegroups.com
Oh, and I forgot to mention -- the update works fine in from the HTML form post ... is only failing with JSON.

Tom Harrison

unread,
May 18, 2012, 2:26:17 PM5/18/12
to plataforma...@googlegroups.com
I think I understand the problem -- in the json request (unlike the HTML form), I was not passing the CRSF token, so the request failed at some point.

I also neglected to mention that the log was sending

WARNING: Can't verify CSRF token authenticity  

There's a good post on SO (http://stackoverflow.com/questions/9362910/rails-warning-cant-verify-csrf-token-authenticity-for-json-devise-requests) and a comment from the OP on the accepted answer that says, in effect, I should not depend on the session cookie, but instead make my API require an API key ... which Devise has support for.

So much for being lazy -- I guess I have to do it the right way :-)

Thanks for getting me on the right track.

Tom
Reply all
Reply to author
Forward
0 new messages