0

Right, this is the most bizarre bug I have ever come across.

I have a field in my resource called hashed_password, of datatype string. Nothing can be read from it. It's insane.

users table

id | username | created_at | updated_at | hashed_password

example data

37 | john harris | 2013-09-24 |  2013-09-24 | eba082ff45517c06b

users index

<% @users.each do |user| %>
  <tr>
    <td><%= user.id %></td>
    <td><%= user.username %></td>
    <td><%= user.password.inspect %></td>
    <td><%= user.hashed_password.inspect %></td>
    <td><%= user.created_at %></td>
    <td><%= user.updated_at %></td>
    <td><%= link_to 'Show', user %></td>
    <td><%= link_to 'Edit', edit_user_path(user) %></td>
    <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>

html

1

john harris

nil

nil

2013-09-24

2013-09-24

It's sitting right there in the database, but it just cannot be read. It's so weird. It only exists as nil.

The only thing different about it and the other columns is that its set programatically. Here's the User controller:

require "digest/sha1"
class User < ActiveRecord::Base
    attr_accessor :password

    before_create :hashed_password

    def self.authenticate(username, password)
        logger.info "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-"
        logger.info "user " + username

        user = find_by_username(username)

        logger.info "user id: " + user.id.to_s
        logger.info "user username: " + user.username.to_s
        logger.info "user hashed_password: " + user.hashed_password.to_s
        logger.info "user created_at: " + user.created_at.to_s
        logger.info "user updated_at: " + user.updated_at.to_s
        logger.info "*-*-*-*-*-*-*-*-"
        logger.info "entered hashed password " + Digest::SHA1.hexdigest(password)

        if user && user.hashed_password == Digest::SHA1.hexdigest(password)
            logger.info "SUCCESS"
            user
        else
            nil
        end
    end

    def hashed_password
        if password.present?
            self.hashed_password = Digest::SHA1.hexdigest(password)
        end
    end

But once it's in the database that shouldn't make a difference, should it? It simply refuses to be read. Also, the log file:

Started POST "/sessions" for 127.0.0.1 at 2013-09-25 08:06:45 +0100
Processing by SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"p5tDog8wOD6+H3fSFZpDXkMxNzFxej3tay6slVmIF5Y=", "username"=>"john harris", "password"=>"[FILTERED]", "commit"=>"Log in"}
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
user john harris
  [1m[35mUser Load (0.0ms)[0m  SELECT "users".* FROM "users" WHERE "users"."username" = 'john harris' LIMIT 1
user id: 37
user username: john harris
user hashed_password: 
user created_at: 2013-09-25 07:06:28 UTC
user updated_at: 2013-09-25 07:06:28 UTC
*-*-*-*-*-*-*-*-
entered hashed password eba082ff45517c06bd365c2fde1fc77cda7a8f6f
  Rendered sessions/new.html.erb within layouts/application (1.0ms)
Completed 200 OK in 11ms (Views: 8.0ms | ActiveRecord: 0.0ms)

Note the blankness of the user hashed_password: entry. What is going on? Once data is in the database, it should be able to be read no matter how it got there. So weird.

The only thing I can think is that hashed_password is a keyword and rails does something stupid to it. That's all I can think. Completely at a loss.

Starkers
  • 10,273
  • 21
  • 95
  • 158

1 Answers1

0

Your callback method for setting hashed_password has the same name with attribute, rename it to something unique, as it overrides attribute accessor.

biomancer
  • 1,284
  • 1
  • 9
  • 20
  • Hello again. Thanks a lot...really stupid error on part. Ah well, it all works perfectly now. So simply creating a method in a model creates an attribute? Interesting... – Starkers Sep 25 '13 at 09:21
  • No, attributes are accessed through methods called accessors, see [this](http://stackoverflow.com/questions/4370960/what-is-attr-accessor-in-ruby) to get the idea. For activerecord attributes similar accessors are created automatically. And when you name some method same with attribute, you override its default read accessor. – biomancer Sep 25 '13 at 10:05