Permalink
Browse files

version 0.2.0. fixed to use latest factory_girl syntax, added option …

…to include associations and validate associations
  • Loading branch information...
1 parent b22370f commit 6a97fcf36bc0e3f6bb4fececd0aac78647363e54 @garysweaver committed Nov 2, 2012
Showing with 78 additions and 49 deletions.
  1. +47 −10 README.md
  2. +2 −0 lib/stepford/cli.rb
  3. +28 −38 lib/stepford/factory_girl.rb
  4. +1 −1 lib/stepford/version.rb
View
@@ -7,14 +7,10 @@ Stepford is a CLI to create starter [Factory Girl][factory_girl] factories for a
FactoryGirl.define do
- factory :item do
- ignore do
- subpart_count 2
- end
- association :created_by, factory: :user
- after(:create) do |item, evaluator|
- FactoryGirl.create_list :subparts, evaluator.subpart_count, item: item
- end
+ factory :post do
+ author
+ association :edited_by, factory: :user
+ FactoryGirl.create_list :comments, 2
created_at { 2.weeks.ago }
name 'Test Name'
price 1.23
@@ -41,7 +37,7 @@ Then run:
#### Factory Girl
-The default will assume a `test/factories` directory exists and that it should create a factory file for each model:
+The default will assume a `test/factories` directory exists and that it should create a factory file for each model with non-primary key, non-foreign key attributes only, and no associations:
bundle exec stepford factories
@@ -53,9 +49,15 @@ It will figure out that you want a single file, if the path ends in `.rb`:
bundle exec stepford factories --path spec/support/factories.rb
+### Associations
+
+To include associations:
+
+ bundle exec stepford factories --associations
+
### Stepford Checks Model Associations
-Stepford first loads Rails and attempts to check your models for broken associations.
+If `--associations` or `--validate_associations` is specified, Stepford first loads Rails and attempts to check your models for broken associations.
If associations are deemed broken, it will output proposed changes.
@@ -67,6 +69,41 @@ Uses the Ruby 1.9 hash syntax in generated factories. If you don't have 1.9, it
If you are using STI, you'll need to manually fix the value that goes into the `type` attribute, or remove it.
+If you specify `--associations`, you might run into issue with circular associations, so you could easily end up with:
+
+ SystemStackError:
+ stack level too deep
+
+Some suggestions from ThoughtBot's Josh Clayton provided include using methods to generate more complex object structures:
+
+ def post_containing_comment_by_author
+ author = FactoryGirl.create(:user)
+ post = FactoryGirl.create(:post)
+ FactoryGirl.create_list(:comment, 3)
+ FactoryGirl.create(:comment, author: author, post: post)
+ post.reload
+ end
+
+or referring to created objects through associations, though he said multiple nestings get tricky:
+
+ factory :post do
+ author
+ title 'Ruby is fun'
+ end
+
+ factory :comment do
+ author
+ post
+ body 'I love Ruby too!'
+
+ trait :authored_by_post_author do
+ author { post.author }
+ end
+ end
+
+ comment = FactoryGirl.create(:comment, :authored_by_post_author)
+ comment.author == comment.post.author # true
+
### License
Copyright (c) 2012 Gary S. Weaver, released under the [MIT license][lic].
View
@@ -5,6 +5,8 @@ class CLI < Thor
desc "factories", "create FactoryGirl factories"
method_option :single, :desc => "Put all factories into a single file"
method_option :path, :desc => "Pathname of file to contain factories or path of directory to contain factory/factories"
+ method_option :associations, :desc => "Include associations in factories"
+ method_option :validate_associations, :desc => "Validate associations in factories even if not including associations"
def factories()
# load Rails environment
require './config/environment'
@@ -14,58 +14,48 @@ def self.generate_factories(options={})
factory = (factories[model_name.to_sym] ||= [])
primary_keys = Array.wrap(model_class.primary_key).collect{|pk|pk.to_sym}
foreign_keys = []
- ignored = []
- after_create = []
association_lines = model_class.reflections.collect {|association_name, reflection|
(expected[reflection.class_name.underscore.to_sym] ||= []) << model_name
foreign_keys << reflection.foreign_key.to_sym
assc_sym = reflection.name.to_sym
clas_sym = reflection.class_name.underscore.to_sym
- if reflection.macro == :has_many
- ignored << clas_sym
- after_create << "FactoryGirl.create_list #{assc_sym.inspect}, evaluator.#{clas_sym}_count, #{model_name}: #{model_name}"
- nil
+ # we have to do the part above to not set arbitrary values in foreign key attributes
+ if options[:associations]
+ if reflection.macro == :has_many
+ "FactoryGirl.create_list #{assc_sym.inspect}, 2"
+ elsif assc_sym != clas_sym
+ "association #{assc_sym.inspect}#{assc_sym != clas_sym ? ", factory: #{clas_sym.inspect}" : ''}"
+ else
+ "#{assc_sym}"
+ end
else
- "association #{assc_sym.inspect}#{assc_sym != clas_sym ? ", factory: #{clas_sym.inspect}" : ''}"
- end
- }.compact.sort
- if ignored.size > 0
- factory << 'ignore do'
- ignored.each do |name|
- factory << " #{name}_count 2"
- end
- factory << 'end'
- end
- association_lines.each {|l|factory << l}
- if after_create.size > 0
- factory << "after(:create) do |#{model_name}, evaluator|"
- after_create.each do |line|
- factory << " #{line}"
+ nil
end
- factory << 'end'
- end
+ }.compact.sort.each {|l|factory << l}
model_class.columns.collect {|c| "#{c.name.to_sym} #{Stepford::Common.value_for(c.name, c.type)}" unless foreign_keys.include?(c.name.to_sym) || primary_keys.include?(c.name.to_sym)}.compact.sort.each {|l|factory << l}
end
- failed = false
- model_to_fixes_required = {}
- expected.keys.sort.each do |factory_name|
- unless factories[factory_name.to_sym]
- puts "#{File.join('app','models',"#{factory_name}.rb")} missing. Model(s) with associations to it: #{expected[factory_name].sort.join(', ')}"
- expected[factory_name].each do |model_name|
- (model_to_fixes_required[model_name.to_sym] ||= []) << factory_name.to_sym
+ if options[:associations] || options[:validate_associations]
+ failed = false
+ model_to_fixes_required = {}
+ expected.keys.sort.each do |factory_name|
+ unless factories[factory_name.to_sym]
+ puts "#{File.join('app','models',"#{factory_name}.rb")} missing. Model(s) with associations to it: #{expected[factory_name].sort.join(', ')}"
+ expected[factory_name].each do |model_name|
+ (model_to_fixes_required[model_name.to_sym] ||= []) << factory_name.to_sym
+ end
+ failed = true
end
- failed = true
end
- end
- model_to_fixes_required.keys.each do |model_to_fix|
- puts ""
- puts "In #{model_to_fix}:"
- model_to_fixes_required[model_to_fix].each do |fix|
- puts "- comment/remove/fix broken association to #{fix}"
+ model_to_fixes_required.keys.each do |model_to_fix|
+ puts ""
+ puts "In #{model_to_fix}:"
+ model_to_fixes_required[model_to_fix].each do |fix|
+ puts "- comment/remove/fix broken association to #{fix}"
+ end
end
+ return false if failed
end
- return false if failed
path = File.join('test','factories.rb')
if options[:path]
View
@@ -1,3 +1,3 @@
module Stepford
- VERSION = '0.1.0'
+ VERSION = '0.2.0'
end

0 comments on commit 6a97fcf

Please sign in to comment.