-I have managed to write tests for these associations for the models , now am stuck forthe controllers.
require 'rails_helper'
RSpec.describe 'Payments', type: :request do
let(:valid_attributes) do
{ first_name: 'mutebi', last_name: 'godfrey', phone_number: '+256780140670', address: 'kampala', money_paid: '6000', date: '25/08/2023',
nin_number: 'KK45896587450P', user_id: '5', home_id: '9' }
end
let(:invalid_attributes) do
skip('Add a hash of attributes invalid for your model')
end
describe 'GET /index' do
it 'renders a successful response' do
Payment.create! valid_attributes
get payments_url, headers: valid_headers, as: :json
expect(response).to be_successful
end
end
describe 'GET /show' do
it 'renders a successful response' do
payment = Payment.create! valid_attributes
get payment_url(payment), as: :json
expect(response).to be_successful
end
end
end
1) Payments GET /index renders a successful response
Failure/Error: Payment.create! valid_attributes
ActiveRecord::RecordInvalid:
Validation failed: User must exist, Home must exist
# ./spec/requests/payments_spec.rb:17:in `block (3 levels) in <main>'
2) Payments GET /show renders a successful response
Failure/Error: payment = Payment.create! valid_attributes
ActiveRecord::RecordInvalid:
Validation failed: User must exist, Home must exist
# ./spec/requests/payments_spec.rb:25:in `block (3 levels) in <main>'
# frozen_string_literal: true
module Api
module V1
class PaymentsController < ApplicationController
before_action :authenticate_user!
before_action :set_payment, only: %i[show edit update destroy]
# GET /payments or /payments.json
def index
if user_signed_in?
@payments = current_user.payments.order(created_at: :desc)
render json: @payments.to_json(include: %i[home user])
else
render json: {}, status: 401
end
end
# GET /payments/1 or /payments/1.json
def show
@payment = current_user.payments.find(params[:id])
render json: @payment.to_json(include: %i[home user])
end
# GET /payments/new
def new
@home = Home.find(params[:home_id])
@payment = @home.payments.new
end
# GET /payments/1/edit
def edit; end
# POST /payments
def create
@home = Home.find(params[:home_id])
@payment = @home.payments.create(payment_params) do |p|
p.user = current_user # if user_signed_in?
end
if @payment.save
render json: @payment.to_json(include: %i[home user])
else
render json: @payment.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /payments/1 or /payments/1.json
def update
@home = Home.find(params[:home_id])
@payment = @home.payments.find(params[:id])
if @payment.update
render json: { notice: 'Payment was successfully updated.' },
status: :ok
else
render json: { error: 'Unable to update payment' },
status: :unprocessable_entity
end
end
# DELETE /payments/1 or /payments/1.json
def destroy
@home = Home.find(params[:home_id])
@payment = @home.payments.find(params[:id])
@payment.destroy
render json: { notice: 'Payment succefully removed' }
end
private
# Use callbacks to share common setup or constraints between actions
def set_payment
@payment = Payment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def payment_params
params.require(:payment).permit(:first_name, :last_name, :phone_number, :address, :money_paid, :date,
:nin_number, :user_id, :home_id)
end
end
end
end
You haven't really understood what factories are or how to use them. Factories should generate unique data that you can use in your tests.
So to clean up your factory you could use the ffaker
gem to generate psuedo random data instead of your own personal data (which you shouldn't be using like this):
FactoryBot.define do
factory :payment do
first_name { FFaker::Name.first_name }
last_name { FFaker::Name.last_name }
phone_number { FFaker::PhoneNumberNL.international_mobile_phone_number }
address { FFaker::Address.street_address }
money_paid { FFaker::Number.decimal }
nin_number { FFaker::Identification.ssn }
user # DO NOT HARDCODE ID's!
home # DO NOT HARDCODE ID's!
end
end
Using psuedo random data in your tests avoids your tests becoming reliant on information outside the test. This one of the biggest reasons why you would use factories instead of fixtures.
You then use the factory in your specs in the test setup phase:
require 'rails_helper'
RSpec.describe 'Payments', type: :request do
let(:payment) { FactoryBot.create(:payment) }
describe 'GET /index' do
let!(:payments) { FactoryBot.create_list(:payment, 5) }
it 'renders a successful response' do
get payments_url, headers: valid_headers, as: :json
expect(response).to be_successful
end
end
describe 'GET /show' do
it 'renders a successful response' do
get payment_url(payment), as: :json
expect(response).to be_successful
end
it 'has the correct JSON' do
get payment_url(payment), as: :json
expect(response.parsed_body).to match(a_hash_including(
payment.attributes.slice(
"first_name", "last_name", "address" # ...
)
))
end
end
end