appirits/comable

View on GitHub
core/app/models/comable/category.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Comable
  class Category < ActiveRecord::Base
    has_and_belongs_to_many :products, class_name: Comable::Product.name, join_table: :comable_products_categories
    has_ancestry
    acts_as_list scope: [:ancestry]

    default_scope -> { order('position ASC') }

    after_save :touch_all_products

    DEFAULT_PATH_NAME_DELIMITER = ' > '

    class << self
      def path_names(delimiter: DEFAULT_PATH_NAME_DELIMITER)
        categoris.path(&:name).join(delimiter)
      end

      def find_by_path_names(path_names, delimiter: DEFAULT_PATH_NAME_DELIMITER)
        path_names.map do |path_name|
          find_by_path_name(path_name, delimiter: delimiter)
        end.compact
      end

      def find_by_path_name(path_name, root: nil, delimiter: DEFAULT_PATH_NAME_DELIMITER)
        names = path_name.split(delimiter)
        names.inject(root) do |category, name|
          (category ? category.children : roots).find_by(name: name) || break
        end
      end

      def to_jstree(options = {})
        build_to_jstree(arrange_serializable(order: :position), options).to_json
      end

      def from_jstree!(jstree_json)
        jstree = JSON.parse(jstree_json)

        transaction do
          restore_from_jstree!(jstree)
        end
      end

      private

      def build_to_jstree(serialized_categories, options = {})
        serialized_categories.map do |serialized_category|
          options.merge(
            id: serialized_category['id'],
            text: serialized_category['name'],
            children: build_to_jstree(serialized_category['children'], options)
          )
        end
      end

      def restore_from_jstree!(jstree, parent = nil)
        return unless jstree

        jstree.each.with_index(1) do |node, index|
          return find(node['_destroy']).destroy! if node['_destroy'].present?

          restore_from_jstree_node!(node, parent, position: index)
        end
      end

      def restore_from_jstree_node!(node, parent, default_attributes = {})
        attributes = default_attributes.merge(parent: parent, name: node['text'])
        category = node['id'].to_i.zero? ? new : find(node['id'])
        category.update_attributes!(attributes)

        restore_from_jstree!(node['children'], category)
      end
    end

    def touch_all_products
      products.update_all(updated_at: Time.now)
    end
  end
end