Ruby on rails 如何在Rails和RSpec中销毁回调后进行测试?

Ruby on rails 如何在Rails和RSpec中销毁回调后进行测试?,ruby-on-rails,ruby-on-rails-3,rspec,rspec2,rspec-rails,Ruby On Rails,Ruby On Rails 3,Rspec,Rspec2,Rspec Rails,我在Ruby on Rails中有一个User类: class User < ActiveRecord::Base after_destroy :ensure_an_admin_remains private def ensure_an_admin_remains if User.where("admin = ?", true).count.zero? raise "Can't delete Admin." end end end 无论

我在Ruby on Rails中有一个
User
类:

class User < ActiveRecord::Base

  after_destroy :ensure_an_admin_remains

  private

  def ensure_an_admin_remains
    if User.where("admin = ?", true).count.zero?
      raise "Can't delete Admin."
    end
  end

end
无论何时运行此测试,都会出现以下错误:

Failure/Error: expect{
count should have been changed by -1, but was changed by 0
但是不应该有任何错误,因为默认情况下,
@user
的admin属性设置为false

有人能帮我吗

谢谢…

我可能错了,但是, 你的规范是从空数据库开始的,对吗?因此,数据库中没有管理员用户。 因此,当您调用delete时,User.where(“admin=?”,true).count始终等于零

在测试之前尝试创建一个用户管理员

describe 'DELETE #destroy' do

  before :each do
    create(:admin_user)
    @user = create(:non_admin_user)
    sign_in(@user)
  end

  it "deletes the user" do
    expect{ 
      delete :destroy, id: @user
    }.to change(User, :count).by(-1)
  end

end
我可能错了,但是, 你的规范是从空数据库开始的,对吗?因此,数据库中没有管理员用户。 因此,当您调用delete时,User.where(“admin=?”,true).count始终等于零

在测试之前尝试创建一个用户管理员

describe 'DELETE #destroy' do

  before :each do
    create(:admin_user)
    @user = create(:non_admin_user)
    sign_in(@user)
  end

  it "deletes the user" do
    expect{ 
      delete :destroy, id: @user
    }.to change(User, :count).by(-1)
  end

end

我会作出以下更改:

before_destroy :ensure_an_admin_remains

def ensure_an_admin_remains
  if self.admin == true and User.where( :admin => true ).count.zero?
    raise "Can't delete Admin."
  end
end

我会作出以下更改:

before_destroy :ensure_an_admin_remains

def ensure_an_admin_remains
  if self.admin == true and User.where( :admin => true ).count.zero?
    raise "Can't delete Admin."
  end
end

另一种方法是使被调用的函数
确保“管理”保持为公共函数,例如
检查“管理”保持为公共函数

然后,您可以测试,
check\u admin\u的逻辑仍然保持
,就好像它是任何其他函数一样

然后在另一个测试中,您可以确保在不进行任何数据库交互的情况下调用destroy函数,如下所示:

let(:user) { build_stubbed(:user) }

it 'is called on destroy' do
  expect(user).to receive(:check_admin_remains)

  user.run_callbacks(:destroy)
end

另一种方法是使被调用的函数
确保“管理”保持为公共函数,例如
检查“管理”保持为公共函数

然后,您可以测试,
check\u admin\u的逻辑仍然保持
,就好像它是任何其他函数一样

然后在另一个测试中,您可以确保在不进行任何数据库交互的情况下调用destroy函数,如下所示:

let(:user) { build_stubbed(:user) }

it 'is called on destroy' do
  expect(user).to receive(:check_admin_remains)

  user.run_callbacks(:destroy)
end

你不应该为了控制流量而升高。您可以在回调期间停止,以防止提交记录

我已经改进了这里的一些答案,以供其他人在Rails 5中尝试如何正确地实现这一点

class User < ActiveRecord::Base
  before_destroy :ensure_an_admin_remains

  private def ensure_an_admin_remains
    return unless admin && User.where(admin: true).limit(2).size == 1
    errors.add(:base, "You cannot delete the last admin.")
    throw :abort
  end
end
class用户
您不应该为控制流而提升。您可以在回调期间停止,以防止提交记录

我已经改进了这里的一些答案,以供其他人在Rails 5中尝试如何正确地实现这一点

class User < ActiveRecord::Base
  before_destroy :ensure_an_admin_remains

  private def ensure_an_admin_remains
    return unless admin && User.where(admin: true).limit(2).size == 1
    errors.add(:base, "You cannot delete the last admin.")
    throw :abort
  end
end
class用户
应该是验证应该是验证这同样有效,甚至不需要我更改规范文件。谢谢这同样有效,甚至不需要我更改规范文件。谢谢在
之后的
应该是在
之前的
吗?在
之后的
应该是在
之前的
吗?