How can I use FactoryBot in db/seeds? - ruby-on-rails

Is it possible to do this?
If so, how can you do it?
Note: FactoryBot was previously named FactoryGirl

All you need to do is add require 'factory_bot_rails' to the db/seeds.rb file. This will give you access to your factories.
Note: Gem was previously called FactoryGirlRails

Josh Clayton, the maintainer of FactoryGirl, recommends against using FactoryGirl in your seeds file. He suggests using plain ActiveRecord instead.

(This answer works in rails 3.0.7)
I found the catch is how you set up the Gemfile - you need to do something along the lines of
gem 'factory_girl'
group :test do
gem 'factory_girl_rails'
end
We found problems having factory_girl_rails outside of the :test environment, which we didn't manage to get to the bottom of (maybe something to do with the way rails does class caching?)
Once that is done, I like to actually load data from a library in lib, something like...
require 'factory_girl'
require 'spec/factories/user_factory'
module Seeds
class SampleUsers
def self.run
u = Factory(:user)
end
end
And then running this method from within db:seed using
Seeds::SampleUsers.run

in db/seeds.rb
require 'factory_girl_rails'
10.times do
FactoryGirl.create :user
end

In Rails 5.2.6, you can create factories in your db/seeds.rb file. Add include FactoryBot::Syntax::Methods at the top of your seeds.rb file. Below that line, you can create your factories – i.e. user1 = create(:user).
# db/seeds.rb
include FactoryBot::Syntax::Methods
user1 = create(:user)

You can insert the following code into your spec_helper.rb, and it make some instances of the data you want (in this case "products" from the yaml file):
seeds_file = File.join(Rails.root, 'db', 'seeds.yml')
config = YAML::load_file(seeds_file)
config["products"].each do |product|
FactoryGirl.create(:product, product) if !Product.find_by_name(product['name'])
end

Related

Rails ActiveSupport::TestCase - colourful output

Surprisingly, I didn't find the standard way to make the output of Rails Minitest colorful. There're some workarounds, though.
So what's the way to do that?
Add minitest-rg to the test group in your Gemfile:
group :test do
gem "minitest-rg"
end
Then require minitest/rg in your test/test_helper.rb:
require "minitest/rg"
Now you have colorful test output when running rake test.
Sure, in this rakefile change it to:
namespace :test do
task :isolated do
Dir.glob("test/**/*_test.rb").all? do |file|
sh(Gem.ruby, '-w', '-Ilib:test', file, '-p')
end or raise "Failures"
end
end
Then from the console run rake test:isolated while in activesupport folder and watch the rainbow go! This is using minitests built in pride library for color.

Rails 4 Use Factory Girl factories from Engine

I've created a rails engine (full, not mountable) to provide models to a number of different rails apps. I use Factory Girl Rails to test this engine and the tests all run fine for the engine itself.
I now want to be able to use these factories in other apps that include this engine.
The dependencies for the Gemspec look like this:
s.add_dependency "rails", "~> 4.0.3"
s.add_dependency "mysql2", "~> 0.3.15"
s.add_development_dependency "rspec-rails", "~> 3.0.0.beta"
s.add_development_dependency "factory_girl_rails", "~> 4.4.1"
s.add_development_dependency "shoulda-matchers", "~> 2.5.0"
And i have defined my factories in /spec/factories.rb:
factory :user do
...
end
To add the factories.rb to the definition paths in factory girl, I added the following to my /lib/engine_name/engine.rb file:
class Engine < ::Rails::Engine
initializer "model_core.factories", :after => "factory_girl.set_factory_paths" do
FactoryGirl.definition_file_paths << File.expand_path('../../../spec/factories.rb', __FILE__) if defined?(FactoryGirl)
end
end
In my rails apps I include the engine by adding the following to the Gemfile:
gem 'engine_name', git: "<GIT_LOCATION>"
I also add factory_girl_rails to the app (is there a way I can expose this from the engine? rather than having to specify it in the apps Gemfile too?).
And require factory girl rails in spec_helper.rb:
require 'factory_girl_rails'
Now when I write, say, a controller test like the following:
it "saves the user to the database" do
expect{post :create, user: attributes_for(:user)}.to change{User.count}.by(1)
end
I get the error: "Factory not registered: user"
I've double checked the factory girl definition file paths by opening the ruby console and running FactoryGirl.definition_file_paths and i can see the factories.rb from the engine in the output: "/home/ ... /gems/engine-name-abc123/spec/factories.rb"
Is there anything else i need to do to make these factories available?
(I have found a few similar questions on stackoverflow and beyond that all seem to point to adding those lines in engine.rb, or specifying namespaces in the factories.rb but I am not using namespaces with this engine.)
I found the easiest route to take with this was to add an install generator that simply copies the factories over. I also have the generator run the install migrations rake task as I will need these in any apps that use the engine.
So, in lib/generators/my_engine/install/install_generator.rb:
module MyEngine
module Generators
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
def copy_migrations
rake("my_engine:install:migrations")
end
def copy_factories
copy_file "../path/to/spec/factories.rb", "spec/factories.rb"
end
end
end
end
Now in projects that use this engine, I simply run rails generate my_engine:install and the factories (and migrations) are ready for me to use.

FactoryGirl creating objects in development environment

When I boot up my rails console in development I see FactoryGirl creating objects. Clearly I'm doing it wrong, but what's the right way to do this? This code makes my tests work...
# tests/factories/board.rb
FactoryGirl.define do
factory :word do
sequence(:text) { |n| "FAKETEXT#{n}" }
end
factory :board do
trait :has_words do
words [
FactoryGirl.create(:word, id: "514b81cae14cfa78f335e250"),
FactoryGirl.create(:word, id: "514b81cae14cfa7917e443f0"),
FactoryGirl.create(:word, id: "514b81cae14cfa79182407a2"),
FactoryGirl.create(:word, id: "514b81cae14cfa78f581c534")
]
end
end
end
Note there's no mention of factory anything in any file in my config directory, so whatever loading is happening automatically by the gem. The relevant part of my Gemfile reads:
# Stuff not to use in production
group :development, :test do
# Command-line debugger for development
gem "debugger"
# for unit testing - replace fixtures
gem "factory_girl_rails"
end
So I could just take factory girl out of the development environment. But I think the fact that these records are being created before the factory is being used is a sign that I've written my factory incorrectly. But if you tell me the factory is written correctly, I'll just do that.
Had the same problem. There are 2 ways to fix this,
1. Use FactoryGirl syntax to reference Factory within a Factory.
Replace FacotryGirl.create(:my_factory) with factory: :my_factory
More info on this, https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations
2. factory_girl :require => false in Gemfile
This causes Factories to generate objects on boot,
group :development, :test do
gem 'factory_girl_rails'
end
Why? During Rails boot, Bundler requires all the gems in the development group, and it seems that FactoryGirl requires all their factory files. Requiring the factories evaluates the Ruby code, and thus, FactoryGirl.create(:my_factory) gets called.
This can be fixed by,
# Gemfile
group :development, :test do
gem 'factory_girl_rails', :require => false
end
Just make sure to manually require factory_girl in your test environment, EG
# spec_helper
require 'factory_girl'
You just need to move factory girl out of the development environment.
I had the same issue, so I just did
group :test do
gem 'faker'
gem 'factory_girl_rails'
end
And works like a charm.
I'm not using those gems at all in development so its correct to just define them in test.
for each factories or model, you have to put in different file
spec/factories/word_factory.rb
spec/factories/board_factory.rb
So the content of each factory, you can do something similar to this:
FactoryGirl.define do
factory :board do
word
special_id
end
end
when in your test folder such as models/board_spec.rb
you can create your object
let(:word) { FactoryGirl.create(:word)
let(:board) { FactoryGirl.create(:board, word: word) }
nt sure is this what you need,correct me if I'm wrong
Assuming you want the words created when the factory is invoked and not at Rails startup, then you need to place the array of words inside a block, to wit:
trait :has_words do
words do [
FactoryGirl.create(:word, id: "514b81cae14cfa78f335e250"),
FactoryGirl.create(:word, id: "514b81cae14cfa7917e443f0"),
FactoryGirl.create(:word, id: "514b81cae14cfa79182407a2"),
FactoryGirl.create(:word, id: "514b81cae14cfa78f581c534")
]
end
end

How to resolve data append in factorygirl while testing?

I am new to rails. i try to write test for a model for that i use factory-girl gem. In that data was taken from XML file.
My problem is when ever am running my rspec file, data was appended every time, in XML file i have only 32 data, but every time am executing rsepc data was increasing...
i even tried database_cleaner but same result.
I want to delete the data in factory-girl.
is there anyway to avoid duplication in factory-girl?
is there anyway to use where condition like query for factory-girl?
Thank you.
Try this:
The following things use to reset factory girl data.
Add following line in your Gemfile and try bundle install.
gem "database_cleaner", ">= 0.8.0", :group => :test
In spec_helper.rb:
RSpec.configure do |config|
# Other things
# Clean up the database
require 'database_cleaner'
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
end
config.before(:each) do
DatabaseCleaner.clean
end
end

How to test JavaScripts without to delete the `test` database data?

I am using Ruby on Rails 3.2.2, cucumber-rails-1.3.0, rspec-rails-2.8.1 and capybara-1.1.2. I would like to use Selenium in order to test JavaScripts, but without to delete the test database data each time I run the cucumber command line in my Terminal window. That is, if I state a feature like the following:
Feature: ...
#javascript
Scenario: ...
JavaScript is tested as well as expected. However, after the test has run, the test database data is deleted and I must seed again that database in order to properly run new tests.
I read the Official Documentation and the text present in the ROOT_APP/features/support/env.rb file (it seems that I installed all required Ruby gems - see below for more information about the Gemfile that I am using) but I didn't understand how to avoid to delete the database data and how to configure Cucumber and Capybara gems so to properly work with Selenium.
What should I make?
Note I: I would like to make the above because I would like to have the same test database data when I "test"/"run" Scenarios.
Note II: In order to seed data in the test database (my application needs that data to work), I add the following code in the RAILS_ROOT_PATH/lib/tasks/cucumber.rake file and I run the rake db:test:prepare command line from the Terminal window.
namespace :db do
namespace :test do
task :prepare => :environment do
Rake::Task["db:seed"].invoke
end
end
end
In the ROOT_APP/features/support/env.rb file I tried to uncomment one and both of the following blocks of code (BTW: I never changed the original file auto-generated by the cucumber-rails gem, so it is the default one), but after running tests it still deletes the test database data.
# Before('#no-txn,#selenium,#culerity,#celerity,#javascript') do
# # { :except => [:widgets] } may not do what you expect here
# # as tCucumber::Rails::Database.javascript_strategy overrides
# # this setting.
# DatabaseCleaner.strategy = :truncation
# end
#
# Before('~#no-txn', '~#selenium', '~#culerity', '~#celerity', '~#javascript') do
# DatabaseCleaner.strategy = :transaction
# end
Gemfile excerpt:
group :development, :test do
gem "rspec-rails"
end
group :test do
gem 'cucumber-rails'
gem 'database_cleaner'
gem 'capybara'
end
I ran into this same problem, and managed to fix it by changing the following line in ROOT_APP/features/support/env.rb
from
Cucumber::Rails::Database.javascript_strategy = :truncation
to
Cucumber::Rails::Database.javascript_strategy = :transaction
Hope this helps...

Resources