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?
source to share
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
source to share