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

时间:2015-05-19 13:39:59

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

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

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''的预期效果?我的规范代码看起来不错吗?

1 个答案:

答案 0 :(得分:6)

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

即。在你的情况下:

  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