1

I'm trying to run some tests on a model "Click".

# models/click_spec.rb
describe Click do
    it "should have a valid constructor" do
        FactoryGirl.create(:click).should be_valid
    end
end

The objective is that the model uses two tables that have the same country. I don't want to use a sequence for the country (as I found for Emails). But it raise this error:

Validation failed: Name has already been taken, Slug has already been taken

The problem is that it seems that it create twice the country [name:"United States", slug:"us"]

Here's the factories used.

# factories/countries.rb
FactoryGirl.define do
    factory :country do
        name "United States"
        slug "us"
    end
end

# factories/offers.rb
FactoryGirl.define do
    factory :offer do
        association :country, factory: :country
        # Other columns
    end
end

# factories/users.rb
FactoryGirl.define do
    factory :user do
        association :country, factory: :country
        # Other columns
    end
end

# factories/clicks.rb
FactoryGirl.define do
    factory :click do
        association :offer, factory: :offer
        association :user, factory: :user
        # Other columns
    end
end

and the model of Country:

class Country < ActiveRecord::Base
    validates :name, :slug,
    presence: true,
    uniqueness: { case_sensitive: false }

    validates :slug,
    length: { is: 2 }

end

I've tried to change the association strategy to something like this:

association :country, factory: :country, strategy: :build

But it raise this error:

Validation failed: Country can't be blank

Any idea?

Thanks,

Simo
  • 464
  • 3
  • 16

1 Answers1

2

As per the shared code,

when you call FactoryGirl.create(:click),

it will go to execute factory :click where it finds association :offer, factory: :offer which in turn calls factory: :offer where you create a country with name "United States" and slug "us" for the first time.

Again, in factory :click, it finds association :user, factory: :user which in turn calls factory: :user where you create a country again with the same name "United States" and slug "us" for the second time.

Issue #1: Validation failed: Name has already been taken, Slug has already been taken

The above error is because of the uniqueness constraint on Country model for name and slug.

Issue #2: Validation failed: Country can't be blank

When you do association :country, factory: :country, strategy: :build then strategy: :build only creates an instance of Country, it does create a record in database.

The Country can't be blank error is because you didn't create a country record in the database for user and offer. And you must be having a validation presence: true in these two models for country OR schema level check of not null.

Kirti Thorat
  • 52,578
  • 9
  • 101
  • 108
  • The thing is that the association :user should use the Country that was created by the association :offer. Something like the `find_or_initialize_by` of ActiveRecord. – Simo Apr 04 '14 at 22:14
  • Refer to `factory_girl` documentation at https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations Its not find_or_initialize_by BUT create – Kirti Thorat Apr 04 '14 at 22:18
  • Yes, I've already read it, but didn't help to solve my issue. I was wondering if there's an equivalent for `find_or_initialize_by` in FactoryGirl that could fix my issue (I used `create` in the my question). – Simo Apr 04 '14 at 22:21
  • Now, your question is getting changed. Your original question was `FactoryGirl Name “can't be blank” VS “already taken”` and my answer explains why. Post another question for it as chaining or modifying original question via comment is not a good practice. – Kirti Thorat Apr 04 '14 at 22:26
  • Done. There's a uniqueness constraint on Country, but my main issue is that it create twice the same record of Country when I call once `FactoryGirl.create(:click)` – Simo Apr 04 '14 at 22:32
  • Post another question means a totally new question for `find_or_initialize_by in FactoryGirl` and NOT to modify the current question. My answer explains why you were getting error `FactoryGirl Name “can't be blank” VS “already taken”`. – Kirti Thorat Apr 04 '14 at 22:38
  • Also, for your reference FactoryGirl does not offer find_or_initialize_by feature. See which all methods you can use here: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#using-factories – Kirti Thorat Apr 04 '14 at 22:42
  • Okay thanks, however it should be something that I'm missing, it must be common use case. Btw, I just cleaned up things. The new question is here : http://stackoverflow.com/questions/22874292/find-or-initialize-by-in-factorygirl – Simo Apr 04 '14 at 22:51
  • So What happens to this question? If it resolved `FactoryGirl Name “can't be blank” VS “already taken”` issue then accept it. – Kirti Thorat Apr 04 '14 at 23:05
  • I don't think that it's the solution for this question. As I already mentioned in my question that the model country have 'uniqueness: { case_sensitive: false }' constraint. Since there's two errors “can't be blank” and “already taken” in the both cases, the issue is still unsolved. – Simo Apr 04 '14 at 23:42
  • @simox See my updated answer. This should resolve both your questions. – Kirti Thorat Apr 05 '14 at 00:01