Jake
Jake

Reputation: 1380

Factory Bot Failures in Rails App

So I have the following models: Regions and Locations. They look fine and I can load up the page just fine. The issue gets with factory bot.

class Region < ApplicationRecord
 scope :ordered, -> { order(name: :desc) }
 scope :search, ->(term) { where('name LIKE ?', "%#{term}%") }
 has_many :locations, dependent: :destroy
end

class Location < ApplicationRecord
 scope :ordered, -> { order(name: :desc) }
 scope :search, ->(term) { where('name LIKE ?', "%#{term}%") }
 belongs_to :region
end

For my factories I have the following:

FactoryBot.define do
 factory :region do
  name 'MyString'
 end
end

FactoryBot.define do
 factory :location do
 name 'MyString'
 hours_operation 'MyString'
 abbreviation 'MyString'
 region nil
 end
end

Both of those were rendered easily enough and the only change I made to them was switching out double quotations with single quotations. But when I run a bin/test I keep getting the following errors: Admin::LocationsController show should render the show page Failure/Error: location = FactoryBot.create(:location) ActiveRecord::RecordInvalid:Validation failed: Region must exist

Then a coordinating example of the failure: rspec ./spec/controllers/admin/locations_controller_spec.rb:16 # Admin::LocationsController show should render the show page

So I check out spec/controllers/admin/locations_controller_spec.rb and here's the code:

require 'rails_helper'

RSpec.describe Admin::LocationsController, type: :controller do
 before(:each) do
   activate_session(admin: true)
 end

describe 'index' do
  it 'should render the index' do
    get :index
    expect(response).to have_http_status :success
   end
 end

 describe 'show' do
  it 'should render the show page' do
   location = FactoryBot.create(:location)
   get :show, params: { id: location.id }
   expect(response).to have_http_status :success
  end

  it 'should return a 404 error' do
    get :show, params: { id: 1 }
    expect(response).to have_http_status :not_found
  end
end
describe 'new' do
  it 'should render the new page' do
    get :new
    expect(response).to have_http_status :success
  end
end

describe 'edit' do
  it 'should render the edit page' do
    location = FactoryBot.create(:location)
    get :edit, params: { id: location.id }
    expect(response).to have_http_status :success
  end
end

describe 'create' do
  it 'should create the record' do
    expect do
      post :create, params: { location: 
  FactoryBot.attributes_for(:location) }
    end.to change(Location, :count).by(1)
  end
end

describe 'update' do
  it 'should update the record' do
    location = FactoryBot.create(:location)
    current_value = location.name
    new_value = current_value + '-Updated'
    expect do
      patch :update, params: { id: location.id, location: { name: new_value } }
      location.reload
    end.to change(location, :name).to(new_value)
  end
end

describe 'destroy' do
  it 'should destroy the record' do
    location = FactoryBot.create(:location)
    expect do
      delete :destroy, params: { id: location.id }
    end.to change(Location, :count).by(-1)
  end
 end
end

The line it's references is: it 'should render the show page'.

Honestly I don't know what's causing it to fail. I thought it might be an association issues but when I went to try and do something like associations :location it caused even more errors to populate. Am I just missing something in the spec controllers for association?

EDIT/UPDATE: Fixed five of the six errors using association :region in location. But I'm getting: Failure/Error: expect do post :create, params: { location: FactoryBot.attributes_for(:location) } end.to change(Location, :count).by(1) expected #count to have changed by 1, but was changed by 0.

Upvotes: 0

Views: 1462

Answers (1)

Subash
Subash

Reputation: 3168

You can create associations in factory-bot using after_create, try this

FactoryBot.define do
 factory :location do
  name 'MyString'
  hours_operation 'MyString'
  abbreviation 'MyString'
  after(:create) do |location, evaluator|
   location.region = FactoryBot.create(:region)
  end
 end

end

All this is doing is creating a region object and associating it to the location object.

See here for more detailed guides Factory Bot Guides

Upvotes: 0

Related Questions