How to convert database calls with mocks/doubles, in Rails and Rspec? - ruby-on-rails

I am working on a reminder scheduler and used rails scaffold to create the models and views for the reminder. So far I have the controller looks like this:
class RemindersController < ApplicationController
before_action :set_reminder, only: [:show, :edit, :update, :destroy]
##reminder_hash = {}
##scheduler = Rufus::Scheduler.singleton
def index
#reminders = Reminder.all
end
def new
#reminder = Reminder.new
end
def edit
end
def create
#reminder = Reminder.new(reminder_params)
respond_to do |format|
if #reminder.save
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully created.') }
format.json { render :show, status: :created, location: #reminder }
schedule_reminder #reminder.id, #reminder.reminder_day, #reminder.reminder_time
else
format.html { render :new }
format.json { render json: #reminder.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #reminder.update(reminder_params)
# Unschedule the job.
jobs = ##scheduler.jobs(tag: #reminder.id)
jobs.each { |job| ##scheduler.unschedule(job) }
# Reschedule the job at the new time.
schedule_reminder #reminder.id, #reminder.reminder_day, #reminder.reminder_time
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully updated.') }
format.json { render :show, status: :ok, location: #reminder }
else
format.html { render :edit }
format.json { render json: #reminder.errors, status: :unprocessable_entity }
end
end
end
def destroy
#reminder.destroy
respond_to do |format|
jobs = ##scheduler.jobs(tag: #reminder.id)
jobs.each { |job| ##scheduler.unschedule(job) }
format.html { redirect_to reminders_url, notice: I18n.t('Reminder was successfully destroyed.') }
format.json { head :no_content }
end
end
# Internal: Schedule reminder to be sent at appropriate time.
#
# id - The Reminder id used to uniquely identify the job associated with that reminder.
# reminder day - The day when the reminder will be sent.
# reminder time - The time when the reminder will be sent.
#
# Returns nothing.
def schedule_reminder(tag, reminder_day, reminder_time)
minute = reminder_time.strftime('%M')
hour = reminder_time.strftime('%H')
day = reminder_day[0...3].upcase
cron_string = '0 ' + minute + ' ' + hour + ' * * ' + day
##scheduler.cron cron_string, tag: tag do
EmailController.mentor_reminder_email_sender
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_reminder
#reminder = Reminder.find(params[:id])
end
# Whitelist the paramters.
def reminder_params
params.fetch(:reminder, {}).permit(:reminder_day, :reminder_time)
end
end
The spec looks like this:
require 'rails_helper'
RSpec.describe RemindersController, type: :controller do
let(:valid_attributes) {
{ id: 1, reminder_day: :monday, reminder_time: Time.now}
}
let(:invalid_attributes) {
{ id: nil, reminder_day: nil, reminder_time: nil}
}
let(:valid_session) { {} }
describe 'DELETE #destroy' do
it 'destroys the requested reminder' do
reminder = Reminder.create! valid_attributes
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create! valid_attributes
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
describe '#create' do
let(:reminder) { Reminder.new(id: 1, reminder_day: 1, reminder_time: Time.now) }
let(:reminders_controller) { RemindersController.new }
context 'with valid params' do
before do
allow(controller).to receive(:schedule_reminder)
end
it 'creates a new Reminder' do
expect {
post :create, {reminder: valid_attributes}, valid_session
}.to change(Reminder, :count).by(1)
end
it 'assigns a newly created reminder as #reminder' do
post :create, {reminder: valid_attributes}, valid_session
expect(assigns(:reminder)).to be_a(Reminder)
expect(assigns(:reminder)).to be_persisted
end
it 'calls schedule_reminder with correct parameters' do
expect(reminders_controller).to receive(:schedule_reminder)
.with(reminder.id, reminder.reminder_day, reminder.reminder_time)
reminders_controller.schedule_reminder(reminder.id, reminder.reminder_day, reminder.reminder_time)
end
end
context 'with invalid params' do
it 'assigns a newly created but unsaved reminder as #reminder' do
post :create, {reminder: invalid_attributes}, valid_session
expect(assigns(:reminder)).to be_a_new(Reminder)
end
it 're-renders the "new" template' do
post :create, {reminder: invalid_attributes}, valid_session
expect(response).to render_template('new')
end
it 'does not call schedule_reminder' do
expect(controller).to_not receive(:schedule_reminder)
end
end
end
describe 'PUT #update' do
context 'with valid params' do
let(:new_attributes) {
{ id: 2, reminder_day: :tuesday, reminder_time: Time.now}
}
let(:reminders_controller) { RemindersController.new }
let(:reminder) { Reminder.new(id: 1, reminder_day: 1, reminder_time: Time.now) }
it 'updates the requested reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: new_attributes}, valid_session
reminder.reload
end
it 'calls reminder scheduler function with correct parameters' do
post :create, {reminder: valid_attributes}, valid_session
expect(reminders_controller).to receive(:schedule_reminder)
.with(reminder.id, reminder.reminder_day, reminder.reminder_time)
reminders_controller.schedule_reminder(reminder.id, reminder.reminder_day, reminder.reminder_time)
end
it 'assigns the requested reminder as #reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: valid_attributes}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
it 'redirects to the reminder' do
reminder = Reminder.create! valid_attributes
put :update, { id: reminder.to_param, reminder: valid_attributes}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
context 'with invalid params' do
it 'assigns the reminder as #reminder' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
it 're-renders the "edit" template' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(response).to render_template('edit')
end
it 'does not call schedule_reminder' do
expect(controller).to_not receive(:schedule_reminder)
end
end
end
describe 'GET #index' do
it 'assigns all reminders as #reminders' do
reminder = Reminder.create! valid_attributes
get :index, {}, valid_session
expect(assigns(:reminders)).to eq([reminder])
end
end
describe 'GET #new' do
it 'assigns a new reminder as #reminder' do
get :new, {}, valid_session
expect(assigns(:reminder)).to be_a_new(Reminder)
end
end
describe 'GET #edit' do
context 'when reminder is found' do
it 'assigns the requested reminder as #reminder' do
reminder = Reminder.create! valid_attributes
get :edit, {id: reminder.to_param}, valid_session
expect(assigns(:reminder)).to eq(reminder)
end
end
context 'when reminder is not found' do
it 're-renders the "edit" template' do
reminder = Reminder.create! valid_attributes
put :update, {id: reminder.to_param, reminder: invalid_attributes}, valid_session
expect(response).to render_template('edit')
end
end
end
end
I am trying to replace all the create statements with a mock/double to eliminate database calls. I have tried replacing all create statements with this:
reminder = double('Reminder', id: 1, reminder_day: :monday, reminder_time: Time.now)
and other variations.
I replaced this :
describe 'DELETE #destroy' do
it 'destroys the requested reminder' do
reminder = Reminder.create! valid_attributes
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create! valid_attributes
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
with this:
describe 'DELETE #destroy' do
let(:reminder){double('Reminder', id: 1, reminder_day: :monday, reminder_time: Time.now)}
before do
allow(Reminder).to receive(:create).and_return(reminder)
end
it 'destroys the requested reminder' do
reminder = Reminder.create
expect {
delete :destroy, {id: reminder.to_param}, valid_session
}.to change(Reminder, :count).by(-1)
end
it 'does not call reminder scheduler function' do
post :create, {reminder: valid_attributes}, valid_session
expect(controller).to_not receive(:schedule_reminder)
end
it 'redirects to the reminders list' do
reminder = Reminder.create
delete :destroy, {id: reminder.to_param}, valid_session
expect(response).to redirect_to(reminders_path)
end
end
I'm getting these errors:
Failure/Error: expect(response).to redirect_to(reminders_path)
Expected response to be a , but was <404>
Failure/Error: expect {
expected #count to have changed by -1, but was changed by 0

Related

rspec: failure/error: _send_(method, file). syntaxError: 104: syntax error, unexpected keyword_end, expecting end-of-input

After doing the bundle exec rspec in the terminal window. I received two errors: [Failure/Error: send(method, file) and Syntax Error: /vagrant/src/grammable/spec/controllers/grams_controller_spec.rb:104: syntax error, unexpected keyword_end, expecting end-of-input]. I am unable to passing the test due to 1 error occurred outside of examples.
require 'rails_helper'
RSpec.describe GramsController, type: :controller
describe "grams#update action" do
it "should allow users to successfully update grams" do
gram = FactoryBot.create(:gram, message: "Initial Value")
patch :update, params: { id: gram.id, gram: { message: 'Changed' } }
expect(response).to redirect_to root_path
gram.reload
expect(gram.message).to eq "Changed"
end
it "should have http 404 error if the gram cannot be found" do
patch :update, params: { id: "YOLOSWAG", gram: { message: 'Changed' } }
expect(response).to have_http_status(:not_found)
end
it "should render the edit form with an http status of unprocessable_entity" do
gram = FactoryBot.create(:gram, message: "Initial Value")
patch :update, params: { id: gram.id, gram: { message: '' } }
expect(response).to have_http_status(:unprocessable_entity)
gram.reload
expect(gram.message).to eq "Initial Value"
end
end
describe "grams#edit action" do
it "should successfully show the edit form if the gram is found" do
gram = FactoryBot.create(:gram)
get :edit, params: { id: gram.id }
expect(response).to have_http_status(:success)
end
it "should return a 404 error message if the gram is not found" do
get :edit, params: { id: 'SWAG' }
expect(response).to have_http_status(:not_found)
end
end
describe "grams#show action" do
it "should successfully show the page if the gram is found" do
gram = FactoryBot.create(:gram)
get :show, params: { id: gram.id }
expect(response).to have_http_status(:success)
end
it "should return a 404 error if the gram is not found" do
get :show, params: { id: 'TACOCAT' }
expect(response).to have_http_status(:not_found)
end
end
describe "grams#index action" do
it "should successfully show the page" do
get :index
expect(response).to have_http_status(:success)
end
end
describe "grams#new action" do
it "should require users to be logged in" do
get :new
expect(response).to redirect_to new_user_session_path
end
it "should successfully show the new form" do
user = FactoryBot.create(:user)
sign_in user
get :new
expect(response).to have_http_status(:success)
end
end
describe "grams#create action" do
it "should require users to be logged in" do
post :create, params: { gram: { message: "Hello" } }
expect(response).to redirect_to new_user_session_path
end
it "should successfully create a new gram in our database" do
user = FactoryBot.create(:user)
sign_in user
post :create, params: { gram: { message: 'Hello!' } }
expect(response).to redirect_to root_path
gram = Gram.last
expect(gram.message).to eq("Hello!")
expect(gram.user).to eq(user)
end
it "should properly deal with validation errors" do
user = FactoryBot.create(:user)
sign_in user
post :create, params: { gram: { message: '' } }
expect(response).to have_http_status(:unprocessable_entity)
expect(Gram.count).to eq Gram.count
end
end
end
I think you have missed do in the first line RSpec.describe GramsController, type: :controller. Find below the edited code. Hope this helps!
require 'rails_helper'
RSpec.describe GramsController, type: :controller do
describe "grams#update action" do
it "should allow users to successfully update grams" do
gram = FactoryBot.create(:gram, message: "Initial Value")
patch :update, params: { id: gram.id, gram: { message: 'Changed' } }
expect(response).to redirect_to root_path
gram.reload
expect(gram.message).to eq "Changed"
end
it "should have http 404 error if the gram cannot be found" do
patch :update, params: { id: "YOLOSWAG", gram: { message: 'Changed' } }
expect(response).to have_http_status(:not_found)
end
it "should render the edit form with an http status of unprocessable_entity" do
gram = FactoryBot.create(:gram, message: "Initial Value")
patch :update, params: { id: gram.id, gram: { message: '' } }
expect(response).to have_http_status(:unprocessable_entity)
gram.reload
expect(gram.message).to eq "Initial Value"
end
end
describe "grams#edit action" do
it "should successfully show the edit form if the gram is found" do
gram = FactoryBot.create(:gram)
get :edit, params: { id: gram.id }
expect(response).to have_http_status(:success)
end
it "should return a 404 error message if the gram is not found" do
get :edit, params: { id: 'SWAG' }
expect(response).to have_http_status(:not_found)
end
end
describe "grams#show action" do
it "should successfully show the page if the gram is found" do
gram = FactoryBot.create(:gram)
get :show, params: { id: gram.id }
expect(response).to have_http_status(:success)
end
it "should return a 404 error if the gram is not found" do
get :show, params: { id: 'TACOCAT' }
expect(response).to have_http_status(:not_found)
end
end
describe "grams#index action" do
it "should successfully show the page" do
get :index
expect(response).to have_http_status(:success)
end
end
describe "grams#new action" do
it "should require users to be logged in" do
get :new
expect(response).to redirect_to new_user_session_path
end
it "should successfully show the new form" do
user = FactoryBot.create(:user)
sign_in user
get :new
expect(response).to have_http_status(:success)
end
end
describe "grams#create action" do
it "should require users to be logged in" do
post :create, params: { gram: { message: "Hello" } }
expect(response).to redirect_to new_user_session_path
end
it "should successfully create a new gram in our database" do
user = FactoryBot.create(:user)
sign_in user
post :create, params: { gram: { message: 'Hello!' } }
expect(response).to redirect_to root_path
gram = Gram.last
expect(gram.message).to eq("Hello!")
expect(gram.user).to eq(user)
end
it "should properly deal with validation errors" do
user = FactoryBot.create(:user)
sign_in user
post :create, params: { gram: { message: '' } }
expect(response).to have_http_status(:unprocessable_entity)
expect(Gram.count).to eq Gram.count
end
end
end

how to write test case for create and update actions in rspec?

Restaurant and Location models contains HABTM association.
how to write test cases for locations controller
def create
#restaurant = Restaurant.find(params[:restaurant_id])
#location = #restaurant.locations.create(location_params)
if #location.save
flash[:notice] = 'Location added!'
redirect_to admin_locations_path
else
flash[:error] = 'Failed to edit location!'
render :new
end
end
def update
#location = Location.find(params[:id])
if #location.update_attributes(location_params)
flash[:notice] = 'Location updated!'
redirect_to admin_locations_path
else
flash[:error] = 'Failed to edit Location!'
render :edit
end
end
Try the following code to create
restaurant = FactoryBot.create(:restaurant, name: Faker::Name.name)
post :create, params: { restaurant_id: restaurant.id, location: {restaurant_ids:[restaurant.id]}, format: 'js' }
expect(response).to have_http_status(:success)
Try the following code to update
restaurant = FactoryBot.create(:restaurant, name: Faker::Name.name)
location = FactoryBot.create(:location, restaurant_id: restaurant.id)
patch :update, params: { id: location.id, location: {restaurant_ids:[restaurant.id]}, format: 'js' }
expect(response).to have_http_status(:success)
You can simply create the spec using the following code snippet :
Restaurant = FactoryBot.create(:Restaurant, name: Faker::Name.name)
post :create, params: { location: {restaurant_ids:[Restaurant.id]}, format: 'json'
expect(response.status).to eq(200)
For simple controllers like this, I also like to ensure that the records are being created, so I would also test this:
restaurant = FactoryBot.create(:restaurant, name: Faker::Name.name)
expect {
post(
:create,
params: {
restaurant_id: restaurant.id,
location: { restaurant_ids:[restaurant.id] },
format: 'js'
}
)
}.to change{ Location.count }.by(1)

RSpec Controller tests fail for POST create

My program functions as expected, but there are problems in my RSpec controller test code. I need help troubleshooting the specs, which were created when I ran the scaffold generator. There are three "POST create with valid params" failures:
POST create
with valid params
creates a new Appointment (FAILED - 1)
assigns a newly created appointment as #appointment (FAILED - 2)
redirects to the created appointment (FAILED - 3)
Failures:
1) AppointmentsController POST create with valid params creates a new Appointment
Failure/Error: expect {
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/appointments_controller_spec.rb:90:in `block (4 levels) in <top (required)>'
2) AppointmentsController POST create with valid params assigns a newly created appointment as #appointment
Failure/Error: expect(assigns(:appointment)).to be_persisted
expected `#<Appointment id: nil, member_id: nil, trainer_id: nil, created_at: nil, updated_at: nil, date: "2020-01-02", starts_at: "2000-01-01 08:00:00", ends_at: "2000-01-01 09:00:00">.persisted?` to return true, got false
# ./spec/controllers/appointments_controller_spec.rb:99:in `block (4 levels) in <top (required)>'
3) AppointmentsController POST create with valid params redirects to the created appointment
Failure/Error: expect(response).to redirect_to(Appointment.last)
Expected response to be a <redirect>, but was <200>
# ./spec/controllers/appointments_controller_spec.rb:104:in `block (4 levels) in <top (required)>'
In the second failure, I notice there are nil values for appointment id, member and trainer, although I have valid factories for member and trainer. Tests for my member and trainer factories pass, and they work as expected. I assume the problem must be caused by the way I set up the "valid attributes" hash in the Controller spec, but I don't know what's wrong. Why are the POST create tests failing? What do I need to do to get them to pass?
Here's the code for the Appointments Controller RSpec:
require 'rails_helper'
RSpec.describe AppointmentsController, :type => :controller do
let(:valid_attributes) { {
'date' => '2020-01-02',
'starts_at' => '08:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}
let(:invalid_attributes) { {
'date' => '2000-01-02',
'starts_at' => '06:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}
let(:valid_session) { {
'date' => '2020-12-30',
'starts_at' => '15:00:00',
'ends_at' => '17:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}
describe "GET index" do
it "assigns all appointments as #appointments" do
appointment = Appointment.create! valid_attributes
get :index, {}, valid_session
expect(assigns(:appointments)).to eq([appointment])
end
end
describe "GET show" do
it "assigns the requested appointment as #appointment" do
appointment = Appointment.create! valid_attributes
get :show, {:id => appointment.to_param}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
end
describe "GET new" do
it "assigns a new appointment as #appointment" do
get :new, {}, valid_session
expect(assigns(:appointment)).to be_a_new(Appointment)
end
end
describe "GET edit" do
it "assigns the requested appointment as #appointment" do
appointment = Appointment.create! valid_attributes
get :edit, {:id => appointment.to_param}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Appointment" do
expect {
post :create, {:appointment => valid_attributes}, valid_session
}.to change(Appointment, :count).by(1)
save_and_open_page
end
it "assigns a newly created appointment as #appointment" do
post :create, {:appointment => valid_attributes}, valid_session
expect(assigns(:appointment)).to be_a(Appointment)
expect(assigns(:appointment)).to be_persisted
end
it "redirects to the created appointment" do
post :create, {:appointment => valid_attributes}, valid_session
expect(response).to redirect_to(Appointment.last)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved appointment as #appointment" do
post :create, {:appointment => invalid_attributes}, valid_session
expect(assigns(:appointment)).to be_a_new(Appointment)
end
it "re-renders the 'new' template" do
post :create, {:appointment => invalid_attributes}, valid_session
expect(response).to render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
let(:new_attributes) { {
'date' => '2020-01-02',
'starts_at' => '10:00:00',
'ends_at' => '12:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}
let(:invalid_attributes) { {
'date' => '2005-03-15',
'starts_at' => '04:00:00',
'ends_at' => '09:00:00',
'member' => FactoryGirl.build(:member),
'trainer' => FactoryGirl.build(:trainer)
}
}
it "updates the requested appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => new_attributes}, valid_session
appointment.reload
expect(controller.notice).to eq('Appointment was successfully updated.')
end
it "assigns the requested appointment as #appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => valid_attributes}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
it "redirects to the appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => valid_attributes}, valid_session
expect(response).to redirect_to(appointment)
end
end
describe "with invalid params" do
it "assigns the appointment as #appointment" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => invalid_attributes}, valid_session
expect(assigns(:appointment)).to eq(appointment)
end
it "re-renders the 'edit' template" do
appointment = Appointment.create! valid_attributes
put :update, {:id => appointment.to_param, :appointment => invalid_attributes}, valid_session
expect(response).to render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested appointment" do
appointment = Appointment.create! valid_attributes
expect {
delete :destroy, {:id => appointment.to_param}, valid_session
}.to change(Appointment, :count).by(-1)
end
it "redirects to the appointments list" do
appointment = Appointment.create! valid_attributes
delete :destroy, {:id => appointment.to_param}, valid_session
expect(response).to redirect_to(appointments_url)
end
end
end
Here's the code for the Appointments Controller:
class AppointmentsController < ApplicationController
before_action :set_appointment, only: [:show, :edit, :update, :destroy]
# GET /appointments
# GET /appointments.json
def index
#appointments = Appointment.all
end
# GET /appointments/1
# GET /appointments/1.json
def show
end
# GET /appointments/new
def new
#appointment = Appointment.new
end
# GET /appointments/1/edit
def edit
end
# POST /appointments
# POST /appointments.json
def create
#appointment = Appointment.new(appointment_params)
respond_to do |format|
if #appointment.save
format.html { redirect_to #appointment, notice: 'Appointment was successfully created.' }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1
# PATCH/PUT /appointments/1.json
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to #appointment, notice: 'Appointment was successfully updated.' }
format.json { render :show, status: :ok, location: #appointment }
else
format.html { render :edit }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1
# DELETE /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
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
#appointment = Appointment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def appointment_params
params.require(:appointment).permit(:date, :starts_at, :ends_at, :member_id, :trainer_id)
end
end
The code for the Appointment Model:
class Appointment < ActiveRecord::Base
belongs_to :member
belongs_to :trainer
validates_date :date, :on => :create, :on_or_after => :today
validates_time :starts_at, :between => ['06:30', '21:00']
validates_time :starts_at, :after => :now, :if => :today_appointment #scopes validation to current day only
validates_time :ends_at, :after => :starts_at
validate :duration_of_appointment
validates :member, :trainer, presence: true
validates :starts_at, :ends_at, :overlap => {
:exclude_edges => ["starts_at", "ends_at"],
:scope => "date",
:scope => "starts_at",
:scope => "trainer_id"
}
validates :starts_at, :ends_at, :overlap => {
:exclude_edges => ["starts_at", "ends_at"],
:scope => "member_id"
}
private
def today_appointment
Date.current == self.date
end
def duration_of_appointment
length = (ends_at - starts_at) / 60
return if length.between?(30, 120) # stops validation if length falls between the two integers
errors.add(:base, 'Duration must be between 30 and 120 minutes')
end
end
You shouldn't provide a built instance of Member and Trainer to controller. Instead, create Member and Trainer, and pass their ids as member_id,
trainer_id in valid_attributes hash.
First, create needed trainer and member:
before :each do
#trainer = FactoryGirl.build(:trainer)
#member = FactoryGirl.build(:member)
end
Then use their ids in your hash:
let(:valid_attributes) { {
'date' => '2020-01-02',
'starts_at' => '08:00:00',
'ends_at' => '09:00:00',
'member_id' => #member.id,
'trainer_id' => #trainer.id
}
In your code, you didn't even create them, you've only built them, but only changing build(:trainer) to create(:trainer) won't work in your case.

expecting <"index"> but render with <[]>

I'm having problems to pass a test in rails with rspec. This is what console tells me when I ran the tests.
The fail is ControlsController GET index logged in renders the index template
Failure/Error: expect(response). to render_template(:index)
expecting <"index"> but rendering with <[]>
And this is my code
require "rails_helper"
RSpec.describe ControlsController, :type => :controller do
render_views
describe "GET index" do
let(:user) {
FactoryGirl.create(:user)
}
let(:control) {
FactoryGirl.create(:control, user: user)
}
context "logged in" do
before :each do
sign_in :user, user
end
it "loads all controls into #controls" do
get :index, { user_id: user.id}
expect(assigns(:controls)).to eq([control])
end
it "assigns a new control to #control" do
get :index, { user_id: user.id}
expect(assigns(:control)).to be_a_new(Control)
end
it "renders the index template" do
get :index, { user_id: user.id}
expect(response). to render_template(:index)
end
it "a user can't see the controls from other user" do
new_user = User.create(name: "Juan",
email: "juan#gmail.com",
password: "123456789",
password_confirmation: "123456789")
get :index, { user_id: new_user.id}
expect(response).to redirect_to root_path
end
class ControlsController < ApplicationController
before_action :authenticate_user!
def index
#user= current_user
#control= Control.new
# #control_last = Control.lastcontrol (current_user.id)
# #controls_average = Control.controls_average (current_user.id)
# #controls_average_day = Control.controls_day_average (current_user.id)
#controls = Control.all
if params[:user_id] != current_user.id
redirect_to root_path
end
end
The answer is to make a private method and redirect_to user_controls_path current_user.name
This is the new code of the controller
controlsController.rb
class ControlsController < ApplicationController
before_action :authenticate_user!
before_action :redirect_if_not_current_user, only: :index
private
def control_params
params.require(:control).permit(:level, :period, :day)
end
def redirect_if_not_current_user
if params[:user_id] != current_user.name
redirect_to user_controls_path current_user.name
end
end

Rspec - controller test error - Paperclip::AdapterRegistry::NoHandlerError: No handler found for "#<File:0x531beb0>"

I asked about my Rspec test as follow.
Rspec - RuntimeError: Called id for nil, which would mistakenly be 4
On the same code (Rspec test for "items_controller.rb"), I am trying to make the test for "PUT update". However I got the error "Paperclip::AdapterRegistry::NoHandlerError: No handler found for "#".
My Rspec test is as follow. Honestly, I guess that the cause of this fail is ""photo" => File.new(Rails.root + 'app/assets/images/rails.png')" on "let(:valid_attributes)". However, I tried several ways but I couldn't fix.
By the way, my rails version is "Rails 3.2.14". Then I tried following post, but also couldn't.
Can't figure out what's causing my tests to fail
The error is as follows.
......F....
Failures:
1) ItemsController PUT update could not update successfully
Failure/Error: put :update, {:id => item.to_param, :item => valid_attributes}, valid_session
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for "#<File:0x5d4c548>"
# ./app/controllers/items_controller.rb:110:in `block in update'
# ./app/controllers/items_controller.rb:108:in `update'
# ./spec/controllers/items_controller_spec.rb:95:in `block (3 levels) in <top (required)>'
Finished in 1.75 seconds
11 examples, 1 failure
Failed examples:
rspec ./spec/controllers/items_controller_spec.rb:91 # ItemsController PUT update could not update successfully
Randomized with seed 40912
My Rspec test is as follows.
require 'spec_helper'
require 'date'
describe ItemsController do
let(:valid_attributes) { {
"days" => "1",
"hours" => "1",
"minutes" => "1",
"name"=>"HogeHoge" ,
"category" => "Gift",
"min_bid_price" => "100.0",
"description" => "HogeHoge",
"photo" => File.new(Rails.root + 'app/assets/images/rails.png')
} }
let(:valid_session) { {} }
it "returns http success" do
get "index"
response.should be_success
end
it "returns http success" do
get "new"
response.should be_success
end
describe "POST create" do
it "" do
#declare the objects and stubs
current_user = User.new(id:'1')
current_user.save
#"current_user=(user)" function on controller
controller.current_user = current_user
#auction
auction = Auction.new(id:'1',highest_bid_id:'1', extend_bit:'1')
auction.save
Auction.stub(:find_by_id).and_return(auction)
#bid
bid = Bid.new(auction_id:'1',amount:'150.0')
bid.save
Bid.stub(:find_by_id).and_return(bid)
#item
item = Item.new(id:'1',auction_id:'1',min_bid_price:'100.0')
item.save
Item.stub(:find_by_id).and_return(item)
date = DateTime.now
post :create, {:item => {'id' => '2','days'=>'1','hours'=>'1','minutes'=>'1','created_at'=>date}}
response.should be_success
end
end
describe "GET index" do
it "assigns all items as #items" do
item = Item.create! valid_attributes
get :index, {}, valid_session
assigns(:items).should eq([item])
end
end
describe "GET show" do
it "assigns the requested item as #item" do
item = Item.create! valid_attributes
get :show, {:id => item.to_param}, valid_session
assigns(:item).should eq(item)
end
end
describe "GET new" do
it "assigns a new item as #item" do
get :new, {}, valid_session
assigns(:item).should be_a_new(Item)
end
end
describe "GET edit" do
it "assigns the requested item as #item" do
item = Item.create! valid_attributes
get :edit, {:id => item.to_param}, valid_session
assigns(:item).should eq(item)
end
end
describe "PUT update" do
it "could not update successfully" do
item = Item.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Item.any_instance.stub(:save).and_return(false)
put :update, {:id => item.to_param, :item => valid_attributes}, valid_session
assigns(:item).should eq(item)
response.should redirect_to(#item)
end
it "could not update successfully" do
item = Item.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
Item.any_instance.stub(:save).and_return(false)
put :update, {:id => item.to_param, :item => { }}, valid_session
response.should render_template("edit")
end
end
describe "DELETE destroy" do
it "destroys the requested item" do
item = Item.create! valid_attributes
expect {
delete :destroy, {:id => item.to_param}, valid_session
}.to change(Item, :count).by(-1)
end
it "redirects to the items list" do
item = Item.create! valid_attributes
delete :destroy, {:id => item.to_param}, valid_session
response.should redirect_to(items_url)
end
end
end
My "items_controller.rb" is as follw.
require 'timers'
class ItemsController < ApplicationController
#instance of current user
def current_user=(user)
#current_user ||= user
end
def extendtimer
Auction.find_by_id(#auction_id).update_attributes(:extend_bit => 0)
#exp = Auction.find_by_id(#auction_id).exp_time + 2.minutes
Auction.find_by_id(#auction_id).update_attributes(:exp_time => #exp)
#min = Item.find_by_id(#item_id).minutes + 2
Item.find_by_id(#item_id).update_attributes(:minutes => #min)
#timer2 = Timers.new
#extend_timer = #timer2.after(120){ buy }
#timer2.wait
end
def buy
if Auction.find_by_id(#auction_id).extend_bit == 1
extendtimer
else
if Auction.find_by_id(#auction_id).highest_bid_id != 0
Item.find_by_auction_id(#auction_id).update_attributes(:sold => 1, :sold_to => Bid.find_by_id(Auction.find_by_id(#auction_id).highest_bid_id).user_id )
MyMailer.auction_winner_email(Auction.find_by_id(#auction_id)).deliver
else
Item.find_by_auction_id(#auction_id).update_attributes(:sold => 0, :sold_to => 0 )
MyMailer.no_bids_email(Auction.find_by_id(#auction_id)).deliver
end
#t1.join
end
end
def index
#items = Item.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #items }
end
end
# GET /items/1
# GET /items/1.json
def show
#item = Item.find(params[:id])
respond_to do |format|
#format.html # show.html.erb
format.html { render layout: (request.headers["X-Requested-With"] != 'XMLHttpRequest') }
format.json { render json: #item }
end
end
# GET /items/new
# GET /items/new.json
def new
#item = Item.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #item }
end
end
# GET /items/1/edit
def edit
#item = Item.find(params[:id])
end
# POST /items
# POST /items.json
def create
#item = Item.new(params[:item])
#item.user_id = current_user.id
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render json: #item, status: :created, location: #item }
else
format.html { render action: "new" }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
#elapsed_seconds =(((params[:item][:days].to_i * 24)+params[:item][:hours].to_i)*60+params[:item][:minutes].to_i)*60
#auction = Auction.create(:item_id => #item.id, :highest_bid_id => 0, :exp_time => #item.created_at+ #elapsed_seconds.seconds, :suspend => 0, :user_id => #current_user.id, :extend_bit => 0 )
#item.update_attributes(:auction_id => #auction.id)
#item_id = #item.id
#auction_id = #auction.id
#t1 = Thread.new{
#timer = Timers.new
#bid_timer = #timer.after(#elapsed_seconds){
if Auction.find_by_id(#auction_id).suspend != 1
buy
end
}
#timer.wait
}
end
# PUT /items/1
# PUT /items/1.json
def update
#item = Item.find(params[:id])
respond_to do |format|
if #item.update_attributes(params[:item])
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item = Item.find(params[:id])
#item.destroy
respond_to do |format|
format.html { redirect_to items_url }
format.json { head :no_content }
end
end
end
I would like to have someone's advice. Thank you in advance.
Try using Rack::Test::UploadedFile instead of File.new
require 'rack/test'
Rack::Test::UploadedFile.new('fixtures/test_file.png', 'image/png')
im pretty sure your problem is with the form_for in the view,
try something like this:
<%= form_for #restaurante, :html => { :multipart => true } do |form| %>
Nome:<%= form.text_field :nome%>
Endereço:<%= form.text_field :endereco %>
Especialidade:<%= form.text_field :especialidade %>
Foto:<%= form.file_field :foto %>
<%= form.submit 'create'%>
<% end %>
Make sure it's multipart/form-data in the test.
I have a helper method for this.
module Support
module Acceptance
module ClassMethods
def multipart_form_data!
header 'Accept', 'application/json'
header 'Content-Type', 'multipart/form-data'
end
end
end
end

Resources