Rademade/rademade_admin

View on GitHub
lib/rademade_admin/model/adapter/data/active_record.rb

Summary

Maintainability
A
1 hr
Test Coverage
# -*- encoding : utf-8 -*-
module RademadeAdmin
  module Model
    module Adapter
      class Data
        class ActiveRecord < RademadeAdmin::Model::Adapter::Data

          protected

          def has_many_relations
            [:has_many, :has_and_belongs_to_many]
          end

          def has_one_relations
            [:has_one, :belongs_to]
          end

          def _map_fields
            fields = {}
            _add_non_localizable_fields fields
            _add_localizable_fields fields
          end

          def _map_relations
            relations = {}
            @model.reflections.each do |name, relation_info|
              name = name.to_sym
              type = relation_info.macro
              if name != :translations
                to_class = relation_info.polymorphic? ? nil : RademadeAdmin::LoaderService.const_get(relation_info.class_name)
                is_sortable = relation_info.respond_to?(:sortable?) ? relation_info.sortable? : false
                relations[name] = _relation_class_name(to_class).new({
                  :name => name,
                  :from => @model,
                  :to => to_class,
                  :destroyable => _relation_destroyable?(relation_info),
                  :getter => name,
                  :setter => :"#{name}=",
                  :type => type,
                  :many => type == :has_many,
                  :has_many => has_many_relations.include?(type),
                  :sortable => is_sortable,
                  :sortable_field => is_sortable ? relation_info.sortable_field : nil,
                  :foreign_key => relation_info.foreign_key.to_sym
                })
              end
            end
            relations
          end

          def _relation_destroyable?(relation_info)
            !_validates_association?(relation_info) &&
              !_validates_presence?(relation_info)
          end

          def _validates_association?(relation_info)
            _model_validates?(@model,
                             relation_info.name,
                             ::ActiveRecord::Validations::AssociatedValidator)
          end

          def _validates_presence?(relation_info)
            _model_validates?(relation_info.klass,
                             relation_info.foreign_key,
                             ::ActiveRecord::Validations::PresenceValidator)
          end

          def _model_validates?(model, name, validator_class)
            model.validators.select do |validator|
              validator.class == validator_class &&
                validator.attributes.include?(name)
            end.any?
          end

          def _add_non_localizable_fields(fields)
            @model.attribute_types.each do |field_name, field_data|
              name = field_name.to_sym
              fields[name] = RademadeAdmin::Model::Info::Field.new({
                :name => name,
                :primary => @model.primary_key == field_name,
                :getter => name,
                :setter => :"#{name}=",
                :type => field_type(extract_column_data(field_data).type),
                :localizable => false,
                :relation_name => name[/(.+)_id$/, 1]
              })
            end
            fields
          end

          def _add_localizable_fields(fields)
            @model.try(:translated_attribute_names).each do |name|
              name = name.to_sym
              fields[name] = RademadeAdmin::Model::Info::Field.new({
                :name => name,
                :primary => false,
                :getter => name,
                :setter => :"#{name}=",
                :localizable => true
              })
            end if @model.respond_to?(:translation_class)
            fields
          end

          def _model_uploaders
            return super unless @model.respond_to?(:translation_class)
            super.merge(@model.translation_class.uploaders)
          end

          def _model_fields
            @model.attribute_types.keys.map(&:to_sym)
          end

          private

          def field_type(type)
            case type
              when :string
                RademadeAdmin::Model::Info::Field::Type::STRING
              when :boolean
                RademadeAdmin::Model::Info::Field::Type::BOOLEAN
              when :date
                RademadeAdmin::Model::Info::Field::Type::DATE
              when :datetime
                RademadeAdmin::Model::Info::Field::Type::DATE_TIME
              when :text
                RademadeAdmin::Model::Info::Field::Type::TEXT
            end
          end

          def extract_column_data(field_data)
            if datetime_type?(field_data)
              field_data.instance_values['column']
            else
              field_data
            end
          end

          def datetime_type?(field_data)
            defined?(::ActiveRecord::AttributeMethods::TimeZoneConversion::Type) &&
              field_data.is_a?(::ActiveRecord::AttributeMethods::TimeZoneConversion::Type)
          end

        end
      end
    end
  end
end