Учебник по Ruby on Rails Глава 10 Упражнение RSpec Failures - PullRequest
1 голос
/ 29 июня 2011

Я работаю над упражнениями из главы 10 Rails Tutorial и наткнулся на загадку с упражнением, которое заставило меня убедиться, что администратор не может удалить себя. Моя первоначальная идея состояла в том, чтобы просто проверить идентификатор текущего пользователя и сравнить его с params [: id], чтобы убедиться, что они не равны. Мое действие уничтожения в контроллере Users выглядело так:

def destroy
  if current_user.id == params[:id].to_i
    flash[:notice] = "You cannot delete yourself."
  else
    User.find(params[:id]).destroy
    flash[:success] = "User destroyed."
  end
  redirect_to users_path
end

Это прекрасно работает, когда я тестирую его вручную в приложении, но 3 из моих тестов RSpec не проходят с той же ошибкой "undefined method 'to_i'" (как показано ниже):

1) UsersController DELETE 'destroy' as an admin user should destory the user
   Failure/Error: delete :destroy, :id => @user
     NoMethodError:
       undefined method `to_i' for #<User:0x000001032de188>
   # ./app/controllers/users_controller.rb:48:in `destroy'
   # ./spec/controllers/users_controller_spec.rb:310:in `block (5 levels) in <top (required)>'
   # ./spec/controllers/users_controller_spec.rb:309:in `block (4 levels) in <top (required)>'

2) UsersController DELETE 'destroy' as an admin user should redirect to the users page
   Failure/Error: delete :destroy, :id => @user
     NoMethodError:
       undefined method `to_i' for #<User:0x000001032b5850>
   # ./app/controllers/users_controller.rb:48:in `destroy'
   # ./spec/controllers/users_controller_spec.rb:315:in `block (4 levels) in <top (required)>'

3) UsersController DELETE 'destroy' as an admin user should not allow you to destroy self
   Failure/Error: delete :destroy, :id => @admin
     NoMethodError:
       undefined method `to_i' for #<User:0x0000010327e350>
   # ./app/controllers/users_controller.rb:48:in `destroy'
   # ./spec/controllers/users_controller_spec.rb:321:in `block (5 levels) in <top (required)>'
   # ./spec/controllers/users_controller_spec.rb:320:in `block (4 levels) in <top (required)>'

Если я использую params [: id], чтобы найти пользователя и сравнить его с current_user, как у меня ниже, тогда он будет работать как в приложении, так и в RSpec.

def destroy
  if current_user == User.find(params[:id])
    flash[:notice] = "You cannot delete yourself."
  else
    User.find(params[:id]).destroy
    flash[:success] = "User destroyed."
  end
  redirect_to users_path
end

Почему в RSpec возникает проблема с методом "to_i"? Если кому-то интересно, я склоняюсь к такому подходу, потому что я подумал, что лучше просто сравнить текущий идентификатор пользователя с идентификатором пользователя, которого нужно удалить (через params [: id]), вместо того, чтобы нажимать db, чтобы «найти» пользователь.

Для справки это мой тест RSpec:

  describe "DELETE 'destroy'" do
    before(:each) do
        @user = Factory(:user)
    end 

    ...

    describe "as an admin user" do
      before(:each) do
        @admin = Factory(:user, :email => "admin@example.com", :admin => true)
        test_sign_in(@admin)
      end

      it "should destory the user" do
        lambda do
          delete :destroy, :id => @user
        end.should change(User, :count).by(-1)
      end

      it "should redirect to the users page" do
        delete :destroy, :id => @user
        response.should redirect_to(users_path)
      end

      it "should not allow you to destroy self" do
        lambda do
          delete :destroy, :id => @admin
        end.should change(User, :count).by(0)
        response.should redirect_to(users_path)
        flash[:notice].should =~ /cannot delete yourself/
      end
    end
  end

Буду признателен за любую помощь!

1 Ответ

1 голос
/ 29 июня 2011

В своих спецификациях попробуйте использовать @user.id вместо @user в параметре :id (я понимаю, что в Tutorial говорится, что нужно просто использовать @user, но что-то может происходить там, где идентификатор не работает должным образом экстрагированный):

delete :destroy, :id => @user.id

Но вы можете рассмотреть реструктуризацию примерно так:

@user = User.find(params[:id])
if current_user == @user
  flash[:notice] = "You cannot delete yourself."
else
  @user.destroy
  flash[:success] = "User destroyed."
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...