diff --git a/app/controllers/body_trackers_controller.rb b/app/controllers/body_trackers_controller.rb index 7441f65..8da8a8c 100644 --- a/app/controllers/body_trackers_controller.rb +++ b/app/controllers/body_trackers_controller.rb @@ -24,22 +24,22 @@ class BodyTrackersController < ApplicationController " #{'unit'.pluralize(new_units.length)}" # Quantities - available_quantities = @project.quantities.map { |q| [[q.name, q.domain], q] }.to_h + available_quantities = Quantity.each_with_path(@project.quantities).map(&:rotate).to_h quantities_count = available_quantities.length defaults = Quantity.where(project: nil) - Quantity.each_with_level(defaults) do |q, level| - unless available_quantities.has_key?([q.name, q.domain]) + Quantity.each_with_path(defaults) do |q, path| + unless available_quantities.has_key?(path) attrs = q.attributes.except('id', 'project_id', 'parent_id', 'lft', 'rgt', 'created_at', 'updated_at') if q.parent - attrs['parent'] = available_quantities[[q.parent.name, q.parent.domain]] + attrs['parent'] = available_quantities[path.rpartition('::').first] end if q.formula attrs['formula_attributes'] = q.formula.attributes .except('id', 'quantity_id', 'unit_id', 'created_at', 'updated_at') attrs['formula_attributes']['unit_id'] = available_units[q.formula.unit.shortname] end - available_quantities[[q.name, q.domain]] = @project.quantities.build(attrs) + available_quantities[path] = @project.quantities.build(attrs) end end Quantity.transaction do diff --git a/app/models/quantity.rb b/app/models/quantity.rb index 07e7fe1..74f5118 100644 --- a/app/models/quantity.rb +++ b/app/models/quantity.rb @@ -22,8 +22,8 @@ class Quantity < ActiveRecord::Base # TODO: :name should be validated against model names (Meal, Ingredient etc.) # Quantity :name uniqueness relaxed to formulas unambiguity validates :name, presence: true, uniqueness: {scope: [:project_id, :parent_id]} - # Formula ambiguity vlidation delayed after save, as otherwise there seems to - # be no other way to validate against newly changed :name + # Formula ambiguity validation delayed after_save, as there seems to be no + # other way to validate against newly changed Quantity :name from Formula after_save do next unless name_changed? || changes.empty? formulas = Formula.joins(:quantity).where(quantities: {project_id: project}) diff --git a/db/migrate/002_load_defaults.rb b/db/migrate/002_load_defaults.rb index 3f028ef..639e3be 100644 --- a/db/migrate/002_load_defaults.rb +++ b/db/migrate/002_load_defaults.rb @@ -186,6 +186,7 @@ class LoadDefaults < ActiveRecord::Migration dir.down do Source.where(project: nil).delete_all + Formula.joins(:quantity).where(quantities: {project_id: nil}).delete_all Quantity.where(project: nil).delete_all Unit.where(project: nil).delete_all end diff --git a/init.rb b/init.rb index 0fea894..e82d133 100644 --- a/init.rb +++ b/init.rb @@ -1,5 +1,6 @@ (Rails::VERSION::MAJOR < 5 ? ActionDispatch : ActiveSupport)::Reloader.to_prepare do Project.include BodyTracking::ProjectPatch + CollectiveIdea.include BodyTracking::AwesomeNestedSetPatch end Redmine::Plugin.register :body_tracking do diff --git a/lib/body_tracking/awesome_nested_set_patch.rb b/lib/body_tracking/awesome_nested_set_patch.rb new file mode 100644 index 0000000..1e3a772 --- /dev/null +++ b/lib/body_tracking/awesome_nested_set_patch.rb @@ -0,0 +1,25 @@ +module BodyTracking::AwesomeNestedSetPatch + CollectiveIdea::Acts::NestedSet.class_eval do + module CollectiveIdea::Acts::NestedSet + class Iterator + def each_with_path + return to_enum(__method__) { objects.length } unless block_given? + + path = [nil] + objects.each do |o| + path[path.rindex(o.parent)+1..-1] = o + yield [o, path.map { |q| q.try(:name) }.join('::')] + end + end + end + + module Model + module ClassMethods + def each_with_path(objects, &block) + Iterator.new(objects).each_with_path(&block) + end + end + end + end + end +end diff --git a/lib/body_tracking/project_patch.rb b/lib/body_tracking/project_patch.rb index 8bc992b..b59f240 100644 --- a/lib/body_tracking/project_patch.rb +++ b/lib/body_tracking/project_patch.rb @@ -1,6 +1,7 @@ module BodyTracking::ProjectPatch Project.class_eval do has_many :sources, dependent: :destroy + # TODO: includes(:parent) ? has_many :quantities, -> { order "lft" }, inverse_of: :project, dependent: :destroy has_many :formulas, through: :quantities has_many :units, dependent: :destroy