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
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
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)
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.
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
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