1

I'm rather new to the Ruby ecosystem and am drowning. I guess I was spoiled by the easy intellisense of Visual Studio w C#. Anyway, I'm using Ruby 1.9.3, Rails 3.2.13, and Devise 3.0.3 on Ubuntu. I can login to this website, via a browser on a PC. But when I attempt to do it from our Phonegap mobile-app, I get this error:

NameError: 'undefined local variable or method 'build_resource' for # ..

Here is the code within sessions_controller.rb:

class SessionsController < Devise::SessionsController
  def create
    respond_to do |format|
      format.html {
        super
      }
      format.json {
        build_resource  # <-This line is evidently producing an error!
        user = User.find_for_database_authentication(:email => params[:user][:email])
        return invalid_login_attempt unless resource
        return invalid_login_attempt unless user
..

Evidently, it is the line that contains build_resource, that is producing the error. I'd appreciate any help to point me where to go. What does that line even do? Is that a method-call? How does one discover what that calls?

Roman Kiselenko
  • 43,210
  • 9
  • 91
  • 103
JamesWHurst
  • 493
  • 8
  • 14

1 Answers1

4

If you go here you see the devise registrations_controller.

It has the build_resource method, that you are calling in you sessions_controller

  # Build a devise resource passing in the session. Useful to move
  # temporary session data to the newly created user.
  def build_resource(hash=nil)
    self.resource = resource_class.new_with_session(hash || {}, session)
  end

The problem is that it is protected ( under the line that says protected ) That means that the build_resource method can only be called from the devise registrations_controller.

The reason it works with the browser it that the create action in you sessions_controller calls

super

This means that it calls the create action from the devise sessions_controller, which your sessions_controller inherits from -

#devise/sessions_controller
def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_flashing_format?
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, location: after_sign_in_path_for(resource)
  end

This gist shows how to login users trough a json api.

It uses this include

include Devise::Controllers::InternalHelpers

in the sessions_controller. I think this makes it possible to use the build_resource method.

Good luck!

Edit

def create
    respond_to do |format|
    # when you log into the application through a web browser you go to the format.html option
    # Thus you're not calling the build_resource method
      format.html {
        super
      }
    # So, lets try to sign in without the build_resource 
    # I am not really sure what you can do, but try this
      format.json { 

        resource = User.find_for_database_authentication(:login=>params[:user_login][:login])
        return invalid_login_attempt unless resource

        if resource.valid_password?(params[:user_login][:password])
          sign_in("user", resource)
          render :json=> {:success=>true, :auth_token=>resource.authentication_token, :login=>resource.login, :email=>resource.email}
        return
        end
        invalid_login_attempt
      end
        # build_resource  # <-This line is evidently producing an error!
        # user = User.find_for_database_authentication(:email => params[:user][:email])
        # return invalid_login_attempt unless resource
        # return invalid_login_attempt unless user
Andreas Lyngstad
  • 4,887
  • 2
  • 36
  • 69
  • This project on which I am working, *was* working previously. I did not change anything within the Devise code. Why would build_resource suddenly become undefined? – JamesWHurst Mar 31 '14 at 22:37
  • What changes have you made? Updated devise? Deleted some code? When you get the undefined error, the code you're running cannot see the method. Do you have the `include Device:Controllers::IneternalHelpers` line in your sessions controller. Technically you change devise code with you sessions controller. As long as you don't call super it will override the `Devise::SessionsController` – Andreas Lyngstad Apr 01 '14 at 08:25
  • Sorry - I'm rather new to StackOverflow and didn't realize there was a response here! I had not made *any* changes to Devise, nor to anything that I can think of that could impact that. – JamesWHurst Apr 13 '14 at 06:27
  • 1
    That's alright. What version of devise are you using? I understand that you have not made any changes to devise, but when you lets the session_controller inherit from the Devise::SessionsController, with this line `class SessionsController < Devise::SessionsController` your create action overrides the devise create action. Thus you _change_ the way devise works. Have you tried this line in the sessions_conroller include `Devise::Controllers::InternalHelpers` – Andreas Lyngstad Apr 13 '14 at 09:23
  • According to the Gemfile.lock, it is devise (2.2.4). If I add "include Devise::Controllers::InternalHelpers, it says "RoutingError (unitialized constant Devise::Controllers::InternalHelpers). What makes the problem even more confusing, is that I can login to the website. But it is when the Android mobile app tries to login, that the error happens with build_resource suddenly not being recognized. – JamesWHurst Apr 14 '14 at 00:22
  • 1
    Thank you for your generous help, I deeply appreciate that! As it happens, though - the problem was quite inane. I was including the Devise gem, without specifying the version in the Gemfile file. Somewhere along the line, that gem got updated, and at that point the build_resource method was no longer valid. The next time someone ran 'bundle install', a new version got pulled down, and since Ruby evidently fails to detect errors like this until that code runs - it was not caught until this mobile-app tried to sign-in. Such, is the nature of open-source I guess. – JamesWHurst Apr 16 '14 at 02:51
  • I always glad to help. It's a really good idea to specify the gem version in the gem file. I've been through a few headaches when gems have "secretly" been updated. Good Luck! – Andreas Lyngstad Apr 16 '14 at 10:01