1

我正在阅读 Michael Hartl 的 RoR 4.0 教程,目前正在做第 9 章的第一个练习。

我应该编写一个测试来确认无法发出 PATCH 请求来编辑用户的admin属性。为了防止批量分配,本教程引入了一个user_params函数,它只允许某些属性。

在测试中,我发出

patch user_path(user), params

其中params是一个散列,其中包含admin的值(见下文)。在这个请求之后,我希望用户的属性仍然是false

这就是问题所在

虽然测试(正确)使用我当前的代码成功,但当我将 admin 属性添加到 user_params 函数中允许的属性列表时,它也(错误地成功

使用 curl 向 /users/:id 发出 PATCH 请求会给出一个我还不太了解的错误页面。我试过用 PUT 替换 PATCH,在某处读到对这种方法的支持是相当新的,并认为我可能没有每个 gem 的正确版本。我使用的是 ruby​​ 1.9.3,而本教程使用的是 2.x。

我在这里有什么遗漏吗?(有关如何在 rails 控制台中模拟这些请求的任何提示也会有所帮助!)

我在下面粘贴了我正在使用的代码的相关部分:


代码:

应用程序/控制器/users_controller.rb

    类用户控制器 < 应用控制器
      before_action :signed_in_user,仅:[:edit, :update, :index, :destroy]
      before_action :correct_user,仅:[:edit, :update]
      before_action :admin_user,仅: :destroy

      ...
        定义更新
            @user = User.find(params[:id])
            如果@user.update_attributes(user_params)
                登录@用户
                flash[:success] = "配置文件已更新"
                重定向到@用户
            别的
                渲染“编辑”
            结尾
        结尾

      ...

        私人的

            定义用户参数
                params.require(:user).permit(:name, :email, :password,
                                       :password_confirmation, :admin)
            结尾
      ...

规范/功能/users_pages_spec.rb

...
    describe "edit page" do
        let(:user) { FactoryGirl.create(:user) }
        before do
            sign_in user
            visit edit_user_path(user)
        end
...
        describe "directly patch forbidden admin attribute" do
            let(:params) do
              { user: { admin: true, password: user.password, password_confirmation: user.password } }
            end

            before { 
              patch user_path(user), params
            }
            specify {  expect(user.reload).not_to be_admin }
        end
...

应用程序/模型/user.rb

class User < ActiveRecord::Base
    before_save { 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.encrypt(token)
        Digest::SHA1.hexdigest(token.to_s)
    end

    private

        def create_remember_token
            self.remember_token = User.encrypt(User.new_remember_token)
        end
end
4

1 回答 1

3

前几天我也遇到了同样的问题。如日志所示

Redirected to http://www.example.com/signin
Filter chain halted as :signed_in_user rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.7ms)

没有使测试变为红色的原因是由于在用户控制器中定义的过滤器之前的 signed_in_user 。因此,登录用户可以解决您遇到的“将测试变为红色/绿色”问题。

describe "forbidden attributes" do
  let(:params) do
    { user: { admin: true, password: user.password,
      password_confirmation: user.password } }
  end
  before { 
    sign_in user, no_capybara: true
    patch user_path(user), params 
  }
  specify { expect(user.reload).not_to be_admin }
end

插入 sign_in 后,您的测试应该是红色/绿色,具体取决于控制器中定义的强参数。

希望这有助于您入门。

最好的,本。

PS:但是,我没有花太多精力去调查为什么提到的 before_filter 得出用户没有登录的结论......

于 2013-08-12T20:09:44.100 回答