1
0

Added Goal model and preliminary Targets index

This commit is contained in:
cryptogopher
2020-06-25 03:56:49 +02:00
parent 8240e5e868
commit 1dd2e2b596
18 changed files with 149 additions and 14 deletions

View File

@@ -0,0 +1,24 @@
class TargetsController < ApplicationController
layout 'body_tracking'
menu_item :body_trackers
helper :body_trackers
include Concerns::Finders
before_action :find_project_by_project_id, only: [:index]
def index
prepare_targets
end
def new
@target = @project.targets.new
@target.arity.times { @target.thresholds.new }
end
private
def prepare_targets
@targets = @project.targets.includes(:item, :thresholds)
end
end

6
app/models/goal.rb Normal file
View File

@@ -0,0 +1,6 @@
class Goal < ActiveRecord::Base
belongs_to :project, required: true
has_many :targets, inverse_of: :goal, dependent: :destroy
validates :name, presence: true, uniqueness: {scope: :project_id}
end

View File

@@ -2,7 +2,7 @@ class Ingredient < ActiveRecord::Base
belongs_to :composition, inverse_of: :ingredients, polymorphic: true, required: true
belongs_to :food, required: true
belongs_to :part_of, required: false
has_many :nutrients, through: :food, source: :nutrients
has_many :nutrients, through: :food
DOMAIN = :diet
alias_attribute :subitems, :nutrients

View File

@@ -1,6 +1,8 @@
class Nutrient < QuantityValue
belongs_to :food, foreign_key: 'registry_id', foreign_type: 'registry_type',
inverse_of: :nutrients, polymorphic: true, required: true
# Need to specify polymorphic association so :registry_type gets written (see
# QuantityValue for explanation why it's needed)
belongs_to :food, inverse_of: :nutrients, polymorphic: true, required: true,
foreign_key: 'registry_id', foreign_type: 'registry_type'
# Uniqueness NOT validated here, see Value for explanation
#validates :quantity, uniqueness: {scope: :food_id}

View File

@@ -9,6 +9,7 @@ class Quantity < ActiveRecord::Base
belongs_to :project, inverse_of: :quantities, required: false
has_many :nutrients, dependent: :restrict_with_error
has_many :readouts, dependent: :restrict_with_error
has_many :thresholds, dependent: :restrict_with_error
has_many :values, class_name: 'QuantityValue', dependent: :restrict_with_error
has_many :exposures, dependent: :destroy

View File

@@ -1,5 +1,9 @@
class QuantityValue < ActiveRecord::Base
# Requirement validation for :registry left to subclasses
# Polymorphic registry (including :registry_type) is required - despite 1:1
# mapping between Nutrient:Food, Readout:Measurement, Threshold:Target ... -
# to allow for accessing registry item without knowing QuantityValue (subitem)
# type, e.g. qv.registry.completed_at
belongs_to :registry, polymorphic: true
belongs_to :quantity, required: true
belongs_to :unit, required: true

View File

@@ -1,6 +1,8 @@
class Readout < QuantityValue
belongs_to :measurement, foreign_key: 'registry_id', foreign_type: 'registry_type',
inverse_of: :readouts, polymorphic: true, required: true
# Need to specify polymorphic association so :registry_type gets written (see
# QuantityValue for explanation why it's needed)
belongs_to :measurement, inverse_of: :readouts, polymorphic: true, required: true,
foreign_key: 'registry_id', foreign_type: 'registry_type'
# Uniqueness NOT validated here, see Value for explanation
#validates :quantity, uniqueness: {scope: [:measurement_id, :unit_id]}

View File

@@ -10,5 +10,16 @@ class Target < ActiveRecord::Base
# TODO: validate thresholds count according to condition type
validates :condition, inclusion: {in: [:<, :<=, :>, :>=, :==]}
validates :scope, inclusion: {in: [:day], if: -> { thresholds.first.domain == :diet }}
validates :effective_from, presence: {unless: goal?}, absence: {if: goal?}
validates :effective_from, presence: {unless: -> { goal.present? }},
absence: {if: -> { goal.present? }}
after_initialize do
if new_record?
self.condition = :<
end
end
def arity
BigDecimal.method(condition).arity
end
end

View File

@@ -1,6 +1,8 @@
class Threshold < QuantityValue
belongs_to :target, foreign_key: 'registry_id', foreign_type: 'foreign_type',
inverse_of: :thresholds, polymorphic: true, required: true
# Need to specify polymorphic association so :registry_type gets written (see
# QuantityValue for explanation why it's needed)
belongs_to :target, inverse_of: :thresholds, polymorphic: true, required: true,
foreign_key: 'registry_id', foreign_type: 'registry_type'
validates :value, numericality: true
end

View File

@@ -1,6 +1,12 @@
<h3><%= t ".heading_body_trackers" %></h3>
<ul>
<li><%= link_to t(".link_summary"), project_body_trackers_path(@project) %></li>
<li>
<%= link_to t(".link_targets"), project_targets_path(@project) %>
/
<%#= link_to t(".link_goals"), nutrients_project_foods_path(@project) %>
Goals
</li>
</ul>
<h3><%= t ".heading_measurements" %></h3>

View File

@@ -0,0 +1,5 @@
<% if User.current.allowed_to?(:manage_common, @project) %>
<%= link_to t(".link_new_target"),
new_project_target_path(@project, @view_params),
{remote: true, class: 'icon icon-add'} %>
<% end %>

View File

@@ -0,0 +1,34 @@
<% if @targets.any? { |t| t.persisted? } %>
<table class="list">
<thead>
<tr>
<th style="width:5%"><%= l(:field_taken_at_date) %></th>
<th><%= l(:field_name) %></th>
<th><%= l(:field_notes) %></th>
<th><%= l(:field_source) %></th>
<th style="width:5%"><%= l(:field_action) %></th>
</tr>
</thead>
<tbody>
<% @measurements.each do |m| %>
<% next if m.new_record? %>
<tr id="measurement-<%= m.id %>" class="primary measurement">
<td class="date unwrappable"><%= format_datetime(m) %></td>
<td class="name">
<div style="float:left;">
<%= link_to m.routine.name, readouts_measurement_routine_path(m.routine) %>
</div>
<div style="float:right;">
<small><%= " (#{pluralize(m.readouts.size, 'readout')})" %></small>
</div>
</td>
<td class="notes ellipsible"><%= m.notes %></td>
<td class="source"><%= m.source.name if m.source.present? %></td>
<td class="action unwrappable"><%= action_links(m) %></td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>

View File

@@ -0,0 +1,11 @@
<div class="contextual">
<%= render partial: 'targets/contextual' %>
</div>
<div id="new-target">
</div>
<h2><%= t ".heading" %></h2>
<div id='targets'>
<%= render partial: 'targets/index' %>
</div>