当模型有效时,PeopleController创建动作应该重定向

时间:2014-02-06 17:48:10

标签: ruby-on-rails ruby ruby-on-rails-3 rspec

已经完成了找出某些rspec测试失败原因的任务。我没有写任何代码,而且卡住了。这是输出:

3) PeopleController create action should redirect when model is valid
     Failure/Error: post :create
     TypeError:
       no implicit conversion of nil into String
     # ./app/models/person.rb:24:in `digest'
     # ./app/models/person.rb:24:in `hexdigest'
     # ./app/models/person.rb:24:in `encrypt_password'
     # ./app/models/person.rb:30:in `prepare_password'
     # ./app/controllers/people_controller.rb:10:in `create'
     # ./spec/controllers/people_controller_spec.rb:20:in `block (2 levels) in <top (required)>'

这是people_controller_spec:

require File.dirname(__FILE__) + '/../spec_helper'

describe PeopleController do
  fixtures :all
  render_views

  it "new action should render new template" do
    get :new
    response.should render_template(:new)
  end

  it "create action should render new template when model is invalid" do
    Person.any_instance.stub(:valid?).and_return(false)
    post :create
    response.should render_template(:new)
  end

  it "create action should redirect when model is valid" do
    Person.any_instance.stub(:valid?).and_return(true)
    post :create
    response.should redirect_to(root_url)
    session['person_id'].should == assigns['person'].id
  end

  it "show action should redirect when not logged in" do
    get :show, :id => "ignored"
    response.should redirect_to(login_url)
  end

  it "show action should render show template" do
    @controller.stub(:current_user).and_return(Person.first)
    get :show, :id => "ignored"
    response.should render_template(:show)
  end

end

以下是失败的people_controller的代码块:

def create
    @person = Person.new(:username => params[:username], :password => params[:password], :first_name => params[:first_name], :last_name => params[:last_name])
    if @person.save
      session[:person_id] = @person.id
      if Invite.where(:ad_username => @person.username).count != 0
        organization = Organization.find(Invite.where(:ad_username => @person.username).first.organization_id)
        Affiliation.create!(:organization_id => organization.id, :person_id => @person.id, :affiliation_type => Affiliation::ATHLETIC_DIRECTOR)
      end
      redirect_to root_url, :notice => "Thank you for signing up! You are now logged in."
    else
      render :action => 'new'
    end
  end

以下是人物模型:

class Person < ActiveRecord::Base

  # new columns need to be added here to be writable through mass assignment
  attr_accessible :username, :password, :password_confirmation, :first_name, :last_name, :cell_phone
  has_one :affiliation, :dependent => :destroy
  has_many :contacts, :dependent => :destroy

  before_save :prepare_password
  before_validation :downcase_username

  validates :username, :uniqueness => {:case_sensitive => false}
  validates_presence_of :username, :first_name, :last_name
  validates_format_of :username, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i, :message => " must be a valid email"
  validates_presence_of :password, :on => :create
  validates_confirmation_of :password
  validates_length_of :password, :minimum => 4

  def self.authenticate(login, pass)
    person = find_by_username(login.downcase)
    return person if person && person.password == person.encrypt_password(pass)
  end

  def encrypt_password(pass)
    Digest::SHA1.hexdigest(pass)
  end

  private

  def prepare_password
    self.password = encrypt_password(password)
  end

  def downcase_username
    self.username = self.username.downcase if self.username.present?
  end

end

我无法弄清楚这会被绊倒。

1 个答案:

答案 0 :(得分:2)

错误是由nil:密码引起的。看起来像before_save:prepare_password过滤器正在运行并抛出该错误。但是使用before_save似乎不正确,因为每次更新人员时都会发生这种情况,每次都会重新加密密码。将它更改为before_create所以它只发生一次。如果它仍然抛出错误,你可以做一些事情来解决它,或者:

def encrypt_password(pass)
  Digest::SHA1.hexdigest(pass.to_s) # will change nils into strings and this won't blow up
end

或在您的测试用例中添加密码参数:

it "create action should render new template when model is invalid" do
  Person.any_instance.stub(:valid?).and_return(false)
  post :create, :password => "" # invalid password
  response.should render_template(:new)
end

这样控制器将收到params[:password]并将字符串传递给Person.new