1

I have a User model with two roles: member and admin and defaults to member. This model has two required attributes payout_bank and payout_account and they are only required to be present if the role is member.

My FactoryGirl for User has two traits that corresponds to the roles. I then add the two required attributes to the member trait, but when I create an User with member trait with linting turned on FactoryGirl will complain that the required attributes are failing validation because they're blank.

If I turn off linting it will correctly generate a member User with payout_bank and payout_account filled out. What's going on?

Model User.rb

class User < ActiveRecord::Base
  validates_presence_of :payout_bank, :payout_account, if: :member?

  def set_default_role
    self.role ||= :member
  end
end

Factory User.rb

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@email.com" }
    password "password"

    trait :member do
      sequence(:email) { |n| "member#{n}@email.com" }
      role "member"
      payout_bank { Faker::Company.name }
      payout_account { Faker::Number.number(10) }
    end

    trait :admin do
      sequence(:email) { |n| "admin#{n}@email.com" }
      role "admin"
      status "active"
    end
  end
end

Creating user from Factory

FactoryGirl.lint
FactoryGirl.create(:member_user, :member)

Output

FactoryGirl::InvalidFactoryError: The following factories are invalid:
* member_user - Validation Failed: payout_bank cannot be blank, payout_account cannot be blank (ActiveRecord::RecordInvalid)/usr/local/lib/ruby/gems/2.3.0/gems/factory_girl-4.7.0/lib/factory_girl/linter.rb:12:in `lint!'
Brian
  • 51
  • 1
  • 4

2 Answers2

0

You have to write the validation tests in spec/models directrory. Something like.

require 'rails_helper' require "validates_email_format_of/rspec_matcher"

RSpec.describe BankAccount, type: :model do

  it "should have a account number" do
    bank_a = build(:bank_account, account_no: '')
    expect(bank_a).to_not be_valid
  end

end
Pulkit Agarwal
  • 594
  • 1
  • 9
  • 22
  • Could you help me understand why is the test needed? Does it plug into FactoryGirl's linting? – Brian Apr 14 '16 at 04:00
  • FactroyGirl basically replaces fixtures in tests. – Pulkit Agarwal Apr 14 '16 at 04:04
  • Above tests are failing as you have provided the validation in your User Model, until and unless you pass those validation tests it will keep on giving you error. – Pulkit Agarwal Apr 14 '16 at 04:06
  • I don't entirely understand your comments, I'll have to do more research to see what you're talking about. In the meanwhile I found out where my issue is, and I posted an answer below. Hopefully I didn't get anything wrong. – Brian Apr 14 '16 at 04:10
  • Ah sorry to mislead you. My usage of FactoryGirl in this case isn't for testing, it's to generate dummy data so my website doesn't look so empty while I develope. So this shouldn't be concerned with RSpec and testing. – Brian Apr 14 '16 at 04:25
0

I found out that FactoryGirl.lint is the line that blew up and caught the validation failure. The issue here is that linting will try to create generic User model with no traits. Since my User model defaults to member role, and this role requires payout_bank and payout_account to be present, the validation thus failed.

The solution is to move these two attributes out of the member trait and into the base in the factory.

Something like this

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@email.com" }
    password "password"
    payout_bank { Faker::Company.name } # Move here
    payout_account { Faker::Number.number(10) } # Move here

    trait :member do
      sequence(:email) { |n| "member#{n}@email.com" }
      role "member"
    end

    trait :admin do
      sequence(:email) { |n| "admin#{n}@email.com" }
      role "admin"
      status "active"
      payout_bank nil
      payout_account nil
    end
  end
end
Brian
  • 51
  • 1
  • 4