Class: ActiveRecordArchiver
- Inherits:
-
Object
- Object
- ActiveRecordArchiver
- Defined in:
- lib/activerecord-archiver/export.rb,
lib/activerecord-archiver/import.rb,
lib/activerecord-archiver/archiver.rb
Overview
method ActiveRecordArchiver::import
Arguments:
A string of JSON generated by ActiveRecordArchiver::export
Returns:
true on success, raises an Exception and rolls back the db on failure
Effects:
Attempts to create and save a new record for each item in the input JSON structure and
connects the specified belongs_to relations
Class Method Summary collapse
- .assert_instance_of(instance, klass) ⇒ Object
- .assert_model(model) ⇒ Object
- .belongs_to?(model, attribute) ⇒ Boolean
- .cols_for_model(model, all_models, options = {}) ⇒ Object
- .column(model, attribute) ⇒ Object
- .column_required(model, attribute) ⇒ Object
- .export(*args) ⇒ Object
- .has_attribute?(model, attribute) ⇒ Boolean
- .id_warning(model, col) ⇒ Object
- .import(json) ⇒ Object
- .insertable_hash(model, hash) ⇒ Object
- .models_hash_from_args(args) ⇒ Object
- .parse_array_option(options, key) ⇒ Object
- .relation(model, attribute) ⇒ Object
- .relation_foreign_key(model, key) ⇒ Object
- .relation_from_key(model, attribute) ⇒ Object
- .relation_id(model, key, value) ⇒ Object
- .relation_index(record, attribute) ⇒ Object
- .relation_model(model, attribute) ⇒ Object
- .relations_update_hash(model, record) ⇒ Object
Class Method Details
.assert_instance_of(instance, klass) ⇒ Object
68 69 70 71 72 |
# File 'lib/activerecord-archiver/archiver.rb', line 68 def self.assert_instance_of instance, klass unless instance.class <= klass raise "Object #{instance} is not an instance of the #{klass} model" end end |
.assert_model(model) ⇒ Object
74 75 76 77 78 |
# File 'lib/activerecord-archiver/archiver.rb', line 74 def self.assert_model model unless model < ActiveRecord::Base raise "#{model} is not an activerecord model" end end |
.belongs_to?(model, attribute) ⇒ Boolean
14 15 16 |
# File 'lib/activerecord-archiver/archiver.rb', line 14 def self.belongs_to? model, attribute !!relation(model, attribute).try(:belongs_to?) end |
.cols_for_model(model, all_models, options = {}) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/activerecord-archiver/archiver.rb', line 99 def self.cols_for_model model, all_models, ={} model.columns.map do |col| if (col.primary or parse_array_option(, :exclude).include? col.name) # omit primary keys and excluded columns nil elsif (relation = relation_from_key(model, col.name)) and relation.belongs_to? # include belongs_to relations to included models if all_models.include? relation.klass relation.name else nil end else # warn before adding an attribute ending in '_id' warn id_warning(model, col) if col.name =~ /_id$/ col.name end end.compact end |
.column(model, attribute) ⇒ Object
18 19 20 |
# File 'lib/activerecord-archiver/archiver.rb', line 18 def self.column model, attribute model.columns_hash.with_indifferent_access[attribute] end |
.column_required(model, attribute) ⇒ Object
22 23 24 |
# File 'lib/activerecord-archiver/archiver.rb', line 22 def self.column_required model, attribute column(model, attribute).null == false end |
.export(*args) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/activerecord-archiver/export.rb', line 39 def self.export *args @models_hash = models_hash_from_args(args) result = {} # serialize @models_hash.each_pair do |model, pair| records, attributes = pair result[model.to_s] = [] records.each do |record| assert_instance_of record, model rec = {} attributes.each do |attribute| attribute, placeholder = if attribute.is_a? Array then attribute else [attribute, nil] end if has_attribute? model, attribute # store attribute rec[attribute] = if placeholder.nil? then record.send attribute else placeholder end elsif belongs_to?(model, attribute) # store relation if (index = relation_index(record, attribute)) rec[attribute] = index if placeholder rec[relation_foreign_key(model, attribute)] = placeholder end end else raise "#{attribute} is not an attribute or belongs_to relation of #{model}" end end result[model.to_s] << rec end end # encode JSON.dump result end |
.has_attribute?(model, attribute) ⇒ Boolean
2 3 4 |
# File 'lib/activerecord-archiver/archiver.rb', line 2 def self.has_attribute? model, attribute model.columns_hash.with_indifferent_access.has_key? attribute end |
.id_warning(model, col) ⇒ Object
93 94 95 96 97 |
# File 'lib/activerecord-archiver/archiver.rb', line 93 def self.id_warning model, col "Warning: #{model}##{col.name} included in export." + " To exclude it use ActiveRecordArchiver.export(#{model.name.downcase.pluralize} => " + "{:exclude => [:#{col.name}]})" end |
.import(json) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/activerecord-archiver/import.rb', line 18 def self.import json @data = JSON.parse json ActiveRecord::Base.transaction do # insert records @data.each_pair do |model_name, records| model = model_name.constantize assert_model model records.each do |record| record[:id] = model.all.insert(insertable_hash(model, record)) end end # add relations @data.each_pair do |model_name, records| model = model_name.constantize records.each do |record| if (update_hash = relations_update_hash(model, record)) instance = model.find(record[:id]) instance.update update_hash end end end end true end |
.insertable_hash(model, hash) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/activerecord-archiver/archiver.rb', line 40 def self.insertable_hash model, hash ret = {} hash.each_pair do |key, value| if column(model, key) ret[column(model, key)] = value elsif belongs_to?(model, key) foreign_key = relation_foreign_key(model, key) if !hash.include?(foreign_key) and column_required(model, foreign_key) # if the foreign key is required connect it to the first available record temporarily ret[column(model, foreign_key)] = relation_model(model, key).first.try(:id) || 0 end else raise "#{key} is not an attribute or belongs_to relation of #{model}" end end ret end |
.models_hash_from_args(args) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/activerecord-archiver/export.rb', line 85 def self.models_hash_from_args args = args. args.each do |arg| [arg] = :all end .keys.each do |collection| if collection.is_a? ActiveRecord::Base [[collection]] = [collection] .delete(collection) end end models = .each_pair.map do |collection, _| collection.first.class end models_hash = {} .each_pair do |collection, cols| models_hash[collection.first.class] = [collection, if cols.is_a? Array then cols elsif cols == :all or cols.is_a? Hash cols_for_model(collection.first.class, models, cols) else raise "unknown column specification: #{cols}" end] end models_hash end |
.parse_array_option(options, key) ⇒ Object
84 85 86 87 88 89 90 91 |
# File 'lib/activerecord-archiver/archiver.rb', line 84 def self.parse_array_option , key if .is_a? Hash case [key] when Array then [key].map(&:to_s) when nil then [] else [[key].to_s] end else [] end end |
.relation(model, attribute) ⇒ Object
6 7 8 |
# File 'lib/activerecord-archiver/archiver.rb', line 6 def self.relation model, attribute model.reflections.with_indifferent_access[attribute] end |
.relation_foreign_key(model, key) ⇒ Object
36 37 38 |
# File 'lib/activerecord-archiver/archiver.rb', line 36 def self.relation_foreign_key model, key relation(model, key).foreign_key end |
.relation_from_key(model, attribute) ⇒ Object
80 81 82 |
# File 'lib/activerecord-archiver/archiver.rb', line 80 def self.relation_from_key model, attribute model.reflections.values.detect{|ref| ref.foreign_key == attribute} end |
.relation_id(model, key, value) ⇒ Object
31 32 33 34 |
# File 'lib/activerecord-archiver/archiver.rb', line 31 def self.relation_id model, key, value relation_model_name = relation(model, key).class_name @data[relation_model_name][value][:id] end |
.relation_index(record, attribute) ⇒ Object
26 27 28 29 |
# File 'lib/activerecord-archiver/archiver.rb', line 26 def self.relation_index record, attribute relevant_records = @models_hash[relation_model(record.class, attribute)].first relevant_records.present? && relevant_records.map(&:id).index(record.send(attribute).id) end |
.relation_model(model, attribute) ⇒ Object
10 11 12 |
# File 'lib/activerecord-archiver/archiver.rb', line 10 def self.relation_model model, attribute relation(model, attribute).class_name.constantize end |
.relations_update_hash(model, record) ⇒ Object
58 59 60 61 62 63 64 65 66 |
# File 'lib/activerecord-archiver/archiver.rb', line 58 def self.relations_update_hash(model, record) ret = {} record.each_pair do |key, value| if belongs_to?(model, key) ret[relation_foreign_key(model, key)] = relation_id(model, key, value) end end ret.presence end |