diff --git a/app/controllers/body_trackers_controller.rb b/app/controllers/body_trackers_controller.rb index 61e9ff6..6cd622b 100644 --- a/app/controllers/body_trackers_controller.rb +++ b/app/controllers/body_trackers_controller.rb @@ -1,4 +1,7 @@ -class BodyTrackersController < BodyTrackingPluginController +class BodyTrackersController < ApplicationController + layout 'body_tracking' + menu_item :body_trackers + before_action :find_project_by_project_id, only: [:index, :defaults] before_action :authorize @@ -43,10 +46,8 @@ class BodyTrackersController < BodyTrackingPluginController flash[:notice] += ", #{new_quantities_count > 0 ? new_quantities_count : "no" } new" \ " #{'quantity'.pluralize(new_quantities_count)}" - ncv = @project.nutrients_column_view - if ncv.quantities.count == 0 - ncv.quantities.append(@project.quantities.roots.first(6)) - ncv.save! + if @project.nutrient_quantities.empty? + @project.nutrient_quantities << @project.quantities.diet.roots.first(6) end # Sources diff --git a/app/controllers/body_tracking_plugin_controller.rb b/app/controllers/body_tracking_plugin_controller.rb deleted file mode 100644 index bb9732c..0000000 --- a/app/controllers/body_tracking_plugin_controller.rb +++ /dev/null @@ -1,17 +0,0 @@ -class BodyTrackingPluginController < ApplicationController - menu_item :body_trackers - layout 'body_tracking' - - private - - def find_quantity(id = :id) - @quantity = Quantity.find(params[id]) - @project = @quantity.project - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_quantity_by_quantity_id - find_quantity(:quantity_id) - end -end diff --git a/app/controllers/concerns/finders.rb b/app/controllers/concerns/finders.rb new file mode 100644 index 0000000..2937225 --- /dev/null +++ b/app/controllers/concerns/finders.rb @@ -0,0 +1,42 @@ +module Concerns::Finders + private + + def find_ingredient + @ingredient = Ingredient.find(params[:id]) + @project = @ingredient.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_measurement + @measurement = Measurement.find(params[:id]) + @project = @measurement.routine.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_measurement_routine + @routine = MeasurementRoutine.find(params[:id]) + @project = @routine.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_quantity(id = :id) + @quantity = Quantity.find(params[id]) + @project = @quantity.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_quantity_by_quantity_id + find_quantity(:quantity_id) + end + + def find_unit + @unit = Unit.find(params[:id]) + @project = @unit.project + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/ingredients_controller.rb b/app/controllers/ingredients_controller.rb index 3ec895d..b62fdf5 100644 --- a/app/controllers/ingredients_controller.rb +++ b/app/controllers/ingredients_controller.rb @@ -1,9 +1,13 @@ -class IngredientsController < BodyTrackingPluginController +class IngredientsController < ApplicationController require 'csv' + layout 'body_tracking' + menu_item :body_trackers helper :body_trackers helper_method :current_view + include Concerns::Finders + before_action :init_session_filters before_action :find_project_by_project_id, only: [:index, :new, :create, :nutrients, :filter, :import] @@ -63,7 +67,7 @@ class IngredientsController < BodyTrackingPluginController end def toggle_column - @project.nutrients_column_view.toggle_column!(@quantity) + @project.nutrient_columns.toggle!(@quantity) prepare_items render :index end @@ -201,15 +205,6 @@ class IngredientsController < BodyTrackingPluginController ) end - # :find_* methods are called before :authorize, - # @project is required for :authorize to succeed - def find_ingredient - @ingredient = Ingredient.find(params[:id]) - @project = @ingredient.project - rescue ActiveRecord::RecordNotFound - render_404 - end - def prepare_ingredients @ingredients, @formula_q = @project.ingredients .includes(:ref_unit, :source) @@ -217,7 +212,7 @@ class IngredientsController < BodyTrackingPluginController end def prepare_nutrients - @quantities = @project.nutrients_column_view.quantities.includes(:formula) + @quantities = @project.nutrient_quantities.includes(:formula) @ingredients, @requested_n, @extra_n, @formula_q = @project.ingredients .filter(session[:i_filters], @quantities) end diff --git a/app/controllers/measurements_controller.rb b/app/controllers/measurements_controller.rb index dfbfb3c..65ef520 100644 --- a/app/controllers/measurements_controller.rb +++ b/app/controllers/measurements_controller.rb @@ -1,11 +1,15 @@ -class MeasurementsController < BodyTrackingPluginController +class MeasurementsController < ApplicationController + layout 'body_tracking' + menu_item :body_trackers helper :body_trackers + include Concerns::Finders + before_action :init_session_filters before_action :find_project_by_project_id, only: [:index, :new, :create, :filter] before_action :find_quantity_by_quantity_id, only: [:toggle_column] - before_action :find_measurement, - only: [:edit, :update, :destroy, :retake, :readouts, :toggle_column] + before_action :find_measurement, only: [:edit, :update, :destroy, :retake] + before_action :find_measurement_routine, only: [:readouts, :toggle_column] before_action :authorize def index @@ -15,12 +19,18 @@ class MeasurementsController < BodyTrackingPluginController def new @measurement = @project.measurements.new + @measurement.build_routine @measurement.readouts.new end def create @measurement = @project.measurements.new(measurement_params) + @measurement.routine.project = @project if @measurement.save + if @measurement.routine.columns.empty? + @measurement.routine.quantities << @measurement.readouts.map(&:quantity).first(6) + end + flash[:notice] = 'Created new measurement' readouts_view? ? prepare_readouts : prepare_measurements else @@ -58,12 +68,12 @@ class MeasurementsController < BodyTrackingPluginController end def readouts - session[:m_filters][:scope] = {name: @measurement.name} + #session[:m_filters][:scope] = {routine: @routine} prepare_readouts end def toggle_column - @measurement.column_view.toggle_column!(@quantity) + @routine.columns.toggle!(@quantity) prepare_readouts render :index end @@ -82,8 +92,13 @@ class MeasurementsController < BodyTrackingPluginController def measurement_params params.require(:measurement).permit( - :name, + :notes, :source_id, + routine_attributes: + [ + :name, + :description + ], readouts_attributes: [ :id, @@ -95,30 +110,17 @@ class MeasurementsController < BodyTrackingPluginController ) end - # :find_* methods are called before :authorize, - # @project is required for :authorize to succeed - def find_measurement - @measurement = Measurement.find(params[:id]) - @project = @measurement.project - rescue ActiveRecord::RecordNotFound - render_404 - end - def prepare_measurements @measurements, @formula_q = @project.measurements - .includes(:source, :readouts) + .includes(:routine, :source, :readouts) .filter(session[:m_filters]) end def prepare_readouts - @scoping_measurement = @project.measurements.where(session[:m_filters][:scope]).first! - @quantities = @scoping_measurement.column_view.quantities.includes(:formula) - @measurements, @requested_r, @extra_r, @formula_q = @project.measurements - .includes(:source) + @quantities = @routine.quantities.includes(:formula) + @measurements, @requested_r, @extra_r, @formula_q = @routine.measurements + .includes(:routine, :source) .filter(session[:m_filters], @quantities) - rescue ActiveRecord::RecordNotFound - session[:m_filters][:scope] = {} - render_404 end def readouts_view? diff --git a/app/controllers/quantities_controller.rb b/app/controllers/quantities_controller.rb index 491fe53..85ca764 100644 --- a/app/controllers/quantities_controller.rb +++ b/app/controllers/quantities_controller.rb @@ -1,6 +1,10 @@ -class QuantitiesController < BodyTrackingPluginController +class QuantitiesController < ApplicationController + layout 'body_tracking' + menu_item :body_trackers helper :body_trackers + include Concerns::Finders + before_action :init_session_filters before_action :find_project_by_project_id, only: [:index, :new, :create, :filter, :parents] before_action :find_quantity, only: [:edit, :update, :destroy, :move, @@ -118,6 +122,6 @@ class QuantitiesController < BodyTrackingPluginController def prepare_quantities @quantities = @project.quantities.filter(@project, session[:q_filters]) - .includes(:column_views, :formula, :parent) + .includes(:columns, :formula, :parent) end end diff --git a/app/controllers/sources_controller.rb b/app/controllers/sources_controller.rb index 1a5195f..a96ca32 100644 --- a/app/controllers/sources_controller.rb +++ b/app/controllers/sources_controller.rb @@ -1,4 +1,7 @@ -class SourcesController < BodyTrackingPluginController +class SourcesController < ApplicationController + layout 'body_tracking' + menu_item :body_trackers + before_action :find_project_by_project_id, only: [:index, :create] before_action :find_source, only: [:destroy] before_action :authorize diff --git a/app/controllers/units_controller.rb b/app/controllers/units_controller.rb index 65509cf..4affd4c 100644 --- a/app/controllers/units_controller.rb +++ b/app/controllers/units_controller.rb @@ -1,4 +1,9 @@ -class UnitsController < BodyTrackingPluginController +class UnitsController < ApplicationController + layout 'body_tracking' + menu_item :body_trackers + + include Concerns::Finders + before_action :find_project_by_project_id, only: [:index, :create] before_action :find_unit, only: [:destroy] before_action :authorize @@ -34,13 +39,4 @@ class UnitsController < BodyTrackingPluginController :shortname ) end - - # :find_* methods are called before :authorize, - # @project is required for :authorize to succeed - def find_unit - @unit = Unit.find(params[:id]) - @project = @unit.project - rescue ActiveRecord::RecordNotFound - render_404 - end end diff --git a/app/helpers/ingredients_helper.rb b/app/helpers/ingredients_helper.rb index 8107d62..24ad9ef 100644 --- a/app/helpers/ingredients_helper.rb +++ b/app/helpers/ingredients_helper.rb @@ -7,9 +7,9 @@ module IngredientsHelper def toggle_column_options disabled = [] - enabled_columns = @project.nutrients_column_view.quantities.to_a + enabled_quantities = @project.nutrient_quantities.to_a options = nested_set_options(@project.quantities.diet) do |q| - disabled << q.id if enabled_columns.include?(q) + disabled << q.id if enabled_quantities.include?(q) raw("#{' ' * q.level}#{q.name}") end options_for_select(options, disabled: disabled) diff --git a/app/helpers/measurements_helper.rb b/app/helpers/measurements_helper.rb index bbe6530..2be63b2 100644 --- a/app/helpers/measurements_helper.rb +++ b/app/helpers/measurements_helper.rb @@ -11,9 +11,9 @@ module MeasurementsHelper def toggle_column_options disabled = [] - enabled_columns = @scoping_measurement.column_view.quantities + enabled_quantities = @routine.quantities.to_a options = nested_set_options(@project.quantities.measurement) do |q| - disabled << q.id if enabled_columns.include?(q) + disabled << q.id if enabled_quantities.include?(q) raw("#{' ' * q.level}#{q.name}") end options_for_select(options, disabled: disabled) diff --git a/app/models/column.rb b/app/models/column.rb new file mode 100644 index 0000000..9b2736c --- /dev/null +++ b/app/models/column.rb @@ -0,0 +1,4 @@ +class Column < ActiveRecord::Base + belongs_to :column_view, polymorphic: true + belongs_to :quantity +end diff --git a/app/models/column_view.rb b/app/models/column_view.rb deleted file mode 100644 index 7a1f175..0000000 --- a/app/models/column_view.rb +++ /dev/null @@ -1,19 +0,0 @@ -class ColumnView < ActiveRecord::Base - enum domain: Quantity.domains - - belongs_to :project, required: true - has_and_belongs_to_many :quantities, -> { order "lft" } - - validates :name, presence: true, uniqueness: {scope: :domain} - validates :domain, inclusion: {in: domains.keys} - - # TODO: enforce column_view - quantity 'domain' identity - def toggle_column!(q) - column = self.quantities.find(q.id) - self.quantities.destroy(column) - rescue ActiveRecord::RecordNotFound - # Cannot 'create' association, as ColumnView (parent) may not be saved yet - self.quantities.append(q) - self.save! - end -end diff --git a/app/models/measurement.rb b/app/models/measurement.rb index 800b14b..7ea473e 100644 --- a/app/models/measurement.rb +++ b/app/models/measurement.rb @@ -1,5 +1,11 @@ class Measurement < ActiveRecord::Base - belongs_to :project, required: true + belongs_to :routine, required: true, inverse_of: :measurements, + class_name: 'MeasurementRoutine' + accepts_nested_attributes_for :routine, allow_destroy: true, reject_if: proc { |attrs| + attrs['name'].blank? + } + after_destroy { self.routine.destroy if self.routine.measurements.empty? } + belongs_to :source, required: false has_many :readouts, inverse_of: :measurement, dependent: :destroy, validate: true @@ -17,7 +23,6 @@ class Measurement < ActiveRecord::Base end end - validates :name, presence: true validates :taken_at, presence: true after_initialize do @@ -26,21 +31,6 @@ class Measurement < ActiveRecord::Base end end - after_create :seed_column_view, if: -> {self.column_view.quantities.count == 0} - after_save :cleanup_column_view, if: :name_changed? - - # Destroy ColumnView after last Measurement destruction - after_destroy do - unless self.project.measurements.exists?(name: self.name) - self.column_view.destroy! - end - end - - def column_view - self.project.column_views - .find_or_create_by(name: self.name, domain: ColumnView.domains[:measurement]) - end - def taken_at_date self.taken_at.getlocal end @@ -54,27 +44,4 @@ class Measurement < ActiveRecord::Base def taken_at_time=(value) self.taken_at = Time.parse(value, self.taken_at) end - - private - - def seed_column_view - quantities = self.project.quantities.joins(:readouts).includes(readouts: [:measurement]) - .where(measurements: {name: self.name}).first(6) - self.column_view.quantities.append(quantities) - self.column_view.save! - end - - # Copy/rename ColumnView on Measurement rename - def cleanup_column_view - old_column_view = self.project.column_views - .find_by(name: self.name_was, domain: ColumnView.domains[:measurement]) - return unless old_column_view - - if self.project.measurements.exists?(name: self.name_was) - self.column_view.quantities.append(old_column_view.quantities) - self.column_view.save! - else - old_column_view.update!(name: self.name) - end - end end diff --git a/app/models/measurement_routine.rb b/app/models/measurement_routine.rb new file mode 100644 index 0000000..85cf4c2 --- /dev/null +++ b/app/models/measurement_routine.rb @@ -0,0 +1,11 @@ +class MeasurementRoutine < ActiveRecord::Base + belongs_to :project, required: true + has_many :measurements, -> { order "taken_at DESC" }, inverse_of: :routine, + foreign_key: 'routine_id', dependent: :restrict_with_error, + extend: BodyTracking::ItemsWithQuantities + has_many :columns, as: :column_view, dependent: :destroy, + extend: BodyTracking::TogglableColumns + has_many :quantities, -> { order "lft" }, through: :columns + + validates :name, presence: true, uniqueness: {scope: :project_id} +end diff --git a/app/models/quantity.rb b/app/models/quantity.rb index e01556a..83d9041 100644 --- a/app/models/quantity.rb +++ b/app/models/quantity.rb @@ -5,16 +5,11 @@ class Quantity < ActiveRecord::Base exercise: 2 } - # Has to go before any 'dependent:' association - before_destroy do - # FIXME: disallow destruction if any object depends on this quantity - nil - end - acts_as_nested_set dependent: :destroy, scope: :project belongs_to :project, required: false - has_and_belongs_to_many :column_views - has_many :readouts + has_many :nutrients, dependent: :restrict_with_error + has_many :readouts, dependent: :restrict_with_error + has_many :columns, dependent: :destroy has_one :formula, inverse_of: :quantity, dependent: :destroy, validate: true accepts_nested_attributes_for :formula, allow_destroy: true, reject_if: proc { |attrs| diff --git a/app/views/measurements/_form.html.erb b/app/views/measurements/_form.html.erb index 6d3a3ad..7f8b8aa 100644 --- a/app/views/measurements/_form.html.erb +++ b/app/views/measurements/_form.html.erb @@ -1,17 +1,29 @@ <%= error_messages_for @measurement %> -
<%= f.select :source_id, source_options, - {required: false, include_blank: t('.null_source')} %>
-<%= f.text_field :name, size: 40, required: true %>
-+
+ +