ivanzotov/constructor

View on GitHub
pages/app/models/constructor_pages/field.rb

Summary

Maintainability
A
0 mins
Test Coverage
module ConstructorPages
  # Field model. Fields allows to add custom fields for template.
  # Each field has type of value such as float, integer, string...
  class Field < ActiveRecord::Base
    # Array of available field types
    TYPES = %w{string integer float boolean text date html image}

    TYPES.each {|t| class_eval %{has_many :#{t}_types, class_name: 'Types::#{t.titleize}Type'} }

    validates_presence_of :name
    validates_uniqueness_of :code_name, scope: :template_id
    validate :code_name_uniqueness

    after_create :create_page_fields
    after_destroy :destroy_all_page_fields

    has_many :pages, through: :template
    belongs_to :template

    acts_as_list scope: :template_id
    default_scope -> { order :position }

    # Return constant of model type_value
    def type_class; "constructor_pages/types/#{type_value}_type".classify.constantize end

    # Return object of type_value by page
    def find_type_object(page); type_class.find_by(field_id: id, page_id: page.id) end

    # Create object of type_value by page
    def create_type_object(page); type_class.create(field_id: id, page_id: page.id) end

    # Find or create type object by page
    def find_or_create_type_object(page); find_type_object(page) || create_type_object(page) end

    # Remove all type_fields values for specified page
    def remove_type_object(page); find_type_object(page).destroy end

    # Get value from type_field for specified page
    def get_value_for(page); find_type_object(page).tap {|t| return t && t.value} end

    # Set value type_field for specified page
    def set_value_for(page, value); find_type_object(page).tap {|t| t || return; t.update value: value} end

    private

    # Check if code_name is not available
    def code_name_uniqueness
      errors.add(:base, :code_name_already_in_use) unless Page.check_code_name(code_name) and check_code_name(code_name)
    end

    # Check if there is code_name in template branch
    def check_code_name(code_name)
      [code_name.pluralize, code_name.singularize].each {|name|
        %w{self_and_ancestors descendants}.each {|m|
          return false if template.send(m).map(&:code_name).include?(name)}}
      true
    end

    def create_page_fields
      template.page_ids.each_slice(500) do |batch|
        _items = []
        batch.each do |_id|
          _items << type_class.new({page_id: _id, field_id: id})
        end
        type_class.import _items
      end
    end

    def destroy_all_page_fields
      template.page_ids.each_slice(1000) do |batch|
        type_class.where(page_id: batch, field_id: id).delete_all
        Page.update_all({updated_at: Time.now}, {id: batch})
      end
    end
  end
end