Brian Weinreich
Brian Weinreich

Reputation: 7702

Regenerate fixture test files in Rails

How do I regenerate all the YML fixture files? I accidentally deleted them.

Upvotes: 8

Views: 1019

Answers (2)

Fumisky Wells
Fumisky Wells

Reputation: 1199

When I use Nested Set in our app (let's say MyTree model here), lft/rgt columns calculation are required before use (during testing as well, of course). In order to set collect lft/rgt for all records in fixture of MyTree, there would be some approaches:

  • a) write down calculated lft/rgt values for all of my_trees.yml entries manually.
  • b) execute MyTree.rebuild! in setup block for every necessary test.
  • c) generate calculated fixture file with lft/rgt values.

a) above is quite tedious task for human. b) consumes CPU resource during test for each setup. I think c) is the best approach so that I post my code here.

@sameera207 's code cannot be applied in our case because I use Label references for fixture entry, so that I write the following 'rake task' which generates test/fixtures/my_trees.yml from test/fixtures.src/my_trees.yml:

For example, data model is:

class MyTree < ApplicationRecord
  acts_as_nested_set
  ...
end

and generating task is:

namespace :my_app do
  desc 'rebuild from test/fixtures.src/my_trees.yml to test/fixtures/my_trees.yml'
  task rebuild_my_trees_fixture: :environment do
    require 'active_record/fixtures'

    if !Rails.env.test?
      puts('not test env')
      next
    end

    id_to_entry   = {}    # ActiveRecord::FixtureSet#idnetity -> entry name
    for key, val in YAML.load(ERB.new(File.read('test/fixtures.src/my_trees.yml'), 0, '-').result) do
      id_to_entry[ActiveRecord::FixtureSet.identify(key)] = key
    end

    MyTree.transaction do
      MyTree.delete_all

      # load source to DB
      ::ActiveRecord::FixtureSet.create_fixtures('test/fixtures.src', 'my_trees')

      MyTree.rebuild!(false)
      File.open(Rails.root + 'test/fixtures/my_trees.yml', 'w') do |f|
        # write header
        f.write <<~EOS
          # ===================================================================
          #                   Do not modify this file manually!!
          #                  This file is automatically generated.
          # ===================================================================
        EOS

        hash = {}
        for rec in MyTree.all do
          key = id_to_entry[rec.id]
          if key.nil?
            STDERR.printf("ERROR: entry not found for id(%d)\n", rec.id)
          else
            hash[id_to_entry[rec.id]] = rec.attributes.except('id')
          end
        end
        f.write(hash.to_yaml)
      end

      # cache should be cleaned here.  Otherwise this working my_trees table 
      # remains at the 'rake test' later.
      ::ActiveRecord::FixtureSet.reset_cache

      raise ActiveRecord::Rollback
    end
  end
end

# invoke above task before 'rake test'
task :'test'    => 'my_app:rebuild_my_trees_fixture'

The key point is MyTree.rebuild! in the above code, which calculates all of lft/rgt for all entries. All of other fragments of codes above are just preparation and generation.

TODO

I didn't have time to write this task to be invoked by file dependency trigger between fixtures.src/my_trees.yml and test/fixtures/my_trees.yml.

Upvotes: 0

sameera207
sameera207

Reputation: 16629

@brian,

I'm using the following script to generate the fixtures from a given sql

This is under my lib/task directory as a rake task

namespace :fixture_generator do
  desc "generate fixtures for a given sql query from the current development database"

  task :fixture_generator, [:sql, :file_name] => :environment do |t, args|
    args.with_defaults(:sql => nil, :file_name => nil)
    i = "000"
    p "creating fixture - #{args.file_name}"
    File.open("#{Rails.root}/test/fixtures/#{args.file_name}.yml", 'a+') do |file|
      data = ActiveRecord::Base.connection.select_all(args.sql)
      file.write data.inject({}) { |hash, record|
        number = i.succ!
        hash["#{args.file_name}_#{number}"] = record
        hash
      }.to_yaml
    end

  end
end

Usage, Say I want to generate fixture for users table

rake fixture_generator:fixture_generator["select * from users","users"]

And also, If you run another query with the same fixture file name, it will append to the existing one

HTH

Upvotes: 10

Related Questions