|
class SeedsYaml |
|
BASE = R.root.join("db").to_s |
|
SEEDS = R.root.join("db", "seeds").to_s |
|
DEVELOPMENT = R.root.join("db", "seeds", "development").to_s |
|
TEST = R.root.join("db", "seeds", "test").to_s |
|
PRODUCTION = R.root.join("db", "seeds", "production").to_s |
|
|
|
require 'yaml' |
|
|
|
def initialize |
|
@options = {} |
|
|
|
build_options(SEEDS) |
|
|
|
case Rails.env |
|
when "development" |
|
build_options(DEVELOPMENT) |
|
when "test" |
|
build_options(TEST) |
|
when "production" |
|
build_options(PRODUCTION) |
|
end |
|
|
|
parse_fixtures @options |
|
end |
|
|
|
|
|
def build_options(directory) |
|
Dir::foreach(directory) do |file| |
|
file = directory + "/" + file |
|
next if File.directory?(file) || File.extname(file) != ".yml" |
|
|
|
model_name = File.basename(file, ".yml").camelcase |
|
@options[file] = { model_name: model_name, key_field: 'id' } |
|
end |
|
end |
|
|
|
|
|
protected |
|
|
|
def parse_fixtures(files_options_hash) |
|
|
|
# load the data from the files |
|
fixtures = Hash.new |
|
files_options_hash.each_key do |filename| |
|
fixtures[filename] = YAML.load(ERB.new(File.read(filename)).result) |
|
end |
|
|
|
# before updating collect all the objects by names given in fixtures |
|
all_objects = Hash.new |
|
# and remember which need to be updated with their hash |
|
to_update = Hash.new |
|
|
|
# for each fixture file |
|
fixtures.each do |filename, fixtures_hash| |
|
|
|
model_classname = files_options_hash[filename][:model_name].classify.split("--").select { |w| w.capitalize! || w }.join("::") |
|
model_class = model_classname.constantize |
|
key_field = files_options_hash[filename][:key_field] |
|
|
|
#for each fixture within the file |
|
fixtures_hash.each do |fixture, values_hash| |
|
if files_options_hash[filename][:update?] |
|
# if we doing updates get or initialise it and apply the values then save |
|
model_instance = model_class.find_or_initialize_by(key_field => values_hash[key_field]) |
|
all_objects[fixture] = model_instance |
|
to_update[fixture] = values_hash |
|
else |
|
# if we're not updating check if it's there and add it if it's not |
|
model_instance = model_class.find_by(key_field => values_hash[key_field]) |
|
if !model_instance |
|
model_instance = model_class.new |
|
to_update[fixture] = values_hash |
|
end |
|
all_objects[fixture] = model_instance |
|
end |
|
end |
|
end |
|
|
|
# now we've collected all the models we can update the ones that need updating |
|
to_update.each do |fixture_name, values_hash| |
|
update_model_instance(all_objects[fixture_name], values_hash, all_objects.except(fixture_name)) |
|
end |
|
|
|
end |
|
|
|
# Update a model instance with values from a fixture. |
|
# Some values may refer to other fixtures |
|
def update_model_instance(model_instance, values_hash, all_fixture_instances) |
|
|
|
values_hash.each do |field, value| |
|
# if the field is an array we need to assign with 'push' instead of '=' |
|
|
|
|
|
# if namespaced model, alter key with table prefix |
|
namespace = model_instance.class.module_parent |
|
if (namespace.respond_to?("table_name_prefix")) |
|
table_prefix = namespace.table_name_prefix |
|
|
|
if model_instance.attributes.key?(table_prefix + field + "_id") |
|
field_target = table_prefix + field |
|
else |
|
field_target = field |
|
end |
|
else |
|
field_target = field |
|
end |
|
|
|
|
|
if model_instance.send(field_target).respond_to?("push") |
|
model_instance.send(field_target).clear |
|
push = true |
|
end |
|
# it may be a comma seperated list of fixtures so process it |
|
values_array = replace_strings_with_fixtures(value, all_fixture_instances) |
|
values_array.each do |value| |
|
if push |
|
model_instance.send(field_target).push(value) |
|
else |
|
field_type = model_instance.type_for_attribute(field_target) |
|
|
|
|
|
# Find Referenced Model Record by id, when integer passed as value |
|
if field_type.type == nil and value.is_a?(Numeric) # is reference and using numeric reference |
|
model_instance.class.reflect_on_all_associations(:belongs_to).each do |belongs_to| |
|
if (belongs_to.name.to_s == field_target) |
|
value = belongs_to.klass.find(value) |
|
end |
|
end |
|
end |
|
|
|
|
|
model_instance.send(field_target + '=', value) |
|
end |
|
end |
|
end |
|
|
|
model_instance.save! |
|
|
|
end |
|
|
|
def replace_strings_with_fixtures(value, all_fixture_instances) |
|
|
|
if value.respond_to?("split") |
|
# it might be a comma sperated list of fixtures |
|
fixtures_array = value.split(',').map(&:strip) |
|
fixtures_array.each_with_index do |fixture_name, index| |
|
if obj = all_fixture_instances[fixture_name] |
|
fixtures_array[index] = obj |
|
else |
|
# could not find one fixture |
|
# it must just be a string after all |
|
return [value] |
|
end |
|
end |
|
return fixtures_array |
|
end |
|
# it's not a string, return it in it's own array |
|
return [value] |
|
end |
|
|
|
end |
|
|
|
|