class LiveFixtures::Import::Fixtures

Attributes

ar_fixtures[R]

ActiveRecord::FixtureSet for delegation

Public Class Methods

new(connection, table_name, class_name, filepath, label_to_id, skip_missing_refs: false) click to toggle source

@param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] connection to the database into which to import the data. @param table_name [String] name of the database table to populate with models @param class_name [Constant] the model's class name @param filepath [String] path to the yml file containing the fixtures @param label_to_id [Hash{String => Int}] map from a reference's label to its new id.

# File lib/live_fixtures/import/fixtures.rb, line 19
def initialize(connection, table_name, class_name, filepath, label_to_id, skip_missing_refs: false)
  @skip_missing_refs = skip_missing_refs
  @ar_fixtures = ActiveRecord::FixtureSet.new connection,
    table_name,
    class_name,
    filepath
  @label_to_id = label_to_id
end

Public Instance Methods

each_table_row_with_label() { |table_name, label, row| ... } click to toggle source

Rewritten to take advantage of @label_to_id instead of AR::FixtureSet#identify, and to make an iterator.

@yieldparam table_name [String] the database table's name @yieldparam label [String] the label for the model being currently imported @yieldparam row [Hash{String => Value}] the model's attributes to be imported Iterator which yields [table_name, label, row] for each fixture (and for any implicit join table records). The block is expected to insert the row and update @label_to_id with the record's newly assigned id. @see github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/fixtures.rb#L611

# File lib/live_fixtures/import/fixtures.rb, line 38
def each_table_row_with_label
  join_table_rows = Hash.new { |h,table| h[table] = [] }

  fixtures.map do |label, fixture|
    row = fixture.to_hash

    reflection_class = reflection_class_for row

    reflection_class.reflect_on_all_associations.each do |association|
      next unless row[association.name.to_s]

      case association.macro
        when :belongs_to
          maybe_convert_association_to_foreign_key row, association

        when :has_and_belongs_to_many
          join_table_name = association.join_table

          targets = row.delete(association.name.to_s)
          targets = targets.split(/\s*,\s*/) unless targets.is_a?(Array)

          join_table_rows[join_table_name] << { targets: targets,
                                                association: association,
                                                label: label }
      end
    end

    yield [table_name, label, row]
  end

  join_table_rows.each do |table_name, rows|
    rows.each do |targets:, association:, label:|
      targets.each do |target|
        assoc_fk = @label_to_id[target] || target
        row = { association.foreign_key             => fetch_id_for_label(label),
                association.association_foreign_key => assoc_fk }
        yield [table_name, NO_LABEL, row]
      end
    end
  end
end
model_connection() click to toggle source
# File lib/live_fixtures/import/fixtures.rb, line 80
def model_connection
  model_class.connection if model_class.respond_to? :connection
end

Private Instance Methods

fetch_id_for_label(label_to_fetch) click to toggle source

Uses the underlying map of labels to return the referenced model's newly assigned ID. @raise [LiveFixtures::MissingReferenceError] if the label isn't found. @param label_to_fetch [String] the label of the referenced model. @return [Integer] the newly assigned ID of the referenced model.

# File lib/live_fixtures/import/fixtures.rb, line 120
    def fetch_id_for_label(label_to_fetch)
      @label_to_id.fetch(label_to_fetch)
    rescue KeyError
      return nil if @skip_missing_refs

      raise LiveFixtures::MissingReferenceError, <<-ERROR.squish
      Unable to find ID for model referenced by label #{label_to_fetch} while
      importing #{model_class} from #{table_name}.yml. Perhaps it isn't included
      in these fixtures or it is too late in the insert_order and has not yet
      been imported.
      ERROR
    end
inheritance_column_name() click to toggle source
# File lib/live_fixtures/import/fixtures.rb, line 86
def inheritance_column_name
  @inheritance_column_name ||= model_class && model_class.inheritance_column
end
maybe_convert_association_to_foreign_key(row, association) click to toggle source
# File lib/live_fixtures/import/fixtures.rb, line 99
def maybe_convert_association_to_foreign_key(row, association)
  fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s

  # Do not replace association name with association foreign key if they are named the same
  return if association.name.to_s == fk_name

  value = row.delete(association.name.to_s)

  # support polymorphic belongs_to as "label (Type)"
  if association.options[:polymorphic] && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
    row[association.foreign_type] = $1
  end

  row[fk_name] = fetch_id_for_label(value)
end
reflection_class_for(row) click to toggle source

If STI is used, find the correct subclass for association reflection

# File lib/live_fixtures/import/fixtures.rb, line 91
def reflection_class_for(row)
  return model_class unless row.include?(inheritance_column_name)

  row[inheritance_column_name].constantize
rescue
  model_class
end