Rails tutorial: undefined method

2019-03-06 06:07发布

问题:

I'm stuck (again!) at Chapter 9 (this time in section 9.2.2) of the Rails tutorial. I am getting

bundle exec rspec spec/
................................FFF........................

Failures:

1) Authentication authorization as wrong user submitting a GET request to the Users#edit action 
 Failure/Error: before {sign_in user, no_capybara: true}
 NoMethodError:
   undefined method `new_remember_token' for #<User:0x007f8181815448>
 # ./spec/support/utilities.rb:13:in `sign_in'
 # ./spec/requests/authentication_pages_spec.rb:71:in `block (4 levels) in <top (required)>'

The other 2 errors are of the same type.

Here is spec causing the errors:

    describe "as wrong user" do
      let(:user) {FactoryGirl.create(:user)}
      let(:wrong_user) {FactoryGirl.create(:user, email: "wrong@example.com")}
      before {sign_in user, no_capybara: true}

      describe "submitting a GET request to the Users#edit action" do
        before {get edit_user_path(wrong_user)}
        specify { expect(response.body).not_to match(full_title('Edit user'))}
        specify { expect(response).to redirect_to(root_url)}
      end

      describe "submitting a PATCH request to the Users#update action" do
        before { patch user_path(wrong_user)}
        specify { expect(response).to redirect_to(root_url)}
      end
    end

And here is the method (utilities.rb) the error message is complaining about:

def sign_in (user, options={})
  if options[:no_capybara]
    # Sign in when not using Capybara
    remember_token = User.new_remember_token
    cookies[:remember_token]
    user.update_attribute(:remember_token, User.digest(remember_token))
  else
    visit signin_path
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    click_button "Sign in"
  end
end

The code for the model (User.rb) is here:

class User < ActiveRecord::Base
before_save { self.email = email.downcase}
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, length: {minimum: 6}
has_secure_password

def User.new_remember_token
  SecureRandom.urlsafe_base64
end

def User.digest(token)
  Digest::SHA1.hexdigest(token.to_s)
end

private
  def create_remember_token
    self.remember_token = User.digest(User.new_remember_token)
  end
end

I had previously trouble with the sign_in method but it miraculously disappeared. What am I doing wrong?

回答1:

I finally found the culprit for the erratic test results that I have been observing in this case and, quite likely, on previous occasions (Failure/Error: sign_in user undefined method `sign_in', Rails named route not recognized). The problem seems to be that rails does not clear by default the cache between tests. Which is, actually, downright scary. It seems you cannot really trust the test results. I realised this by commenting out the method that rails was complaining about and re-running the test. The error persisted which meant one thing - rspec was simply working with some cached versions of the files and thus disregarding the changes which I am making. So even if the tests pass you can't be sure that they really do. This is really bizarre. After realising the problem with a bit of googling I found how to force rails to clean the cache - check jaustin's answer here: is Rails.cache purged between tests?