I've employed the use of this in my 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 full materials_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
Can you see anything wrong with this? I don't actually understand how the controller.class.skip_before_action :require_authorisation_to_view_materials works, and I've had some weird things happen before when using this (but I'm not sure if this was to blame). Could someone explain what this line does exactly, and if my
controller.class.before_action :require_authorisation_to_view_materials
does actually have the intended effect of 'switching' the before_action 'back on' in the materials_controller? Does my spec code look ok?
After you determine the required Action’s Controller, follow the steps below to remove or disable the Action: Override the Controller ‘s OnActivated method. Use the GetController method or the Frame. Controllers ( Window.Controllers) property to access the Controller.
An action (or action method) is a method on a controller which handles requests. Controllers logically group similar actions together. This aggregation of actions allows common sets of rules, such as routing, caching, and authorization, to be applied collectively. Requests are mapped to actions through routing. By convention, controller classes:
Use the GetController method or the Frame. Controllers ( Window.Controllers) property to access the Controller. Use the Actions property of the Controller class ( YourController.Actions ["YourActionId"]) or built-in Controller properties (for example, NewObjectViewController.NewObjectAction) to access an Action.
Use the Conditional Appearance module. You can enable and disable Actions based on the specified rules (for example, disable an Action based on business object properties). Refer to the following topic for more information: Declare Conditional Appearance Rules in Code.
When doing controller specs and faking login I like to use an expectation to stub out authorisation instead.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With