Rails - How to pass controller tests when I use before_action - ruby-on-rails

I need to run some tests and I have come at a stand still here.
I am using before_action in my Appointments controller
Here is the controller
class AppointmentsController < ApplicationController
before_action :set_appointment, only: %i[ show edit update destroy ]
#before we run anything if the user is not signed in show index and show functions
before_action :authenticate_user!, except: [:index,:show]
#only the correct user can edit,update and destroy
before_action :correct_user, only: [:edit, :update , :destroy]
# GET /appointments or /appointments.json
def index
#appointments = Appointment.all.decorate
end
# GET /appointments/1 or /appointments/1.json
def show
end
# GET /appointments/new
def new
##appointment = Appointment.new
#appointment = current_user.appointments.build
end
# GET /appointments/1/edit
def edit
end
#function to allow for search functionality
def search
#appointments = Appointment.where("date LIKE?", "%"+params[:q]+"%")
end
# POST /appointments or /appointments.json
def create
##appointment = Appointment.new(appointment_params)
#appointment = current_user.appointments.build(appointment_params)
#here underneath I am using my custom gem to filter bad words within the notes field when creating an appointment
#appointment.notes = Badwordgem::Base.sanitize(#appointment.notes)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointment_url(#appointment), notice: "Appointment was successfully created." }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1 or /appointments/1.json
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to appointment_url(#appointment), notice: "Appointment was successfully updated." }
format.json { render :show, status: :ok, location: #appointment }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1 or /appointments/1.json
def destroy
#appointment.destroy
respond_to do |format|
format.html { redirect_to appointments_url, notice: "Appointment was successfully destroyed." }
format.json { head :no_content }
end
end
#function here that restricts editing so the current logged in user can edit only their records
def correct_user
#appointment = current_user.appointments.find_by(id: params[:id])
redirect_to appointments_path, notice:"NOT ALLOWED TO EDIT THIS" if #appointment.nil?
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
#appointment = Appointment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def appointment_params
params.require(:appointment).permit(:barber, :customer, :notes, :date,:user_id)
end
end
and here is my test controller
require "test_helper"
class AppointmentsControllerTest < ActionDispatch::IntegrationTest
Devise::Test::IntegrationHelpers
setup do
#appointment = appointments(:one)
end
test "should get index" do
get appointments_url
assert_response :success
end
test "should get new" do
get new_appointment_url
assert_response :success
end
test "should create appointment" do
assert_difference('Appointment.count') do
post appointments_url, params: { appointment: { barber: #appointment.barber, customer: #appointment.customer, date: #appointment.date, notes: #appointment.notes } }
end
assert_redirected_to appointment_url(Appointment.last)
end
test "should show appointment" do
get appointment_url(#appointment)
assert_response :success
end
test "should get edit" do
get edit_appointment_url(#appointment)
assert_response :success
end
test "should update appointment" do
patch appointment_url(#appointment), params: { appointment: { barber: #appointment.barber, customer: #appointment.customer, date: #appointment.date, notes: #appointment.notes } }
assert_redirected_to appointment_url(#appointment)
end
test "should destroy appointment" do
assert_difference('Appointment.count', -1) do
delete appointment_url(#appointment)
end
assert_redirected_to appointments_url
end
end
If I comment out the "before actions" in my controller , of course all the tests pass but with them 15 tests fail.
How do I make the tests pass with the before_action ?

For :authenticate_user just use the helper log_in in te test, after create a user, like this:
class AppointmentsControllerTest < ActionDispatch::IntegrationTest
let(:user) { User.new(user_params) }
......
and put
sign_ig user
inside each 'it methods you want'
For :set_appointment or :correct_user just passing right id params inside the path's call

Related

Rails test failure 500 when I use .includes

I'm developing a small e-commerce and I´ve a problem when I run the tests for my cart controller.
here cart controller
class CartsController < ApplicationController
include CurrentCart #modul current_cart in controllers/concerns
before_action :set_cart, only: [:show, :edit, :update, :destroy]
before_action :set_current_cart, only: [:index]
# GET /carts
# GET /carts.json
def index
respond_to do |format|
format.html { redirect_to #cart, notice: 'Line item was successfully created.' }
format.json { render :show, status: :created, location: #line_item }
end
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
#cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: #cart }
else
format.html { render :new }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: #cart }
else
format.html { render :edit }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart.destroy if #cart.id == session[:cart_id]
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to catalog_index_url, notice: 'Cart was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
#cart = Cart.includes(line_items: :product).find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params.fetch(:cart, {})
end
end
and here my tests:
require 'test_helper'
class CartsControllerTest < ActionDispatch::IntegrationTest
setup do
#line_item = line_items(:one)
#product = products(:one)
#cart = carts(:one)
end
test "should get index" do
get carts_url
assert_response :success
end
test "should get new" do
get new_cart_url
assert_response :success
end
test "should create cart" do
assert_difference('Cart.count') do
post carts_url, params: { cart: {} }
end
assert_redirected_to cart_url(Cart.last)
end
test "should show cart" do
get cart_url(#cart)
assert_response :success
end
test "should get edit" do
get edit_cart_url(#cart)
assert_response :success
end
test "should update cart" do
patch cart_url(#cart), params: { cart: {} }
assert_redirected_to cart_url(#cart)
end
test "should destroy cart" do
post line_items_url, params: { product_id: products(:one).id }
#cart = Cart.find(session[:cart_id])
assert_difference('Cart.count', -1) do
delete cart_url(#cart)
end
assert_redirected_to catalog_index_url
end
end
here the results:
Failure: CartsControllerTest#test_should_destroy_cart Expected
response to be a <3XX: redirect>, but was a <500: Internal Server
Error>
Failure: CartsControllerTest#test_should_get_edit Expected response
to be a <2XX: success>, but was a <500: Internal Server Error>
Failure: CartsControllerTest#test_should_update_cart Expected
response to be a <3XX: redirect>, but was a <500: Internal Server
Error>
here is the modul current cart for the cartsController:
module CurrentCart
private
def set_current_cart
#cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
#cart = Cart.create
session[:cart_id] = #cart.id
end
end
I think that the problem is here:
if I remove this in the method set_cart from the cart controller: .includes(line_items: :product) the tests will run perfectly without failure, but I cannot understand why.
(I put the include because otherwise I get this error when I access the cart from the browser:
USE eager loading detected LineItem => [:product] Add to your
finder: :includes => [:product] Call stack
UPDATE:
I found something interesting in the file "test.log" :
Bullet::Notification::UnoptimizedQueryError - user: claudio
DELETE /carts/980190963
AVOID eager loading detected
LineItem => [:product]
Remove from your finder: :includes => [:product]
Call stack
##here there's a path##.rb:45:in `block (2 levels) in <class:CartsControllerTest>'
##here there's a path##:in `block in <class:CartsControllerTest>'

RSpec undefined method `request='

I am getting the following error from a RSpec get request:
1) Flight GET/index displays flights
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `request=' for #<Flight:0x00000006a2ad68>
Here is my spec/requests/flights_spec.rb :
require 'rails_helper'
require 'spec_helper'
require 'flight'
RSpec.describe Flight, type: :controller do
describe 'GET/index', :type => :request do
it 'displays flights' do
Flight.create!(:destination => 'San Francisco')
get :index
response.body.should include('San Francisco')
end
end
end
Here is my spec/controllers/flights_controller_spec.rb:
require 'rails_helper'
RSpec.describe FlightsController, type: :controller do
describe 'GET index' do
end
end
Here is my app/controllers/flights_controller.rb:
class FlightsController < ApplicationController
before_action :set_flight, only: [:show, :edit, :update, :destroy]
# GET /flights
# GET /flights.json
def index
#flights = Flight.all
end
# GET /flights/1
# GET /flights/1.json
def show
end
# GET /flights/new
def new
#flight = Flight.new
end
# GET /flights/1/edit
def edit
end
# POST /flights
# POST /flights.json
def create
#flight = Flight.new(flight_params)
respond_to do |format|
if #flight.save
format.html { redirect_to #flight, notice: 'Flight was successfully created.' }
format.json { render :show, status: :created, location: #flight }
else
format.html { render :new }
format.json { render json: #flight.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /flights/1
# PATCH/PUT /flights/1.json
def update
respond_to do |format|
if #flight.update(flight_params)
format.html { redirect_to #flight, notice: 'Flight was successfully updated.' }
format.json { render :show, status: :ok, location: #flight }
else
format.html { render :edit }
format.json { render json: #flight.errors, status: :unprocessable_entity }
end
end
end
# DELETE /flights/1
# DELETE /flights/1.json
def destroy
#flight.destroy
respond_to do |format|
format.html { redirect_to flights_url, notice: 'Flight was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_flight
#flight = Flight.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def flight_params
params.require(:flight).permit(:departure, :arrival, :destination, :baggage_allowance, :capacity)
end
end
Not sure what's gong on - any help appreciated - thanks in advance,
Slavko
At the top of your spec you've got
RSpec.describe Flight, type: :controller
But then just below
describe "GET /index", type: :request
You've got to pick one or the other (from what's in the spec you probably want a controller spec)
In addition for a controller spec the described object should be a controller class, not a model class.

Controller Name Error

I have added a module to my application called Tokened.rb and added the include Tokened to my model. However, now when I try to load that model, I get a "NameError in TestingsController#index" error... I haven't included Tokened in my TestingsController, but not sure why I should or where I should put it.
My code:
testing.rb
class Testing < ActiveRecord::Base
include Tokened
end
My Tokened.rb module:
module Tokened
extend ActiveSupport::Concern
included do
after_initialize do
self.token = generate_token if self.token.blank?
end
end
private
def generate_token
loop do
key = SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
break key unless self.class.find_by(token: key)
end
end
end
Finally, my testing controller:
class TestingsController < ApplicationController
before_action :set_testing, only: [:show, :edit, :update, :destroy]
# GET /testings
# GET /testings.json
def index
#testings = Testing.all
end
# GET /testings/1
# GET /testings/1.json
def show
end
# GET /testings/new
def new
#testing = Testing.new
end
# GET /testings/1/edit
def edit
end
# POST /testings
# POST /testings.json
def create
#testing = Testing.new(testing_params)
respond_to do |format|
if #testing.save
format.html { redirect_to #testing, notice: 'Testing was successfully created.' }
format.json { render :show, status: :created, location: #testing }
else
format.html { render :new }
format.json { render json: #testing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /testings/1
# PATCH/PUT /testings/1.json
def update
respond_to do |format|
if #testing.update(testing_params)
format.html { redirect_to #testing, notice: 'Testing was successfully updated.' }
format.json { render :show, status: :ok, location: #testing }
else
format.html { render :edit }
format.json { render json: #testing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /testings/1
# DELETE /testings/1.json
def destroy
#testing.destroy
respond_to do |format|
format.html { redirect_to testings_url, notice: 'Testing was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_testing
#testing = Testing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def testing_params
params.require(:testing).permit(:name, :address, :signature)
end
end
What gives? I am not sure what is going on here and why it needs to be included in the controller.
First of all it should be lowercased: tokened.rb. But where is your file? It should be here modules/concerns/tokened.rb.

NoMethodError : undefined method `find' for nil:NilClass

I want show a daycare details on show page but I got this error
NoMethodError : undefined method `find' for nil:NilClass
from daycare controller file and i'm not get any idea. I have mentioned below that error line.
This is my Controller file
class DayCaresController < ApplicationController
before_filter :authenticate_user!
before_action :set_day_care, only: [:show, :edit, :update, :destroy]
# GET /day_cares
# GET /day_cares.json
def index
#day_cares = DayCare.all
end
# GET /day_cares/1
# GET /day_cares/1.json
def show
end
# GET /day_cares/new
def new
#day_care = DayCare.new
end
# GET /day_cares/1/edit
def edit
end
# POST /day_cares
# POST /day_cares.json
def create
#day_care = current_user.build_day_care(day_care_params)
respond_to do |format|
if #day_care.save
UserMailer.welcome_email(#user).deliver
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully created.'} }
format.json { render :show, status: :created, location: #day_care }
else
format.html { render :new }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /day_cares/1
# PATCH/PUT /day_cares/1.json
def update
respond_to do |format|
if #day_care.update(day_care_params)
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully updated.'} }
format.json { render :show, status: :ok, location: #day_care }
else
format.html { render :edit }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# DELETE /day_cares/1
# DELETE /day_cares/1.json
def destroy
#day_care.destroy
respond_to do |format|
format.html { redirect_to day_cares_url, :gflash => { :success => 'Day care was successfully destroyed.'} }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions
def set_day_care
#day_care = current_user.day_care.find(params[:id]) # => **I got error this line**
end
# Never trust parameters from the scary internet, only allow the white list through.
def day_care_params
params.require(:day_care).permit(:name, :address, :office_phone, :cell_phone, :logo, :website, :user_id)
end
def dashboard
end
def profile
end
end
If user has_many: day_cares then use this name instead of day_care:
#day_care = current_user.day_cares.where(id: params[:id]).take
or probably as you wrote:
#day_care = current_user.day_cares.find(params[:id])
But with arrays instead of single instance (day_cares).
Also you can use just:
#day_care = DayCare.find(params[:id])
If you search by id. Or if you need to check that it's users day_care:
#day_care = DayCare.where(id: params[:id], user: current_user).take
current_user.day_care.find is not available, because you can only perform queries on plural associations. So given that the model associations are setup correctly as:
class User < ActiveRecord:Base
has_many :day_cares
...
end
the solution is probably just to resolve the spelling error from
`current_user.day_care.find` #wrong!
to
`current_user.day_cares.find` #right!

undefined method for nil:NilClass in RSpec

I'm using RSpec, and I get this error when running tests:
Failure/Error: before { get edit_job_path(job) }
NoMethodError:
undefined method `jobs' for nil:NilClass
# ./app/controllers/jobs_controller.rb:63:in `correct_user'
# ./spec/requests/authentication_pages_spec.rb:35:in `block (6 levels) in <top (required)>'
The actual behavior of the page (when doing rails server) seems fine. Why is the test not working? I'm still a beginner to Ruby/Rails, so any help would be appreciated.
Some code for help:
authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin" do
[...]
describe "authorization" do
describe "for non-signed in users" do
describe "when attempting to visit a protected page" do
let(:user) { FactoryGirl.create(:user) }
let(:job) { FactoryGirl.create(:job, user: user) }
before { get edit_job_path(job) }
it { should_not have_content('Editing job') }
describe "after signing in" do
[...]
end
[...]
end
end
[...]
end
end
end
jobs_controller.rb
class JobsController < ApplicationController
before_action :signed_in_user, only: [:new, :create, :update]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :set_job, only: [:show, :edit, :update, :destroy]
def index
#jobs = Job.all
end
def show
end
def new
#job = Job.new
end
def edit
end
def create
#job = current_user.jobs.build(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render action: 'show', status: :created, location: #job }
else
format.html { render action: 'new' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def destroy
#job.destroy
respond_to do |format|
format.html { redirect_to jobs_url }
format.json { head :no_content }
end
end
private
def set_job
#job = Job.find(params[:id])
end
def job_params
params.require(:job).permit(:title, :org, :internship, :postdate, :filldate, :location, :link, :description)
end
def correct_user
#job = current_user.jobs.find_by(id: params[:id])
redirect_to root_url, notice: 'You can only edit your own jobs.' if #job.nil?
end
end
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Johnny #{n}" }
sequence(:email) { |n| "johnny_#{n}#example.com" }
password "sampleton"
password_confirmation "sampleton"
end
factory :job do
sequence(:title) { |n| "Example Title #{n}" }
user
end
end
sessions_helper.rb
module SessionsHelper
[...]
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
[...]
def signed_in?
!current_user.nil?
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
[...]
def store_location
session[:return_to] = request.url if request.get?
end
[...]
end
Your test seems to be working fine in that they've uncovered a bug. Your action expects that current_user be set, and it isn't, so you're getting an error.
You need a before_filter which redirects you when you hit a page that requires authorization.

Resources