views:

317

answers:

3

I have a fantasy football league rails app that was working last year and it's time to get it going again before the season starts. I cleared out the database and did a "rake db:migrate" so I could restart the app from scratch. The login page comes up fine but when a user tries to "sign up" using restful_authentication I get the following error in log/production.log:

NoMethodError (undefined method `make_activation_code' for #<User:0xb7743490>):
/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:256:in `method_missing'
/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/callbacks.rb:173:in `send'
/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/callbacks.rb:173:in `evaluate_method'
/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/callbacks.rb:161:in `call'

Here are some snippets from my user.rb class:

require 'digest/sha1'
require 'gravtastic'

class User < ActiveRecord::Base
  include Authentication
  include Authentication::ByPassword
  include Authentication::ByCookieToken

# has_one :division
has_and_belongs_to_many :divisions

has_gravatar

validates_presence_of     :login
validates_length_of       :login,    :within => 3..40
validates_uniqueness_of   :login,    :case_sensitive => false
validates_format_of       :login,    :with => RE_LOGIN_OK, :message => MSG_LOGIN_BAD

validates_presence_of     :team_name
validates_length_of       :team_name,    :within => 3..40
validates_uniqueness_of   :team_name,    :case_sensitive => false

# validates_format_of       :name,     :with => RE_NAME_OK,  :message => MSG_NAME_BAD,      :allow_nil => true
# validates_length_of       :name,     :maximum => 100

validates_presence_of     :email
validates_length_of       :email,    :within => 6..100 #[email protected]
validates_uniqueness_of   :email,    :case_sensitive => false
validates_format_of       :email,    :with => RE_EMAIL_OK, :message => MSG_EMAIL_BAD

before_create :make_activation_code

# HACK HACK HACK -- how to do attr_accessible from here?
# prevents a user from submitting a crafted form that bypasses activation
# anything else you want your user to change should be added here.
attr_accessible :login, :email, :team_name, :password, :password_confirmation

bottom of my user.rb:

protected

def make_activation_code
    self.activation_code = self.class.make_token
end

def make_password_reset_code
  self.reset_password_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
end

The make_activation_code is defined in the User class and activation_code was created in the migration so I don't understand why is it undefined.

A: 

I couldn't speak to how to solve this problem directly, but in situations where anomalous behavior is at hand, my approach is usually to try to isolate what's causing the problem. In your case, I'd try things like creating a method of a different name than "make_activation_code," see if you can add it to before_create and it gets called. If so, add the code that's currently in make_activation_code inside the method and see if it still works.

The closest phenomenon I have seen to this specific problem is with the Savage Beast plugin, where the plugin itself has a User model which can redefine the User model inside the application. That's why it would be interesting to see if you can add a different method to your before_create and see if it gets called, so you can verify that your User model itself isn't somehow being replaced by a rogue User model defined in some other part of your app.

Another way to test this theory would be to see if it works differently in production than in development mode. In production, the model doesn't get reloaded between requests, so there is less likely to be problems with one model/method in a plugin overriding another after the initial environment load.

wbharding
A: 

Did you try with out-commenting the protected-line?

Lichtamberg
A: 

Ok I found the answer to my question. I had to change around the before_create to look like this:

  def before_create
    self.activation_code = self.class.make_token
  end

  def make_password_reset_code
    self.reset_password_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
  end

Must have been an internal change in Rails.

hacintosh