Class: LiveFixtures::Import

Inherits:
Object
  • Object
show all
Defined in:
lib/live_fixtures/import.rb,
lib/live_fixtures/import/fixtures.rb,
lib/live_fixtures/import/insertion_order_computer.rb

Overview

An object that facilitates the import of fixtures into a database.

Defined Under Namespace

Classes: Fixtures, InsertionOrderComputer, ProgressBarIterator, SimpleIterator

Constant Summary collapse

NO_LABEL =
nil

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_path, insert_order = nil, class_names = {}, **opts) ⇒ LiveFixtures::Import

Instantiate a new Import with the directory containing your fixtures, and the order in which to import them. The order should ensure fixtures containing references to another fixture are imported AFTER the referenced fixture.

Parameters:

  • root_path (String)

    path to the directory containing the yml files to import.

  • insert_order (Array<String> | Nil) (defaults to: nil)

    a list of yml files (without .yml extension) in the order they should be imported, or ‘nil` if these order is to be inferred by this class.

  • class_names (Hash{Symbol => String}) (defaults to: {})

    a mapping table name => Model class, for any that don’t follow convention.

  • opts (Hash)

    export configuration options

Options Hash (**opts):

  • show_progress (Boolean)

    whether or not to show the progress bar

  • skip_missing_tables (Boolean)

    when false, an error will be raised if a yaml file isn’t found for each table in insert_order

  • skip_missing_refs (Boolean)

    when false, an error will be raised if an ID isn’t found for a label.

  • use_insert_order_as_table_names (Boolean)

    when true, table names will be those passed in insert_order, not read from yaml files

Raises:

  • (ArgumentError)

    raises an argument error if not every element in the insert_order has a corresponding yml file.

See Also:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/live_fixtures/import.rb', line 33

def initialize(root_path, insert_order = nil, class_names = {}, **opts)
  defaut_options = {
    show_progress: true,
    skip_missing_tables: false,
    skip_missing_refs: false,
    use_insert_order_as_table_names: false,
  }
  @options = defaut_options.merge(opts)
  @root_path = root_path

  if insert_order && @options[:use_insert_order_as_table_names]
    @table_names = insert_order
  else
    @table_names = Dir.glob(File.join(@root_path, '{*,**}/*.yml')).map do |filepath|
      File.basename filepath, ".yml"
    end
  end

  @class_names = class_names
  @table_names.each { |n|
    @class_names[n.tr('/', '_').to_sym] ||= n.classify if n.include?('/')
  }

  @insert_order = insert_order
  @insert_order ||= InsertionOrderComputer.compute(@table_names, @class_names, compute_polymorphic_associations)

  @table_names = @insert_order.select {|table_name| @table_names.include? table_name}
  if @table_names.size < @insert_order.size && !@options[:skip_missing_tables]
    raise ArgumentError, "table(s) mentioned in `insert_order` which has no yml file to import: #{@insert_order - @table_names}"
  end

  @label_to_id = {}
  @alternate_imports = {}
end

Instance Attribute Details

#alternate_importsHash<String => Proc> (readonly)

Map of table_name to import routine

Returns:

  • (Hash<String => Proc>)


13
14
15
# File 'lib/live_fixtures/import.rb', line 13

def alternate_imports
  @alternate_imports
end

#insert_orderObject (readonly)

Returns the insert order that was specified in the constructor or the inferred one if none was specified.



9
10
11
# File 'lib/live_fixtures/import.rb', line 9

def insert_order
  @insert_order
end

#label_to_idObject (readonly)

Accessor for string label for a given fixture mapping to it’s db id



16
17
18
# File 'lib/live_fixtures/import.rb', line 16

def label_to_id
  @label_to_id
end

Instance Method Details

#import_allObject

Within a transaction, import all the fixtures into the database.

The very similar method: ActiveRecord::FixtureSet.create_fixtures has the unfortunate side effect of truncating each table!!

Therefore, we have reproduced the relevant sections here, without DELETEs, with calling LiveFixtures::Import::Fixtures#each_table_row_with_label instead of ‘AR::Fixtures#table_rows`, and using those labels to populate `@label_to_id`.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/live_fixtures/import.rb', line 77

def import_all
  connection = ActiveRecord::Base.connection
  show_progress = @options[:show_progress]

  # TODO: should be additive with alternate_imports so we can delete the fixture file
  files_to_read = @table_names

  return if files_to_read.empty?

  connection.transaction(requires_new: true) do
    files_to_read.each do |path|
      table_name = path.tr '/', '_'
      if alternate = @alternate_imports[table_name]
        time = Benchmark.ms do
          alternate.call(@label_to_id)
        end
        puts "Imported %s in %.0fms" % [table_name, time] if show_progress
      else
        class_name = @class_names[table_name.to_sym] || table_name.classify

        ff = Fixtures.new(connection,
                          table_name,
                          class_name,
                          ::File.join(@root_path, path),
                          @label_to_id,
                          skip_missing_refs: @options[:skip_missing_refs])

        conn = ff.model_connection || connection

        iterator = show_progress ? ProgressBarIterator : SimpleIterator
        iterator.new(ff).each do |tname, label, row|
          conn.insert_fixture(row, tname)
          @label_to_id[label] = conn.send(:last_inserted_id, tname) unless label == NO_LABEL
        end
      end
    end
  end
end

#override(table_name, callable) ⇒ Object

Override import of table using a callable object

Parameters:

  • table_name (String)

    table to use callable instead of fixture file

  • callable (Proc)

    Proc/lambda that will be called with @label_to_id



119
120
121
122
# File 'lib/live_fixtures/import.rb', line 119

def override(table_name, callable)
  @alternate_imports[table_name] = callable
  self
end