如何在控制器规范中禁用before_action?

我在我的控制器规范中使用了这个:

controller.class.skip_before_action 

具体来说,在这种情况下:

controller.class.skip_before_action:require_authorisation_to_view_materials

MaterialsController:

 class MaterialsController < ApplicationController before_action :set_material, only: [:show, :edit, :update, :destroy] before_action :require_authorisation_to_view_materials, only: [:index, :show] def require_authorisation_to_view_materials # For Materials Page unless user_signed_in? && current_user.can_view_materials? redirect_to root_path, alert: "You are not authorised to view the Materials page." end end # GET /materials # GET /materials.json def index @materials = Material.all end # GET /materials/1 # GET /materials/1.json def show end # GET /materials/new def new @material = Material.new end # GET /materials/1/edit def edit end # POST /materials # POST /materials.json def create @material = Material.new(material_params) respond_to do |format| if @material.save format.html { redirect_to materials_path, notice: 'Material was successfully created.' } format.json { render :show, status: :created, location: @material } else format.html { render :new } format.json { render json: @material.errors, status: :unprocessable_entity } end end end # PATCH/PUT /materials/1 # PATCH/PUT /materials/1.json def update respond_to do |format| if @material.update(material_params) format.html { redirect_to materials_path, notice: 'Material was successfully updated.' } format.json { render :show, status: :ok, location: @material } else format.html { render :edit } format.json { render json: @material.errors, status: :unprocessable_entity } end end end # DELETE /materials/1 # DELETE /materials/1.json def destroy @material.destroy respond_to do |format| format.html { redirect_to materials_url, notice: 'Material was successfully deleted.' } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_material @material = Material.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def material_params params.require(:material).permit(:title, :level, :description, :link) end end 

而完整的material_controller_spec:

 require "rails_helper.rb" describe MaterialsController do before :each do controller.class.skip_before_action :require_authorisation_to_view_materials end after :each do controller.class.before_action :require_authorisation_to_view_materials end describe "GET #index" do it "populates an array of materials (@materials)" do material1, material2 = (FactoryGirl.create :material), (FactoryGirl.create :material) get :index expect(assigns(:materials)).to eq([material1, material2]) end it "renders the index view" do get :index expect(response).to render_template :index end end describe "GET #show" do it "assigns the requested material to @material" do material = FactoryGirl.create :material get :show, id: material expect(assigns(:material)).to eq(material) end it "renders the #show view" do get :show, id: FactoryGirl.create(:material) expect(response).to render_template :show end end describe "POST #create" do context "with VALID attributes" do it "creates new material" do expect { post :create, material: FactoryGirl.attributes_for(:material) }.to change(Material, :count).by(1) end it "redirects to the materials page" do post :create, material: FactoryGirl.attributes_for(:material) expect(response).to redirect_to :materials end end context "with INvalid attributes" do it "does not create new material" do expect { post :create, material: FactoryGirl.attributes_for(:invalid_material) }.to_not change(Material, :count) end it "re-renders the #new method" do post :create, material: FactoryGirl.attributes_for(:invalid_material) expect(response).to render_template :new end end end describe "PUT #update" do before :each do @material = FactoryGirl.create :material, title: "Title", level: "B2", description: "blah blah", link: "Dropbox Link" end context "valid attributes" do it "locates the requested @material" do put :update, id: @material, material: FactoryGirl.attributes_for(:material) expect(assigns :material).to eq @material end it "changes @material's attributes" do put :update, id: @material, material: FactoryGirl.attributes_for(:material, title: "Title", level: "A1", description: "blah blah", link: "Dropbox Link") @material.reload expect(@material.title).to eq("Title") expect(@material.level).to eq("A1") expect(@material.description).to eq("blah blah") end it "redirects to the materials page" do put :update, id: @material, material: FactoryGirl.attributes_for(:material) expect(response).to redirect_to :materials end end context "invalid attributes" do it "locates the requested @material" do put :update, id: @material, material: FactoryGirl.attributes_for(:invalid_material) expect(assigns :material).to eq @material end it "does not change @material's attributes" do put :update, id: @material, material: FactoryGirl.attributes_for(:material, title: nil, level: "B1", description: "description", link: "Dropbox Link") @material.reload expect(@material.title).to eq("Title") expect(@material.level).to_not eq("B1") expect(@material.description).to eq("blah blah") end it "re-renders the edit method" do put :update, id: @material, material: FactoryGirl.attributes_for(:invalid_material) expect(response).to render_template :edit end end end describe "DELETE destroy" do before :each do @material = FactoryGirl.create :material end it "deletes the material" do expect{ delete :destroy, id: @material }.to change(Material, :count).by(-1) end it "redirects to materials#index" do delete :destroy, id: @material expect(response).to redirect_to :materials end end end 

你能看到这个有什么问题吗? 我实际上并不理解controller.class.skip_before_action:require_authorisation_to_view_materials是如何工作的,而且在使用它之前我已经发生了一些奇怪的事情(但我不确定这是否应该受到指责)。 有人可以解释一下这行是什么,如果我的话

 controller.class.before_action :require_authorisation_to_view_materials 

确实在material_controller中有’切换’before_action”的预期效果? 我的规范代码看起来不错吗?

在进行控制器规范和伪造登录时,我喜欢使用期望来取消授权。

即在你的情况下:

  require "rails_helper.rb" describe MaterialsController do before :each do allow(controller).to receive(:require_authorisation_to_view_materials).and_return(true) end #..snip end 

甚至更好

  require "rails_helper.rb" describe MaterialsController do before :each do allow(controller).to receive(:current_user).and_return(FactoryGirl.create(:admin_user) end #..snip end