module DenormalizeFields
Constants
- VERSION
Public Instance Methods
apply(changeset, to:, owner:, mapping:)
click to toggle source
Note: missing related records are ignored, and new related records are not persisted. Extra options to raise/create/persist in this case might be nice.
# File lib/denormalize_fields.rb, line 50 def apply(changeset, to:, owner:, mapping:) return if to.nil? to.assign_attributes(changeset) return if to.new_record? ? to.valid? : to.save DenormalizeFields.copy_errors(to.errors, to_record: owner, mapping: mapping) raise(ActiveRecord::RecordInvalid, to) end
call(record:, relation_name:, mapping:)
click to toggle source
# File lib/denormalize_fields.rb, line 24 def call(record:, relation_name:, mapping:) changeset = DenormalizeFields.changeset(record: record, mapping: mapping) return if changeset.empty? Array(record.send(relation_name)).each do |related_record| DenormalizeFields.apply( changeset, to: related_record, owner: record, mapping: mapping ) end end
cast_to_mapping(fields, prefix: nil)
click to toggle source
# File lib/denormalize_fields.rb, line 15 def cast_to_mapping(fields, prefix: nil) if fields.is_a?(Hash) prefix && raise(ArgumentError, 'pass EITHER a fields Hash OR a prefix') fields else Array(fields).map { |e| [e.to_sym, [prefix, e].join.to_sym] }.to_h end end
changeset(record:, mapping:)
click to toggle source
# File lib/denormalize_fields.rb, line 35 def changeset(record:, mapping:) mapping.each.with_object({}) do |(source, dest), hash| if source.is_a?(Array) if source.any? { |field| record.saved_change_to_attribute?(field) } current_values = record.attributes.values_at(*source.map(&:to_s)) hash[dest] = current_values.join(' ') end elsif change = record.saved_change_to_attribute(source) hash[dest] = change.last end end end
copy_errors(errors, to_record:, mapping:)
click to toggle source
TODO: use Errors#import when it becomes available in rails 6.1 or 6.2
# File lib/denormalize_fields.rb, line 61 def copy_errors(errors, to_record:, mapping:) errors.details.each do |key, array| field = mapping.rassoc(key.to_sym).first array.each do |details| to_record.errors.add(field, details[:error], **details.except(:error)) end end end
denormalize(fields:, from:, onto:, prefix: nil)
click to toggle source
# File lib/denormalize_fields.rb, line 7 def denormalize(fields:, from:, onto:, prefix: nil) mapping = cast_to_mapping(fields, prefix: prefix) from.after_save do DenormalizeFields.call(record: self, relation_name: onto, mapping: mapping) end end