How to disable before_action in controller spec?

I used this in the controller spec:

controller.class.skip_before_action

      

Specifically in this case:

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

      

And the complete 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 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 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

      

Do you see something wrong with this? I don't understand how controller.class.skip_before_action: require_authorisation_to_view_materials works, and I had some strange things that happened before when you used this (but I'm not sure if this is to blame). Can anyone explain what this line does and if mine

controller.class.before_action :require_authorisation_to_view_materials

      

does it really have the intended effect of "switching" before_action "back" to "material_controller"? Does my code mean BOM?

+3


source to share


1 answer


When executing controller specs and fake login, I like to use wait to exclude authorization.

i.e. in your situation:

  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

      



Or even better

  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

      

+4


source







All Articles