core/app/models/comable/category.rb
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