Skip to content

Commit 65fe74d

Browse files
committed
Simplify fixture generation and add customization hooks
- Always use ActiveRecord instead of only when we happen to be able to constantize the name. - Add select_scope_proc for custom record selection - Add hashize_record_proc for custom serialization - Use attributes_before_type_cast
1 parent b2478fe commit 65fe74d

2 files changed

Lines changed: 39 additions & 33 deletions

File tree

lib/fixture_builder/builder.rb

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,26 +96,25 @@ def dump_tables
9696
Date::DATE_FORMATS[:default] = Date::DATE_FORMATS[:db]
9797
begin
9898
fixtures = tables.inject([]) do |files, table_name|
99-
table_klass = table_name.classify.constantize rescue nil
100-
if table_klass && table_klass < ActiveRecord::Base
101-
rows = table_klass.unscoped do
102-
table_klass.all.collect do |obj|
103-
attrs = obj.attributes
104-
attrs.inject({}) do |hash, (attr_name, value)|
105-
hash[attr_name] = serialized_value_if_needed(table_klass, attr_name, value)
106-
hash
107-
end
108-
end
109-
end
110-
else
111-
rows = ActiveRecord::Base.connection.select_all(select_sql % {table: ActiveRecord::Base.connection.quote_table_name(table_name)})
99+
# Always create our own Class (inheriting from ActiveRecord) so that:
100+
# 1) We can always use ActiveRecord, even if the app doesn't have an
101+
# ActiveRecord model defined (e.g. some join tables)
102+
# 2) We don't have to worry about default scopes and other things that
103+
# may be present on the application's class.
104+
table_class = Class.new(ActiveRecord::Base) { self.table_name = table_name }
105+
106+
records = select_scope_proc.call(table_class).to_a
107+
108+
rows = records.map do |record|
109+
hashize_record_proc.call(record)
112110
end
111+
113112
next files if rows.empty?
114113

115114
row_index = '000'
116-
fixture_data = rows.inject({}) do |hash, record|
117-
hash.merge(record_name(record, table_name, row_index) => record)
118-
end
115+
fixture_data = rows.map do |row|
116+
[record_name(row, table_name, row_index), row]
117+
end.to_h
119118

120119
write_fixture_file fixture_data, table_name
121120

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

130-
def serialized_value_if_needed(table_klass, attr_name, value)
131-
if table_klass.respond_to?(:type_for_attribute)
132-
if table_klass.type_for_attribute(attr_name).respond_to?(:serialize)
133-
table_klass.type_for_attribute(attr_name).serialize(value)
134-
else
135-
table_klass.type_for_attribute(attr_name).type_cast_for_database(value)
136-
end
137-
else
138-
if table_klass.serialized_attributes.has_key? attr_name
139-
table_klass.serialized_attributes[attr_name].dump(value)
140-
else
141-
value
142-
end
143-
end
144-
end
145-
146129
def write_fixture_file(fixture_data, table_name)
147130
File.open(fixture_file(table_name), 'w') do |file|
148131
file.write fixture_data.to_yaml

lib/fixture_builder/configuration.rb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ class Configuration
88
include Delegations::Namer
99

1010
ACCESSIBLE_ATTRIBUTES = [:select_sql, :delete_sql, :skip_tables, :files_to_check, :record_name_fields,
11-
:fixture_builder_file, :fixture_directory, :after_build, :legacy_fixtures, :model_name_procs]
11+
:fixture_builder_file, :fixture_directory, :after_build, :legacy_fixtures, :model_name_procs,
12+
:select_scope_proc, :hashize_record_proc]
1213
attr_accessor(*ACCESSIBLE_ATTRIBUTES)
1314

1415
SCHEMA_FILES = ['db/schema.rb', 'db/development_structure.sql', 'db/test_structure.sql', 'db/production_structure.sql']
@@ -33,6 +34,28 @@ def factory(&block)
3334
write_config
3435
end
3536

37+
# this gets called when selecting records from the database to dump into
38+
# fixtures. you can use it to customize things like the order in which
39+
# records are selected.
40+
def select_scope_proc
41+
@select_scope_proc ||= ->(table_class) do
42+
scope = table_class.unscoped
43+
if table_class.primary_key
44+
scope = scope.order(table_class.primary_key => :asc)
45+
end
46+
scope
47+
end
48+
end
49+
50+
# this gets called to turn each record into a hash before dumping to yaml.
51+
# you can customize it if you want to do things like leave out some fields
52+
# (e.g. created_at & updated_at, which are automatically populated by Rails)
53+
def hashize_record_proc
54+
@hashize_record_proc ||= ->(record) do
55+
record.attributes_before_type_cast
56+
end
57+
end
58+
3659
def select_sql
3760
@select_sql ||= "SELECT * FROM %{table}"
3861
end

0 commit comments

Comments
 (0)