Search code examples
ruby-on-railsbasic-authenticationfilemaker

Authentication from scratch: "undefined method `find_by_username`"


I'm trying to include a simple user authentication into my application, based on a filemaker database (using the ginjo-rfm gem). After getting some ideas from Ryan Bates' Authentication from Scratch, I've written a customized version of it, but running into some problems.

When I submit my login form, I'm presented with

undefined method `find_by_username' for User:Class

The find_by_username method should be based on a column in the database called 'username', is it not?

User.rb

class User < Rfm::Base
  include ActiveModel::SecurePassword
  include ActiveModel::MassAssignmentSecurity
  include ActiveModel::SecurePassword
  has_secure_password
  attr_accessible :username, :password

   config :layout => 'web__SupplierContacts'

  def self.authenticate(username, password)
    user = find_by_username(username)
    if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
      user
    else
      nil
    end
  end  

end

sessions_controller.rb

class SessionsController < ApplicationController
 def new
 end

 def create
   user = User.authenticate(params[:username], params[:password])
      if user && user.authenticate(params[:password])
     session[:user_id] = user.id
     redirect_to root_url, notice: "Logged in!"
   else
     flash.now.alert = "Email or password is invalid"
     render "new"
   end
 end

 def destroy
   session[:user_id] = nil
   redirect_to root_url, notice: "Logged out!"
 end
end

I'm guessing this is a problem with my model inheriting from Rfm::Base, but I'm not sure. Any ideas?

Idea: Is there any way to rephrase the Class.find_by_column statement? I'm not able to do User.where(:username => "username usernamerson", either (returns undefined method 'where' for User:Class).


Solution

  • If Rfm::Base does not extend ActiveRecord, then you won't be able to use the activerecord db query methods like find, where, etc. -- they are part of the ActiveRecord class and only available to classes which inherit from it.

    If you want to include database wrapper methods in a class which extends another class (in this case Rfm::Base), you might have a look at DataMapper, which takes the form of a module (and thus can be included in any class). (DataMapper can be used as a replacement for ActiveRecord in Rails apps.)

    Also, you've included ActiveModel::SecurePassword twice:

    class User < Rfm::Base
      include ActiveModel::SecurePassword
      include ActiveModel::MassAssignmentSecurity
      include ActiveModel::SecurePassword
    

    I'd delete one of those.