Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 15 additions & 32 deletions lib/fixture_builder/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,26 +96,25 @@ def dump_tables
Date::DATE_FORMATS[:default] = Date::DATE_FORMATS[:db]
begin
fixtures = tables.inject([]) do |files, table_name|
table_klass = table_name.classify.constantize rescue nil
if table_klass && table_klass < ActiveRecord::Base
rows = table_klass.unscoped do
table_klass.all.collect do |obj|
attrs = obj.attributes
attrs.inject({}) do |hash, (attr_name, value)|
hash[attr_name] = serialized_value_if_needed(table_klass, attr_name, value)
hash
end
end
end
else
rows = ActiveRecord::Base.connection.select_all(select_sql % {table: ActiveRecord::Base.connection.quote_table_name(table_name)})
# Always create our own Class (inheriting from ActiveRecord) so that:
# 1) We can always use ActiveRecord, even if the app doesn't have an
# ActiveRecord model defined (e.g. some join tables)
# 2) We don't have to worry about default scopes and other things that
# may be present on the application's class.
table_class = Class.new(ActiveRecord::Base) { self.table_name = table_name }

records = select_scope_proc.call(table_class).to_a

rows = records.map do |record|
hashize_record_proc.call(record)
end

next files if rows.empty?

row_index = '000'
fixture_data = rows.inject({}) do |hash, record|
hash.merge(record_name(record, table_name, row_index) => record)
end
fixture_data = rows.map do |row|
[record_name(row, table_name, row_index), row]
end.to_h

write_fixture_file fixture_data, table_name

Expand All @@ -127,22 +126,6 @@ def dump_tables
say "Built #{fixtures.to_sentence}"
end

def serialized_value_if_needed(table_klass, attr_name, value)
if table_klass.respond_to?(:type_for_attribute)
if table_klass.type_for_attribute(attr_name).respond_to?(:serialize)
table_klass.type_for_attribute(attr_name).serialize(value)
else
table_klass.type_for_attribute(attr_name).type_cast_for_database(value)
end
else
if table_klass.serialized_attributes.has_key? attr_name
table_klass.serialized_attributes[attr_name].dump(value)
else
value
end
end
end

def write_fixture_file(fixture_data, table_name)
File.open(fixture_file(table_name), 'w') do |file|
file.write fixture_data.to_yaml
Expand Down
24 changes: 23 additions & 1 deletion lib/fixture_builder/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Configuration

ACCESSIBLE_ATTRIBUTES = [:select_sql, :delete_sql, :skip_tables, :files_to_check, :record_name_fields,
:fixture_builder_file, :fixture_directory, :after_build, :legacy_fixtures, :model_name_procs,
:write_empty_files]
:write_empty_files, :select_scope_proc, :hashize_record_proc]
attr_accessor(*ACCESSIBLE_ATTRIBUTES)

SCHEMA_FILES = ['db/schema.rb', 'db/development_structure.sql', 'db/test_structure.sql', 'db/production_structure.sql']
Expand All @@ -35,6 +35,28 @@ def factory(&block)
write_config
end

# this gets called when selecting records from the database to dump into
# fixtures. you can use it to customize things like the order in which
# records are selected.
def select_scope_proc
@select_scope_proc ||= ->(table_class) do
scope = table_class.unscoped
if table_class.primary_key
scope = scope.order(table_class.primary_key => :asc)
end
scope
end
end

# this gets called to turn each record into a hash before dumping to yaml.
# you can customize it if you want to do things like leave out some fields
# (e.g. created_at & updated_at, which are automatically populated by Rails)
def hashize_record_proc
@hashize_record_proc ||= ->(record) do
record.attributes_before_type_cast
end
end

def select_sql
@select_sql ||= "SELECT * FROM %{table}"
end
Expand Down