Using factory_girl_rails with Rspec on namespaced models
Asked Answered
C

5

36

I have a web service that serves Ads to several different clients. The structure of the Ad varies between clients, and therefore, I am using namespaces for my models and controllers by the client name to differentiate between Ads. From the high level, it looks like this:

'app/models/client1/ad.rb'

class Client1::Ad < ActiveRecord::Base
  attr_accessible :title, :description
end

'app/models/client2/ad.rb'

class Client2::Ad < ActiveRecord::Base
  attr_accessible :title, :description, :source
end

In reality, these models are more complex and have associations, but that is not the point.
I am writing some unit tests using rspec-rails 2.4.0 and factory_girl_rails 1.0.1, and all of my factories work great. However, I am not able to define factories for the namespaced models. I've tried something like:

Factory.define :client1_ad, :class => Client1::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
end  

and

Factory.define :client2_ad, :class => Client2::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
  ad.source      "feed"
end

It didn't do the job. I looked around, but every single example that I saw was using non-namespaced models. Anyone have any ideas? Any input is greatly appreciated.

Capitally answered 14/6, 2011 at 20:2 Comment(0)
R
49

I have a minimal working example here, maybe you could use it to pinpoint where your problem is. The comment you left on dmarkow's answer suggests to me that you have an error someplace else.

app/models/bar/foo.rb

class Bar::Foo < ActiveRecord::Base
end

*db/migrate/20110614204536_foo.rb*

class Foo < ActiveRecord::Migration
  def self.up
    create_table :foos do |t|
      t.string :name
    end
  end

  def self.down
    drop_table :foos
  end
end

spec/factories.rb

Factory.define :foo, :class => Bar::Foo do |f|
  f.name 'Foooo'
end

*spec/models/foo_spec.rb*

require 'spec_helper'

describe Bar::Foo do

  it 'does foo' do
    foo = Factory(:foo)
    foo.name.should == 'Foooo'
  end
end

Running the test:

$ rake db:migrate
$ rake db:test:prepare
$ rspec  spec/models/foo_spec.rb 
.

Finished in 0.00977 seconds
1 example, 0 failures

Hope it helps.

Raphaelraphaela answered 14/6, 2011 at 20:53 Comment(2)
Thanks a lot for your very detailed answer, Jorge. Seems like my problem was that I did not run rake db:test:prepare. Accepted, voted up.Capitally
I'm curious, shouldn't your tablename be bar_foos instead of foos?Francisco
D
12

I think maybe FactoryGirl changes since this answer was posted. I did to make it work

Factory.define do
  factory :foo, :class => Bar::Foo do |f|
    f.name 'Foooo'
  end
end
Depreciable answered 7/2, 2014 at 18:32 Comment(0)
G
8

With the current latest version of FactoryGirl (4.5.0), this is the syntax:

FactoryGirl.define do
  factory :client1_ad, class: Client1::Ad do |f|
    f.title       "software tester"
    f.description "Immediate opening"
  end
end

Notice that client1_ad can be whatever name you want coz we already force identifying its class name.

Gifted answered 13/7, 2015 at 2:59 Comment(0)
B
2

I found this question looking into a related issue with FactoryGirl and after a little reading of the source I figured out I could solve my problem by renaming my factories.

When I had model classes that were namespaced inside modules, eg: Admin::User I should have been defining my factories like this:

factory :'admin/user', class: Admin::User do
  #...
end

Rather than:

factory :admin_user, class: Admin::User do
  #...
end

Maybe this little tidbit of info might help someone someday. The specifics of my issue was that I was trying to use build(described_class) to build instances from factories in my RSpec specs and this works just fine with un-namespaced classes but not with classes inside modules. The reason is that internally when looking up factories FactoryGirl will use ActiveSupport's underscore helper to normalise the factory name.

Bink answered 28/10, 2016 at 1:9 Comment(0)
M
0

Have you tried passing the actual class, rather than a string with the class name:

Factory.define :client1_ad, :class => Client1::Ad do |ad|
Macmahon answered 14/6, 2011 at 20:6 Comment(1)
Just tried. Didn't work. I get 'undefined method is' for #<Class:0xbea9024> (NoMethodError)'.I've also tried: Factory.define Client1::Ad do |ad|Capitally

© 2022 - 2024 — McMap. All rights reserved.