Skip to content

Instantly share code, notes, and snippets.

@ippeiukai
Last active December 18, 2015 09:59
Show Gist options
  • Save ippeiukai/5765797 to your computer and use it in GitHub Desktop.
Save ippeiukai/5765797 to your computer and use it in GitHub Desktop.
A monkey patch that speeds up fixture loading of Rails 3.2. The speed up in my case was by five-fold (with ``time rake db:fixtures:load``), quite significant if you have a large set of fixtures and load them regularly.
# for Rails 3.2.12
# loads fixtures a lot faster
require 'active_record/fixtures'
class ActiveRecord::Fixtures
# based on activerecord-3.2.12/lib/active_record/fixtures.rb l.462
# modified lines are marked CHANGED
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
table_names = [table_names].flatten.map { |n| n.to_s }
table_names.each { |n|
class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/')
}
# FIXME: Apparently JK uses this.
connection = block_given? ? yield : ActiveRecord::Base.connection
files_to_read = table_names.reject { |table_name|
fixture_is_cached?(connection, table_name)
}
unless files_to_read.empty?
connection.disable_referential_integrity do
fixtures_map = {}
fixture_files = files_to_read.map do |path|
table_name = path.tr '/', '_'
fixtures_map[path] = ActiveRecord::Fixtures.new(
connection,
table_name,
class_names[table_name.to_sym] || table_name.classify,
::File.join(fixtures_directory, path))
end
all_loaded_fixtures.update(fixtures_map)
connection.transaction(:requires_new => true) do
fixture_files.each do |ff|
conn = ff.model_class.respond_to?(:connection) ? ff.model_class.connection : connection
table_rows = ff.table_rows
table_rows.keys.each do |table|
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
end
table_rows.each do |table_name,rows|
if conn.respond_to?(:insert_fixtures) # CHANGED +
conn.insert_fixtures(rows, table_name) # CHANGED +
else # CHANGED +
rows.each do |row|
conn.insert_fixture(row, table_name)
end
end # CHANGED +
end
end
# Cap primary key sequences to max(pk).
if connection.respond_to?(:reset_pk_sequence!)
table_names.each do |table_name|
connection.reset_pk_sequence!(table_name.tr('/', '_'))
end
end
end
cache_fixtures(connection, fixtures_map)
end
end
cached_fixtures(connection, table_names)
end
end
module FasterFixtureLoading
module DatabaseStatements
# Inserts multiple fixtures into the table.
def insert_fixtures(fixtures, table_name)
columns = columns(table_name).index_by(&:name)
fixtures.group_by { |fixture| fixture.keys.sort }.each do |keys, fixtures_with_same_keys|
key_list = keys.map { |name| quote_column_name(name) }
value_lists = []
fixtures_with_same_keys.each do |fixture|
value_lists << keys.map { |name| quote(fixture[name], columns[name]) }
end
value_lists_string = value_lists.map { |value_list| "(#{value_list.join(', ')})" }.join(',')
execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES #{value_lists_string}", 'Fixture Insert'
end
end
end
end
ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:include, FasterFixtureLoading::DatabaseStatements)
@ippeiukai
Copy link
Author

@austinfromboston
Copy link

This is great -- are you pursuing it with the core team?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment