pax_global_header00006660000000000000000000000064125060361050014510gustar00rootroot0000000000000052 comment=a13ce36900e6283072c06eb45b713353ccc13bfe seed-fu-v.2.3.5/000077500000000000000000000000001250603610500133135ustar00rootroot00000000000000seed-fu-v.2.3.5/.gitignore000066400000000000000000000000731250603610500153030ustar00rootroot00000000000000*.log *.gem .DS_Store /pkg Gemfile.lock .bundle .yardoc docseed-fu-v.2.3.5/.yardopts000066400000000000000000000000311250603610500151530ustar00rootroot00000000000000-m markdown --no-private seed-fu-v.2.3.5/CHANGELOG.md000066400000000000000000000051621250603610500151300ustar00rootroot00000000000000Version 2.3.5 ------------- Features: * Rails 4.2 support Version 2.3.3 ------------- Features: * Capistrano v3 support (by @shishi) Version 2.3.2 ------------- Features: * Documentation improvements (by @george, @kenips, @joshuapinter) * Fix documentation of seed_once method (by weedySeaDragon) * Allow to seed data with an id < 1 (by @SamSaffron, @aserafin) * Seeds work on postgresql when there is no primary key or if primary key has no sequence assigned (by @aserafin) Version 2.3.1 ------------- Features: * Rails 4.1 support added. * Capistrano task included. (by @linjunpop) Version 2.3.0 ------------- Features: * Rails 4.0.X support added. (by @tkhr, @DanielWright) Version 2.2.0 ------------- * Rails 3.2 support Version 2.1.0 ------------- Features: * Deprecations removed * Rails 3.1 support added, Rails 3.0 support removed (please use 2.0.X line with 3.0) Version 2.0.1 ------------- Bug fixes: * Update the primary key sequence in PostgreSQL tables after seeding data. This ensures that id conflicts do not occur when records are subsequently added to the table. * Raise ActiveRecord::RecordNotSaved if any of the saves fail (but they won't fail due to validation since saves are done without validation, so this guards against callbacks failing etc.) Version 2.0.0 ------------- Features: * Depends only on Active Record, not the whole of Rails * The `Model.seed_many` syntax is now supported by `Model.seed`, and `Model.seed_many` is deprecated * `Model.seed` supports adding multiple records without an explicit array argument. I.e. the following are equivalent: Model.seed([ { :name => "Jon" }, { :name => "Emily" } ]) Model.seed( { :name => "Jon" }, { :name => "Emily } ) * A side-effect of the above is another option for single seeds: Model.seed(:name => "Jon") * The `SEED` option to `rake db:seed_fu` is deprecated, and replaced by `FILTER` which works the same way. * Added `SeedFu.quiet` boolean option, set to `true` if you don't want any output from Seed Fu. * Added `SeedFu.fixture_paths`. Set to an array of paths to look for seed files in. Defaults to `["db/fixtures"]` in general, or `["#{Rails.root}/db/fixtures", "#{Rails.root}/db/fixtures/#{Rails.env}"]` when Seed Fu is installed as a Rails plugin. * Added `SeedFu.seed` method which is basically a method equivalent of running `rake db:seed_fu` (the rake task now just basically called `SeedFu.seed`) * Simplified and changed the `SeedFu::Writer` API, see docs for details Bug fixes: * Fix Rails 3 deprecation warnings and make seed-fu fully compatible with being installed as a gem seed-fu-v.2.3.5/Gemfile000066400000000000000000000001041250603610500146010ustar00rootroot00000000000000source 'http://rubygems.org' gem 'rails', ">= 3.1", "< 4.3" gemspec seed-fu-v.2.3.5/LICENSE000066400000000000000000000020471250603610500143230ustar00rootroot00000000000000Copyright (c) 2008-2010 Michael Bleigh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. seed-fu-v.2.3.5/README.md000066400000000000000000000134201250603610500145720ustar00rootroot00000000000000Seed Fu ======= Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around. Warning: API Changes -------------------- Version 2.0.0 of Seed Fu introduced API changes. `Seed::Writer` was been completely overhauled and will require you to update your scripts. Some other deprecations were introduced, and support is fully removed in version 2.1.0. Please see the [CHANGELOG](CHANGELOG.md) for details. The API documentation is available in full at [http://rubydoc.info/github/mbleigh/seed-fu/master/frames](http://rubydoc.info/github/mbleigh/seed-fu/master/frames). Basic Example ------------- ### In `db/fixtures/users.rb` User.seed do |s| s.id = 1 s.login = "jon" s.email = "jon@example.com" s.name = "Jon" end User.seed do |s| s.id = 2 s.login = "emily" s.email = "emily@example.com" s.name = "Emily" end ### To load the data: $ rake db:seed_fu == Seed from /path/to/app/db/fixtures/users.rb - User {:id=>1, :login=>"jon", :email=>"jon@example.com", :name=>"Jon"} - User {:id=>2, :login=>"emily", :email=>"emily@example.com", :name=>"Emily"} Installation ------------ ### Rails 3.1, 3.2, 4.0, 4.1 Just add `gem 'seed-fu', '~> 2.3'` to your `Gemfile` Seed Fu depends on Active Record, but doesn't have to be used with a full Rails app. Simply load and require the `seed-fu` gem and you're set. ### Rails 3.0 The current version is not backwards compatible with Rails 3.0. Please use `gem 'seed-fu', '~> 2.0.0'`. ### Rails 2.3 The current version is not backwards compatible with Rails 2.3. Please use `gem 'seed-fu', '~> 1.2.0'`. Constraints ----------- Constraints are used to identify seeds, so that they can be updated if necessary. For example: Point.seed(:x, :y) do |s| s.x = 4 s.y = 7 s.name = "Home" end The first time this seed is loaded, a `Point` record will be created. Now suppose the name is changed: Point.seed(:x, :y) do |s| s.x = 4 s.y = 7 s.name = "Work" end When this is run, Seed Fu will look for a `Point` based on the `:x` and `:y` constraints provided. It will see that a matching `Point` already exists and so update its attributes rather than create a new record. If you do not want seeds to be updated after they have been created, use `seed_once`: Point.seed_once(:x, :y) do |s| s.x = 4 s.y = 7 s.name = "Home" end The default constraint just checks the `id` of the record. Where to put seed files ----------------------- By default, seed files are looked for in the following locations: * `#{Rails.root}/db/fixtures` and `#{Rails.root}/db/fixtures/#{Rails.env}` in a Rails app * `./db/fixtures` when loaded without Rails You can change these defaults by modifying the `SeedFu.fixture_paths` array. Seed files can be named whatever you like, and are loaded in alphabetical order. Terser syntax ------------- When loading lots of records, the above block-based syntax can be quite verbose. You can use the following instead: User.seed(:id, { :id => 1, :login => "jon", :email => "jon@example.com", :name => "Jon" }, { :id => 2, :login => "emily", :email => "emily@example.com", :name => "Emily" } ) Rake task --------- Seed files can be run automatically using `rake db:seed_fu`. There are two options which you can pass: * `rake db:seed_fu FIXTURE_PATH=path/to/fixtures` -- Where to find the fixtures * `rake db:seed_fu FILTER=users,articles` -- Only run seed files with a filename matching the `FILTER` You can also do a similar thing in your code by calling `SeedFu.seed(fixture_paths, filter)`. Disable output -------------- To disable output from Seed Fu, set `SeedFu.quiet = true`. Handling large seed files ------------------------- Seed files can be huge. To handle large files (over a million rows), try these tricks: * Gzip your fixtures. Seed Fu will read .rb.gz files happily. `gzip -9` gives the best compression, and with Seed Fu's repetitive syntax, a 160M file can shrink to 16M. * Add lines reading `# BREAK EVAL` in your big fixtures, and Seed Fu will avoid loading the whole file into memory. If you use `SeedFu::Writer`, these breaks are built into your generated fixtures. * Load a single fixture at a time with the `FILTER` environment variable * If you don't need Seed Fu's ability to update seed with new data, then you may find that [activerecord-import](https://github.com/zdennis/activerecord-import) is faster Generating seed files --------------------- If you need to programmatically generate seed files, for example to convert a CSV file into a seed file, then you can use [`SeedFu::Writer`](lib/seed-fu/writer.rb). Capistrano deployment --------------------- SeedFu has included Capistrano [deploy script](lib/seed-fu/capistrano.rb), you just need require that in `config/deploy.rb`: ```ruby require 'seed-fu/capistrano' # Trigger the task after update_code after 'deploy:update_code', 'db:seed_fu' ``` If you use Capistrano3, you should require another file. ```ruby require 'seed-fu/capistrano3' # Trigger the task before publishing before 'deploy:publishing', 'db:seed_fu' ``` Bugs / Feature requests ----------------------- Please report them on [Github Issues](https://github.com/mbleigh/seed-fu/issues). Contributors ------------ * [Michael Bleigh](http://www.mbleigh.com/) is the original author * [Jon Leighton](http://jonathanleighton.com/) is the current maintainer * Thanks to [Matthew Beale](https://github.com/mixonic) for his great work in adding the writer, making it faster and better. Copyright © 2008-2010 Michael Bleigh, released under the MIT license seed-fu-v.2.3.5/Rakefile000066400000000000000000000002511250603610500147560ustar00rootroot00000000000000require "bundler/gem_tasks" require "rake/testtask" require 'rspec/core/rake_task' RSpec::Core::RakeTask.new :spec do |spec| spec.pattern = 'spec/**/*_spec.rb' end seed-fu-v.2.3.5/lib/000077500000000000000000000000001250603610500140615ustar00rootroot00000000000000seed-fu-v.2.3.5/lib/seed-fu.rb000066400000000000000000000023651250603610500157440ustar00rootroot00000000000000require 'active_record' require 'active_support/core_ext/module/attribute_accessors' require 'seed-fu/railtie' if defined?(Rails) && Rails.version >= "3" module SeedFu autoload :VERSION, 'seed-fu/version' autoload :Seeder, 'seed-fu/seeder' autoload :ActiveRecordExtension, 'seed-fu/active_record_extension' autoload :BlockHash, 'seed-fu/block_hash' autoload :Runner, 'seed-fu/runner' autoload :Writer, 'seed-fu/writer' mattr_accessor :quiet # Set `SeedFu.quiet = true` to silence all output @@quiet = false mattr_accessor :fixture_paths # Set this to be an array of paths to directories containing your seed files. If used as a Rails # plugin, SeedFu will set to to contain `Rails.root/db/fixtures` and # `Rails.root/db/fixtures/Rails.env` @@fixture_paths = ['db/fixtures'] # Load seed data from files # @param [Array] fixture_paths The paths to look for seed files in # @param [Regexp] filter If given, only filenames matching this expression will be loaded def self.seed(fixture_paths = SeedFu.fixture_paths, filter = nil) Runner.new(fixture_paths, filter).run end end # @public class ActiveRecord::Base extend SeedFu::ActiveRecordExtension end seed-fu-v.2.3.5/lib/seed-fu/000077500000000000000000000000001250603610500154115ustar00rootroot00000000000000seed-fu-v.2.3.5/lib/seed-fu/active_record_extension.rb000066400000000000000000000042651250603610500226520ustar00rootroot00000000000000module SeedFu module ActiveRecordExtension # Load some seed data. There are two ways to do this. # # Verbose syntax # -------------- # # This will seed a single record. The `:id` parameter ensures that if a record already exists # in the database with the same id, then it will be updated with the name and age, rather # than created from scratch. # # Person.seed(:id) do |s| # s.id = 1 # s.name = "Jon" # s.age = 21 # end # # Note that `:id` is the default attribute used to identify a seed, so it need not be # specified. # # Terse syntax # ------------ # # This is a more succinct way to load multiple records. Note that both `:x` and `:y` are being # used to identify a seed here. # # Point.seed(:x, :y, # { :x => 3, :y => 10, :name => "Home" }, # { :x => 5, :y => 9, :name => "Office" } # ) def seed(*args, &block) SeedFu::Seeder.new(self, *parse_seed_fu_args(args, block)).seed end # Has the same syntax as {#seed}, but if a record already exists with the same values for # constraining attributes, it will not be updated. # # @example # Person.seed(:id, :id => 1, :name => "Jon") # => Record created # Person.seed(:id, :id => 1, :name => "Bob") # => Name changed # Person.seed_once(:id, :id => 1, :name => "Harry") # => Name *not* changed def seed_once(*args, &block) constraints, data = parse_seed_fu_args(args, block) SeedFu::Seeder.new(self, constraints, data, :insert_only => true).seed end private def parse_seed_fu_args(args, block) if block.nil? if args.last.is_a?(Array) # Last arg is an array of data, so assume the rest of the args are constraints data = args.pop [args, data] else # Partition the args, assuming the first hash is the start of the data args.partition { |arg| !arg.is_a?(Hash) } end else # We have a block, so assume the args are all constraints [args, [SeedFu::BlockHash.new(block).to_hash]] end end end end seed-fu-v.2.3.5/lib/seed-fu/block_hash.rb000066400000000000000000000005531250603610500200360ustar00rootroot00000000000000module SeedFu # @private class BlockHash def initialize(proc) @hash = {} proc.call(self) end def to_hash @hash end def method_missing(method_name, *args, &block) if method_name.to_s =~ /^(.*)=$/ && args.length == 1 && block.nil? @hash[$1] = args.first else super end end end end seed-fu-v.2.3.5/lib/seed-fu/capistrano.rb000066400000000000000000000004201250603610500200750ustar00rootroot00000000000000Capistrano::Configuration.instance.load do namespace :db do desc "Load seed data into database" task :seed_fu, :roles => :db, :only => { :primary => true } do run "cd #{release_path} && bundle exec rake RAILS_ENV=#{rails_env} db:seed_fu" end end end seed-fu-v.2.3.5/lib/seed-fu/capistrano3.rb000066400000000000000000000001101250603610500201540ustar00rootroot00000000000000load File.expand_path('../../tasks/seed_fu_capistrano3.rake', __FILE__) seed-fu-v.2.3.5/lib/seed-fu/railtie.rb000066400000000000000000000004701250603610500173700ustar00rootroot00000000000000module SeedFu class Railtie < Rails::Railtie rake_tasks do load "tasks/seed_fu.rake" end initializer 'seed_fu.set_fixture_paths' do SeedFu.fixture_paths = [ Rails.root.join('db/fixtures').to_s, Rails.root.join('db/fixtures/' + Rails.env).to_s ] end end end seed-fu-v.2.3.5/lib/seed-fu/runner.rb000066400000000000000000000041411250603610500172470ustar00rootroot00000000000000require 'zlib' require 'active_support/core_ext/array/wrap' module SeedFu # Runs seed files. # # It is not recommended to use this class directly. Instead, use {SeedFu.seed SeedFu.seed}, which creates # an instead of {Runner} and calls {#run #run}. # # @see SeedFu.seed SeedFu.seed class Runner # @param [Array] fixture_paths The paths where fixtures are located. Will use # `SeedFu.fixture_paths` if {nil}. If the argument is not an array, it will be wrapped by one. # @param [Regexp] filter If given, only seed files with a file name matching this pattern will # be used def initialize(fixture_paths = nil, filter = nil) @fixture_paths = Array.wrap(fixture_paths || SeedFu.fixture_paths) @filter = filter end # Run the seed files. def run puts "\n== Filtering seed files against regexp: #{@filter.inspect}" if @filter && !SeedFu.quiet filenames.each do |filename| run_file(filename) end end private def run_file(filename) puts "\n== Seed from #{filename}" unless SeedFu.quiet ActiveRecord::Base.transaction do open(filename) do |file| chunked_ruby = '' file.each_line do |line| if line == "# BREAK EVAL\n" eval(chunked_ruby) chunked_ruby = '' else chunked_ruby << line end end eval(chunked_ruby) unless chunked_ruby == '' end end end def open(filename) if filename[-3..-1] == '.gz' Zlib::GzipReader.open(filename) do |file| yield file end else File.open(filename) do |file| yield file end end end def filenames filenames = [] @fixture_paths.each do |path| filenames += (Dir[File.join(path, '*.rb')] + Dir[File.join(path, '*.rb.gz')]).sort end filenames.uniq! filenames = filenames.find_all { |filename| filename =~ @filter } if @filter filenames end end end seed-fu-v.2.3.5/lib/seed-fu/seeder.rb000066400000000000000000000073731250603610500172170ustar00rootroot00000000000000require 'active_support/core_ext/hash/keys' module SeedFu # Creates or updates seed records with data. # # It is not recommended to use this class directly. Instead, use `Model.seed`, and `Model.seed_once`, # where `Model` is your Active Record model. # # @see ActiveRecordExtension class Seeder # @param [ActiveRecord::Base] model_class The model to be seeded # @param [Array] constraints A list of attributes which identify a particular seed. If # a record with these attributes already exists then it will be updated rather than created. # @param [Array] data Each item in this array is a hash containing attributes for a # particular record. # @param [Hash] options # @option options [Boolean] :quiet (SeedFu.quiet) If true, output will be silenced # @option options [Boolean] :insert_only (false) If true then existing records which match the # constraints will not be updated, even if the seed data has changed def initialize(model_class, constraints, data, options = {}) @model_class = model_class @constraints = constraints.to_a.empty? ? [:id] : constraints @data = data.to_a || [] @options = options.symbolize_keys @options[:quiet] ||= SeedFu.quiet validate_constraints! validate_data! end # Insert/update the records as appropriate. Validation is skipped while saving. # @return [Array] The records which have been seeded def seed records = @model_class.transaction do @data.map { |record_data| seed_record(record_data.symbolize_keys) } end update_id_sequence records end private def validate_constraints! unknown_columns = @constraints.map(&:to_s) - @model_class.column_names unless unknown_columns.empty? raise(ArgumentError, "Your seed constraints contained unknown columns: #{column_list(unknown_columns)}. " + "Valid columns are: #{column_list(@model_class.column_names)}.") end end def validate_data! raise ArgumentError, "Seed data missing" if @data.empty? end def column_list(columns) '`' + columns.join("`, `") + '`' end def seed_record(data) record = find_or_initialize_record(data) return if @options[:insert_only] && !record.new_record? puts " - #{@model_class} #{data.inspect}" unless @options[:quiet] # Rails 3 or Rails 4 + rails/protected_attributes if record.class.respond_to?(:protected_attributes) && record.class.respond_to?(:accessible_attributes) record.assign_attributes(data, :without_protection => true) # Rails 4 without rails/protected_attributes else record.assign_attributes(data) end record.save(:validate => false) || raise(ActiveRecord::RecordNotSaved, 'Record not saved!') record end def find_or_initialize_record(data) @model_class.where(constraint_conditions(data)).first || @model_class.new end def constraint_conditions(data) Hash[@constraints.map { |c| [c, data[c.to_sym]] }] end def update_id_sequence if @model_class.connection.adapter_name == "PostgreSQL" return if @model_class.primary_key.nil? || @model_class.sequence_name.nil? quoted_id = @model_class.connection.quote_column_name(@model_class.primary_key) sequence = @model_class.sequence_name @model_class.connection.execute <<-EOS SELECT setval('#{sequence}', (SELECT GREATEST(MAX(#{quoted_id})+(SELECT increment_by FROM #{sequence}), (SELECT min_value FROM #{sequence})) FROM #{@model_class.quoted_table_name}), false) EOS end end end end seed-fu-v.2.3.5/lib/seed-fu/version.rb000066400000000000000000000001111250603610500174140ustar00rootroot00000000000000module SeedFu # The current version of Seed Fu VERSION = '2.3.5' end seed-fu-v.2.3.5/lib/seed-fu/writer.rb000066400000000000000000000102011250603610500172440ustar00rootroot00000000000000module SeedFu # {Writer} is used to programmatically generated seed files. For example, you might want to write # a script which converts data in a CSV file to a valid Seed Fu seed file, which can then be # imported. # # @example Basic usage # SeedFu::Writer.write('path/to/file.rb', :class_name => 'Person', :constraints => [:first_name, :last_name]) do |writer| # writer.add(:first_name => 'Jon', :last_name => 'Smith', :age => 21) # writer.add(:first_name => 'Emily', :last_name => 'McDonald', :age => 24) # end # # # Writes the following to the file: # # # # Person.seed(:first_name, :last_name, # # {:first_name=>"Jon", :last_name=>"Smith", :age=>21}, # # {:first_name=>"Emily", :last_name=>"McDonald", :age=>24} # # ) class Writer cattr_accessor :default_options @@default_options = { :chunk_size => 100, :constraints => [:id], :seed_type => :seed } # @param [Hash] options # @option options [String] :class_name *Required* The name of the Active Record model to # generate seeds for # @option options [Fixnum] :chunk_size (100) The number of seeds to write before generating a # `# BREAK EVAL` line. (Chunking reduces memory usage when loading seeds.) # @option options [:seed, :seed_once] :seed_type (:seed) The method to use when generating # seeds. See {ActiveRecordExtension} for details. # @option options [Array] :constraints ([:id]) The constraining attributes for the seeds def initialize(options = {}) @options = self.class.default_options.merge(options) raise ArgumentError, "missing option :class_name" unless @options[:class_name] end # Creates a new instance of {Writer} with the `options`, and then calls {#write} with the # `io_or_filename` and `block` def self.write(io_or_filename, options = {}, &block) new(options).write(io_or_filename, &block) end # Writes the necessary headers and footers, and yields to a block within which the actual # seed data should be writting using the `#<<` method. # # @param [IO] io_or_filename The IO to which writes will be made. (If an `IO` is given, it is # your responsibility to close it after writing.) # @param [String] io_or_filename The filename of a file to make writes to. (Will be opened and # closed automatically.) # @yield [self] make calls to `#<<` within the block def write(io_or_filename, &block) raise ArgumentError, "missing block" unless block_given? if io_or_filename.respond_to?(:write) write_to_io(io_or_filename, &block) else File.open(io_or_filename, 'w') do |file| write_to_io(file, &block) end end end # Add a seed. Must be called within a block passed to {#write}. # @param [Hash] seed The attributes for the seed def <<(seed) raise "You must add seeds inside a SeedFu::Writer#write block" unless @io buffer = '' if chunk_this_seed? buffer << seed_footer buffer << "# BREAK EVAL\n" buffer << seed_header end buffer << ",\n" buffer << ' ' + seed.inspect @io.write(buffer) @count += 1 end alias_method :add, :<< private def write_to_io(io) @io, @count = io, 0 @io.write(file_header) @io.write(seed_header) yield(self) @io.write(seed_footer) @io.write(file_footer) ensure @io, @count = nil, nil end def file_header <<-END # DO NOT MODIFY THIS FILE, it was auto-generated. # # Date: #{Time.now} # Seeding #{@options[:class_name]} # Written with the command: # # #{$0} #{$*.join} # END end def file_footer <<-END # End auto-generated file. END end def seed_header constraints = @options[:constraints] && @options[:constraints].map(&:inspect).join(', ') "#{@options[:class_name]}.#{@options[:seed_type]}(#{constraints}" end def seed_footer "\n)\n" end def chunk_this_seed? @count != 0 && (@count % @options[:chunk_size]) == 0 end end end seed-fu-v.2.3.5/lib/tasks/000077500000000000000000000000001250603610500152065ustar00rootroot00000000000000seed-fu-v.2.3.5/lib/tasks/seed_fu.rake000066400000000000000000000022411250603610500174630ustar00rootroot00000000000000require 'seed-fu' namespace :db do desc <<-EOS Loads seed data for the current environment. It will look for ruby seed files in /db/fixtures/ and /db/fixtures//. By default it will load any ruby files found. You can filter the files loaded by passing in the FILTER environment variable with a comma-delimited list of patterns to include. Any files not matching the pattern will not be loaded. You can also change the directory where seed files are looked for with the FIXTURE_PATH environment variable. Examples: # default, to load all seed files for the current environment rake db:seed_fu # to load seed files matching orders or customers rake db:seed_fu FILTER=orders,customers # to load files from RAILS_ROOT/features/fixtures rake db:seed_fu FIXTURE_PATH=features/fixtures EOS task :seed_fu => :environment do if ENV["FILTER"] filter = /#{ENV["FILTER"].gsub(/,/, "|")}/ end if ENV["FIXTURE_PATH"] fixture_paths = [ENV["FIXTURE_PATH"], ENV["FIXTURE_PATH"] + '/' + Rails.env] end SeedFu.seed(fixture_paths, filter) end end seed-fu-v.2.3.5/lib/tasks/seed_fu_capistrano3.rake000066400000000000000000000004071250603610500217730ustar00rootroot00000000000000namespace :db do desc 'Load seed data into database' task :seed_fu do on roles(:db) do within release_path do with rails_env: fetch(:rails_env) do execute :bundle, :exec, :rake, 'db:seed_fu' end end end end end seed-fu-v.2.3.5/seed-fu.gemspec000066400000000000000000000023161250603610500162120ustar00rootroot00000000000000# -*- encoding: utf-8 -*- lib = File.expand_path('../lib/', __FILE__) $:.unshift lib unless $:.include?(lib) require 'seed-fu/version' Gem::Specification.new do |s| s.name = "seed-fu" s.version = SeedFu::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Michael Bleigh", "Jon Leighton"] s.email = ["michael@intridea.com", "j@jonathanleighton.com"] s.homepage = "http://github.com/mbleigh/seed-fu" s.summary = "Easily manage seed data in your Active Record application" s.description = "Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around." s.add_dependency "activerecord", [">= 3.1", "< 4.3"] s.add_dependency "activesupport", [">= 3.1", "< 4.3"] s.add_development_dependency "rspec", "~> 2.0" s.add_development_dependency "pg", '~> 0' s.add_development_dependency "mysql2", '~> 0' s.add_development_dependency "sqlite3", '~> 0' s.files = Dir.glob("{lib}/**/*") + %w(LICENSE README.md CHANGELOG.md) s.require_path = 'lib' end seed-fu-v.2.3.5/spec/000077500000000000000000000000001250603610500142455ustar00rootroot00000000000000seed-fu-v.2.3.5/spec/.gitignore000066400000000000000000000000501250603610500162300ustar00rootroot00000000000000debug.log test.sqlite3 seeded_models.rb seed-fu-v.2.3.5/spec/README000066400000000000000000000007711250603610500151320ustar00rootroot00000000000000To run the specs: gem install bundler # If not already installed bundle install # Install the dependencies rspec spec/ # Run the specs By default an sqlite3 database is used. To test others: DB=mysql rspec spec/ DB=postgresql rspec spec/ In each of these cases, you'll need to create a database named "spec_fu_test". The connection paramaters for each of these are specified in spec/connections/, which you can edit if necessary (for example to change the username/password). seed-fu-v.2.3.5/spec/connections/000077500000000000000000000000001250603610500165675ustar00rootroot00000000000000seed-fu-v.2.3.5/spec/connections/mysql.rb000066400000000000000000000001711250603610500202600ustar00rootroot00000000000000ActiveRecord::Base.establish_connection( :adapter => "mysql2", :database => "seed_fu_test", :username => "root" ) seed-fu-v.2.3.5/spec/connections/postgresql.rb000066400000000000000000000002011250603610500213100ustar00rootroot00000000000000ActiveRecord::Base.establish_connection( :adapter => "postgresql", :database => "seed_fu_test", :username => "postgres" ) seed-fu-v.2.3.5/spec/connections/sqlite3.rb000066400000000000000000000001741250603610500205020ustar00rootroot00000000000000ActiveRecord::Base.establish_connection( :adapter => "sqlite3", :database => File.dirname(__FILE__) + "/test.sqlite3" ) seed-fu-v.2.3.5/spec/fixtures/000077500000000000000000000000001250603610500161165ustar00rootroot00000000000000seed-fu-v.2.3.5/spec/fixtures/seeded_models.rb000066400000000000000000000000711250603610500212350ustar00rootroot00000000000000SeededModel.seed do |s| s.id = 1 s.title = "Foo" end seed-fu-v.2.3.5/spec/fixtures/seeded_models_2.rb000066400000000000000000000000711250603610500214560ustar00rootroot00000000000000SeededModel.seed do |s| s.id = 2 s.title = "Bar" end seed-fu-v.2.3.5/spec/fixtures/seeded_models_3.rb.gz000066400000000000000000000001321250603610500220740ustar00rootroot00000000000000Lseeded_models_3.rb NMMIMOI+Rjk2Sl̒̒T O)J+5/ 9seed-fu-v.2.3.5/spec/runner_spec.rb000066400000000000000000000014151250603610500171160ustar00rootroot00000000000000require 'spec_helper' describe SeedFu::Runner do it "should seed data from Ruby and gzipped Ruby files in the given fixtures directory" do SeedFu.seed(File.dirname(__FILE__) + '/fixtures') SeededModel.find(1).title.should == "Foo" SeededModel.find(2).title.should == "Bar" SeededModel.find(3).title.should == "Baz" end it "should seed only the data which matches the filter, if one is given" do SeedFu.seed(File.dirname(__FILE__) + '/fixtures', /_2/) SeededModel.count.should == 1 SeededModel.find(2).title.should == "Bar" end it "should use the SpecFu.fixtures_path variable to determine where fixtures are" do SeedFu.fixture_paths = [File.dirname(__FILE__) + '/fixtures'] SeedFu.seed SeededModel.count.should == 3 end end seed-fu-v.2.3.5/spec/seeder_spec.rb000066400000000000000000000120301250603610500170470ustar00rootroot00000000000000require 'spec_helper' describe SeedFu::Seeder do it "should work with negative seeds" do SeededModel.seed(:id) do |s| s.id = 10 s.login = "bob2" s.first_name = "Bob2" s.last_name = "Bobson2" s.title = "Peaon2" end SeededModel.seed(:id) do |s| s.id = -2 s.login = "bob" s.first_name = "Bob" s.last_name = "Bobson" s.title = "Peon" end bob = SeededModel.find_by_id(-2) bob.first_name.should == "Bob" bob.last_name.should == "Bobson" if ENV['DB'] == 'postgresql' next_id = SeededModel.connection.execute("select nextval('seeded_models_id_seq')") next_id[0]['nextval'].to_i.should == 11 end end it "should create a model if one doesn't exist" do SeededModel.seed(:id) do |s| s.id = 5 s.login = "bob" s.first_name = "Bob" s.last_name = "Bobson" s.title = "Peon" end bob = SeededModel.find_by_id(5) bob.first_name.should == "Bob" bob.last_name.should == "Bobson" end it "should be able to handle multiple constraints" do SeededModel.seed(:title, :login) do |s| s.login = "bob" s.title = "Peon" s.first_name = "Bob" end SeededModel.count.should == 1 SeededModel.seed(:title, :login) do |s| s.login = "frank" s.title = "Peon" s.first_name = "Frank" end SeededModel.count.should == 2 SeededModel.find_by_login("bob").first_name.should == "Bob" SeededModel.seed(:title, :login) do |s| s.login = "bob" s.title = "Peon" s.first_name = "Steve" end SeededModel.find_by_login("bob").first_name.should == "Steve" end it "should be able to create models from an array of seed attributes" do SeededModel.seed(:title, :login, [ {:login => "bob", :title => "Peon", :first_name => "Steve"}, {:login => "frank", :title => "Peasant", :first_name => "Francis"}, {:login => "harry", :title => "Noble", :first_name => "Harry"} ]) SeededModel.find_by_login("bob").first_name.should == "Steve" SeededModel.find_by_login("frank").first_name.should == "Francis" SeededModel.find_by_login("harry").first_name.should == "Harry" end it "should be able to create models from a list of seed attribute hashes at the end of the args" do SeededModel.seed(:title, :login, {:login => "bob", :title => "Peon", :first_name => "Steve"}, {:login => "frank", :title => "Peasant", :first_name => "Francis"}, {:login => "harry", :title => "Noble", :first_name => "Harry"} ) SeededModel.find_by_login("bob").first_name.should == "Steve" SeededModel.find_by_login("frank").first_name.should == "Francis" SeededModel.find_by_login("harry").first_name.should == "Harry" end it "should update, not create, if constraints are met" do SeededModel.seed(:id) do |s| s.id = 1 s.login = "bob" s.first_name = "Bob" s.last_name = "Bobson" s.title = "Peon" end SeededModel.seed(:id) do |s| s.id = 1 s.login = "bob" s.first_name = "Robert" s.last_name = "Bobson" s.title = "Peon" end bob = SeededModel.find_by_id(1) bob.first_name.should == "Robert" bob.last_name.should == "Bobson" end it "should create but not update with seed_once" do SeededModel.seed_once(:id) do |s| s.id = 1 s.login = "bob" s.first_name = "Bob" s.last_name = "Bobson" s.title = "Peon" end SeededModel.seed_once(:id) do |s| s.id = 1 s.login = "bob" s.first_name = "Robert" s.last_name = "Bobson" s.title = "Peon" end bob = SeededModel.find_by_id(1) bob.first_name.should == "Bob" bob.last_name.should == "Bobson" end it "should default to an id constraint" do SeededModel.seed(:title => "Bla", :id => 1) SeededModel.seed(:title => "Foo", :id => 1) SeededModel.find(1).title.should == "Foo" end it "should require that all constraints are defined" do expect { SeededModel.seed(:doesnt_exist, :title => "Bla") }.to raise_error(ArgumentError) end it "should not perform validation" do expect { SeededModel.seed(:id => 1) }.not_to raise_error() end if ENV["DB"] == "postgresql" it "should update the primary key sequence after a records have been seeded" do id = SeededModel.connection.select_value("SELECT currval('seeded_models_id_seq')").to_i + 1 SeededModel.seed(:title => "Foo", :id => id) expect { SeededModel.create!(:title => "Bla") }.not_to raise_error end it "should not raise error when there is no primary key specified" do expect { SeededModelNoPrimaryKey.seed(:id => "Id") }.not_to raise_error end it "should not raise error when there is primary key without sequence" do expect { SeededModelNoSequence.seed(:id => "Id") }.not_to raise_error end end it "should raise an ActiveRecord::RecordNotSaved exception if any records fail to save" do expect { SeededModel.seed(:fail_to_save => true, :title => "Foo") }.to raise_error(ActiveRecord::RecordNotSaved) end end seed-fu-v.2.3.5/spec/spec_helper.rb000066400000000000000000000024141250603610500170640ustar00rootroot00000000000000require 'rubygems' require 'bundler/setup' require 'seed-fu' require 'logger' SeedFu.quiet = true ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/../debug.log") ENV["DB"] ||= 'sqlite3' puts "Using #{ENV["DB"]} to run the tests." require File.dirname(__FILE__) + "/connections/#{ENV["DB"]}.rb" ActiveRecord::Schema.define :version => 0 do create_table :seeded_models, :force => true do |t| t.column :login, :string t.column :first_name, :string t.column :last_name, :string t.column :title, :string end create_table :seeded_model_no_primary_keys, :id => false, :force => true do |t| t.column :id, :string end create_table :seeded_model_no_sequences, :id => false, :force => true do |t| t.column :id, :string end execute("ALTER TABLE seeded_model_no_sequences ADD PRIMARY KEY (id)") if ENV['DB'] == 'postgresql' end class SeededModel < ActiveRecord::Base validates_presence_of :title attr_protected :first_name if self.respond_to?(:protected_attributes) attr_accessor :fail_to_save before_save { false if fail_to_save } end class SeededModelNoPrimaryKey < ActiveRecord::Base end class SeededModelNoSequence < ActiveRecord::Base end RSpec.configure do |config| config.before do SeededModel.delete_all end end seed-fu-v.2.3.5/spec/writer_spec.rb000066400000000000000000000024551250603610500171260ustar00rootroot00000000000000require 'spec_helper' describe SeedFu::Writer do before do @file_name = File.dirname(__FILE__) + '/seeded_models.rb' end after do FileUtils.rm(@file_name) end it "should successfully write some seeds out to a file and then import them back in" do SeedFu::Writer.write(@file_name, :class_name => 'SeededModel') do |writer| writer << { :id => 1, :title => "Mr" } writer << { :id => 2, :title => "Dr" } end load @file_name SeededModel.find(1).title.should == "Mr" SeededModel.find(2).title.should == "Dr" end it "should support chunking" do SeedFu::Writer.write(@file_name, :class_name => 'SeededModel', :chunk_size => 2) do |writer| writer << { :id => 1, :title => "Mr" } writer << { :id => 2, :title => "Dr" } writer << { :id => 3, :title => "Dr" } end load @file_name SeededModel.count.should == 3 File.read(@file_name).should include("# BREAK EVAL\n") end it "should support specifying the output to use 'seed_once' rather than 'seed'" do SeededModel.seed(:id => 1, :title => "Dr") SeedFu::Writer.write(@file_name, :class_name => 'SeededModel', :seed_type => :seed_once) do |writer| writer << { :id => 1, :title => "Mr" } end load @file_name SeededModel.find(1).title.should == "Dr" end end