Added MealsController#new and form autocomplete for Food
Renamed QuantityColumn -> Exposure
This commit is contained in:
parent
8e8160c41a
commit
e78803e474
@ -9,7 +9,7 @@ class FoodsController < ApplicationController
|
|||||||
|
|
||||||
before_action :init_session_filters
|
before_action :init_session_filters
|
||||||
before_action :find_project_by_project_id,
|
before_action :find_project_by_project_id,
|
||||||
only: [:index, :new, :create, :nutrients, :filter, :import]
|
only: [:index, :new, :create, :nutrients, :filter, :autocomplete, :import]
|
||||||
before_action :find_quantity_by_quantity_id, only: [:toggle_column]
|
before_action :find_quantity_by_quantity_id, only: [:toggle_column]
|
||||||
before_action :find_food, only: [:edit, :update, :destroy, :toggle]
|
before_action :find_food, only: [:edit, :update, :destroy, :toggle]
|
||||||
before_action :authorize
|
before_action :authorize
|
||||||
@ -63,7 +63,7 @@ class FoodsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def toggle_column
|
def toggle_column
|
||||||
@project.nutrient_columns.toggle!(@quantity)
|
@project.nutrient_exposures.toggle!(@quantity)
|
||||||
prepare_nutrients
|
prepare_nutrients
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -73,6 +73,10 @@ class FoodsController < ApplicationController
|
|||||||
render :index
|
render :index
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def autocomplete
|
||||||
|
@foods = @project.foods.where("name LIKE ?", "%#{params[:term]}%")
|
||||||
|
end
|
||||||
|
|
||||||
def import
|
def import
|
||||||
warnings = []
|
warnings = []
|
||||||
|
|
||||||
|
@ -13,6 +13,17 @@ class MealsController < ApplicationController
|
|||||||
prepare_meals
|
prepare_meals
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@meal = @project.meals.new
|
||||||
|
@meal.ingredients.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def prepare_meals
|
def prepare_meals
|
||||||
|
@ -33,7 +33,7 @@ class MeasurementsController < ApplicationController
|
|||||||
@measurement.routine.project = @project
|
@measurement.routine.project = @project
|
||||||
@routine = @measurement.routine
|
@routine = @measurement.routine
|
||||||
if @measurement.save
|
if @measurement.save
|
||||||
if @routine.columns.empty?
|
if @routine.exposures.empty?
|
||||||
@routine.quantities << @measurement.readouts.map(&:quantity).first(6)
|
@routine.quantities << @measurement.readouts.map(&:quantity).first(6)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ class MeasurementsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def toggle_column
|
def toggle_column
|
||||||
@routine.columns.toggle!(@quantity)
|
@routine.exposures.toggle!(@quantity)
|
||||||
prepare_readouts
|
prepare_readouts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -122,6 +122,6 @@ class QuantitiesController < ApplicationController
|
|||||||
|
|
||||||
def prepare_quantities
|
def prepare_quantities
|
||||||
@quantities = @project.quantities.filter(@project, session[:q_filters])
|
@quantities = @project.quantities.filter(@project, session[:q_filters])
|
||||||
.includes(:columns, :formula, :parent)
|
.includes(:exposures, :formula, :parent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
5
app/helpers/meals_helper.rb
Normal file
5
app/helpers/meals_helper.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module MealsHelper
|
||||||
|
def action_links(m)
|
||||||
|
delete_link(meal_path(m), {remote: true, data: {}}) if m.persisted?
|
||||||
|
end
|
||||||
|
end
|
4
app/models/exposure.rb
Normal file
4
app/models/exposure.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class Exposure < ActiveRecord::Base
|
||||||
|
belongs_to :view, polymorphic: true
|
||||||
|
belongs_to :quantity
|
||||||
|
end
|
@ -34,6 +34,9 @@ class Food < ActiveRecord::Base
|
|||||||
validates :ref_amount, numericality: {greater_than: 0}
|
validates :ref_amount, numericality: {greater_than: 0}
|
||||||
validates :group, inclusion: {in: groups.keys}
|
validates :group, inclusion: {in: groups.keys}
|
||||||
|
|
||||||
|
scope :visible, -> { where(hidden: false) }
|
||||||
|
scope :hidden, -> { where(hidden: true) }
|
||||||
|
|
||||||
after_initialize do
|
after_initialize do
|
||||||
if new_record?
|
if new_record?
|
||||||
self.ref_amount ||= 100
|
self.ref_amount ||= 100
|
||||||
|
8
app/models/ingredient.rb
Normal file
8
app/models/ingredient.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class Ingredient < ActiveRecord::Base
|
||||||
|
belongs_to :composition, inverse_of: :ingredients, required: true
|
||||||
|
belongs_to :food, required: true
|
||||||
|
belongs_to :part_of, required: false
|
||||||
|
|
||||||
|
validates :ready_ratio, numericality: {greater_than_or_equal_to: 0.0}
|
||||||
|
validates :amount, numericality: {greater_than_or_equal_to: 0.0}
|
||||||
|
end
|
@ -1,6 +1,19 @@
|
|||||||
class Meal < ActiveRecord::Base
|
class Meal < ActiveRecord::Base
|
||||||
belongs_to :project, required: true
|
belongs_to :project, required: true
|
||||||
|
|
||||||
has_many :ingredients, as: :composition, dependent: :destroy
|
has_many :ingredients, as: :composition, dependent: :destroy, validate: true
|
||||||
has_many :foods, through: :ingredients
|
has_many :foods, through: :ingredients
|
||||||
|
validates :ingredients, presence: true
|
||||||
|
accepts_nested_attributes_for :ingredients, allow_destroy: true, reject_if: proc { |attrs|
|
||||||
|
attrs['food_id'].blank? && attrs['amount'].blank?
|
||||||
|
}
|
||||||
|
# Ingredient food_id + part_of_id uniqueness validation. Cannot be effectively
|
||||||
|
# checked on Ingredient model level.
|
||||||
|
validate do
|
||||||
|
ingredients = self.ingredients.reject { |i| i.marked_for_destruction? }
|
||||||
|
.map { |i| [i.food_id, i.part_of_id] }
|
||||||
|
if ingredients.length != ingredients.uniq.length
|
||||||
|
errors.add(:ingredients, :duplicated_ingredient)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,9 +3,9 @@ class MeasurementRoutine < ActiveRecord::Base
|
|||||||
has_many :measurements, -> { order "taken_at DESC" }, inverse_of: :routine,
|
has_many :measurements, -> { order "taken_at DESC" }, inverse_of: :routine,
|
||||||
foreign_key: 'routine_id', dependent: :restrict_with_error,
|
foreign_key: 'routine_id', dependent: :restrict_with_error,
|
||||||
extend: BodyTracking::ItemsWithQuantities
|
extend: BodyTracking::ItemsWithQuantities
|
||||||
has_many :readout_columns, as: :column_view, dependent: :destroy,
|
has_many :readout_exposures, as: :view, dependent: :destroy,
|
||||||
class_name: 'QuantityColumn', extend: BodyTracking::TogglableColumns
|
class_name: 'Exposure', extend: BodyTracking::TogglableColumns
|
||||||
has_many :quantities, -> { order "lft" }, through: :readout_columns
|
has_many :quantities, -> { order "lft" }, through: :readout_exposures
|
||||||
|
|
||||||
validates :name, presence: true, uniqueness: {scope: :project_id}
|
validates :name, presence: true, uniqueness: {scope: :project_id}
|
||||||
end
|
end
|
||||||
|
@ -9,7 +9,7 @@ class Quantity < ActiveRecord::Base
|
|||||||
belongs_to :project, required: false
|
belongs_to :project, required: false
|
||||||
has_many :nutrients, dependent: :restrict_with_error
|
has_many :nutrients, dependent: :restrict_with_error
|
||||||
has_many :readouts, dependent: :restrict_with_error
|
has_many :readouts, dependent: :restrict_with_error
|
||||||
has_many :columns, dependent: :destroy
|
has_many :exposures, dependent: :destroy
|
||||||
|
|
||||||
has_one :formula, inverse_of: :quantity, dependent: :destroy, validate: true
|
has_one :formula, inverse_of: :quantity, dependent: :destroy, validate: true
|
||||||
accepts_nested_attributes_for :formula, allow_destroy: true, reject_if: proc { |attrs|
|
accepts_nested_attributes_for :formula, allow_destroy: true, reject_if: proc { |attrs|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
class QuantityColumn < ActiveRecord::Base
|
|
||||||
belongs_to :column_view, polymorphic: true
|
|
||||||
belongs_to :quantity
|
|
||||||
end
|
|
1
app/views/foods/autocomplete.json.erb
Normal file
1
app/views/foods/autocomplete.json.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<%= raw @foods.map { |f| {id: f.id, label: f.name, value: f.name} }.to_json %>
|
4
app/views/meals/_contextual.html.erb
Normal file
4
app/views/meals/_contextual.html.erb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<% if User.current.allowed_to?(:manage_common, @project) %>
|
||||||
|
<%= link_to t(".link_new_meal"), new_project_meal_path(@project),
|
||||||
|
{remote: true, class: 'icon icon-add'} %>
|
||||||
|
<% end %>
|
79
app/views/meals/_form.html.erb
Normal file
79
app/views/meals/_form.html.erb
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<%= error_messages_for @meal %>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<div class="tabular">
|
||||||
|
<% @meal.ingredients.each_with_index do |i, index| %>
|
||||||
|
<table style="width:95%;">
|
||||||
|
<%= f.fields_for 'ingredients_attributes', i, index: '' do |ff| %>
|
||||||
|
<tr class="ingredient">
|
||||||
|
<td style="width:90%;">
|
||||||
|
<p>
|
||||||
|
<%= ff.hidden_field :id %>
|
||||||
|
<%= ff.text_field :food_id, {class: "autocomplete food-autocomplete",
|
||||||
|
style: "width: 80%;",
|
||||||
|
required: true,
|
||||||
|
label: (index > 0 ? '' : :field_ingredients)} %>
|
||||||
|
<%= ff.number_field :amount, {style: "width: 8%", step: :any, label: ''} %>
|
||||||
|
<%= i.food.ref_unit.shortname if i.food %>
|
||||||
|
<%= ff.hidden_field :_destroy %>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td style="width:10%;">
|
||||||
|
<%= link_to t(".button_delete_ingredient"), '#',
|
||||||
|
class: 'icon icon-del',
|
||||||
|
style: (@meal.ingredients.length > 1 ? "" : "display:none"),
|
||||||
|
onclick: "deleteIngredient(); return false;" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<%= link_to t(".button_new_ingredient"), '#', class: 'icon icon-add',
|
||||||
|
onclick: 'newIngredient(); return false;' %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= javascript_tag do %>
|
||||||
|
function autocompleteFood($row) {
|
||||||
|
$row.find('.food-autocomplete').autocomplete({
|
||||||
|
source: '<%= j autocomplete_project_foods_path(@project) %>',
|
||||||
|
minLength: 2,
|
||||||
|
position: {collision: 'flipfit'},
|
||||||
|
search: function(event){
|
||||||
|
$(event.target).closest('.food-autocomplete').addClass('ajax-loading');
|
||||||
|
},
|
||||||
|
response: function(event){
|
||||||
|
$(event.target).closest('.food-autocomplete').removeClass('ajax-loading');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
autocompleteFood($('tr.ingredient:visible'));
|
||||||
|
|
||||||
|
function newIngredient() {
|
||||||
|
var form = $(event.target).closest('form');
|
||||||
|
var row = form.find('tr.ingredient:visible:last');
|
||||||
|
var new_row = row.clone().insertAfter(row);
|
||||||
|
new_row.find('input[id$=__id], input[id$=__amount], input[id$=__food_id]').val('');
|
||||||
|
new_row.find('input[id$=__destroy]').val('');
|
||||||
|
new_row.find('label:first').hide();
|
||||||
|
form.find('tr.ingredient:visible a.icon-del').show();
|
||||||
|
autocompleteFood(new_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteIngredient() {
|
||||||
|
var form = $(event.target).closest('form');
|
||||||
|
var row = $(event.target).closest('tr.ingredient');
|
||||||
|
if (row.find('input[id$=__id]').val()) {
|
||||||
|
row.hide();
|
||||||
|
row.find('input[id$=__destroy]').val('1');
|
||||||
|
} else {
|
||||||
|
row.remove();
|
||||||
|
}
|
||||||
|
form.find('tr.ingredient:visible:first label:first').show();
|
||||||
|
if (form.find('tr.ingredient:visible').length <= 1) {
|
||||||
|
form.find('tr.ingredient:visible a.icon-del').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<% end %>
|
21
app/views/meals/_index.html.erb
Normal file
21
app/views/meals/_index.html.erb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<% if @meals.any? { |m| m.persisted? } %>
|
||||||
|
<table id="meals" class="odd-even">
|
||||||
|
<tbody>
|
||||||
|
<% @meals.group_by { |m| m.eaten_at.date if m.eaten_at }.each do |d, meals| %>
|
||||||
|
<% meals.each_with_index do |m, index| %>
|
||||||
|
<tr id="meal-<%= m.new_record? ? 'new' : m.id %>" class="primary meal">
|
||||||
|
<td class="name">
|
||||||
|
<h4>
|
||||||
|
<%= "#{t '.label_meal'}" %><%= index ? " ##{index+1}" : " (new)" %>
|
||||||
|
<%= ", #{m.eaten_at.time}" if m.eaten_at %>
|
||||||
|
</h4>
|
||||||
|
</td>
|
||||||
|
<td class="action unwrappable" style="width:5%"><%= action_links(m) %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% else %>
|
||||||
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
|
<% end %>
|
18
app/views/meals/_new_form.html.erb
Normal file
18
app/views/meals/_new_form.html.erb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<h2><%= t ".heading_new_meal" %></h2>
|
||||||
|
|
||||||
|
<%= labelled_form_for @meal,
|
||||||
|
url: project_meals_path(@project),
|
||||||
|
remote: true,
|
||||||
|
html: {id: 'new-meal-form', name: 'new-meal-form'} do |f| %>
|
||||||
|
|
||||||
|
<%= render partial: 'meals/form', locals: {f: f} %>
|
||||||
|
|
||||||
|
<div class="tabular">
|
||||||
|
<p>
|
||||||
|
<%= submit_tag l(:button_create) %>
|
||||||
|
<%= link_to l(:button_cancel), "#",
|
||||||
|
onclick: '$("#new-meal").empty(); return false;' %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<hr>
|
0
app/views/meals/_show.html.erb
Normal file
0
app/views/meals/_show.html.erb
Normal file
11
app/views/meals/index.html.erb
Normal file
11
app/views/meals/index.html.erb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<div class="contextual">
|
||||||
|
<%= render partial: 'meals/contextual' %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="new-meal">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%= t ".heading" %></h2>
|
||||||
|
<div id='meals'>
|
||||||
|
<%= render partial: 'meals/index' %>
|
||||||
|
</div>
|
2
app/views/meals/new.js.erb
Normal file
2
app/views/meals/new.js.erb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
$('#new-meal')
|
||||||
|
.html('<%= j render partial: 'meals/new_form' %>');
|
@ -18,12 +18,12 @@
|
|||||||
<%
|
<%
|
||||||
next if q.new_record?
|
next if q.new_record?
|
||||||
quantity_class = "quantity"
|
quantity_class = "quantity"
|
||||||
quantity_class += " primary" unless q.columns.empty?
|
quantity_class += " primary" unless q.exposures.empty?
|
||||||
quantity_class += " project idnt idnt-#{level+1}"
|
quantity_class += " project idnt idnt-#{level+1}"
|
||||||
%>
|
%>
|
||||||
<tr id="quantity-<%= q.id %>" class="<%= quantity_class %>">
|
<tr id="quantity-<%= q.id %>" class="<%= quantity_class %>">
|
||||||
<td class="name unwrappable">
|
<td class="name unwrappable">
|
||||||
<div class="icon <%= q.columns.empty? ? 'icon-fav-off' : 'icon-fav' %>">
|
<div class="icon <%= q.exposures.empty? ? 'icon-fav-off' : 'icon-fav' %>">
|
||||||
<%= q.name %>
|
<%= q.name %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -32,10 +32,13 @@ fieldset#filters table.filter td {padding-left: 8px;}
|
|||||||
.icon-bullet-open { background-image: url(../../../images/bullet_toggle_minus.png); }
|
.icon-bullet-open { background-image: url(../../../images/bullet_toggle_minus.png); }
|
||||||
.icon-bullet-closed { background-image: url(../../../images/bullet_toggle_plus.png); }
|
.icon-bullet-closed { background-image: url(../../../images/bullet_toggle_plus.png); }
|
||||||
|
|
||||||
|
.ui-state-focus, .ui-widget-content .ui-state-focus { font-weight: normal; }
|
||||||
|
|
||||||
|
|
||||||
input[type=number] {
|
input[type=number] {
|
||||||
-moz-appearance:textfield;
|
-moz-appearance:textfield;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
height: 1.5em;
|
||||||
}
|
}
|
||||||
input[type=date], input[type=time], input[type=number], textarea {
|
input[type=date], input[type=time], input[type=number], textarea {
|
||||||
border:1px solid #d7d7d7;
|
border:1px solid #d7d7d7;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# English strings go here for Rails i18n
|
# English strings go here for Rails i18n
|
||||||
en:
|
en:
|
||||||
body_trackers_menu_caption: 'Body trackers'
|
body_trackers_menu_caption: 'Body trackers'
|
||||||
|
field_ingredients: 'Ingredients'
|
||||||
field_measurement_routine: 'Routine'
|
field_measurement_routine: 'Routine'
|
||||||
field_readouts: 'Readouts'
|
field_readouts: 'Readouts'
|
||||||
field_taken_at_date: 'Taken at'
|
field_taken_at_date: 'Taken at'
|
||||||
@ -22,10 +23,14 @@ en:
|
|||||||
activerecord:
|
activerecord:
|
||||||
errors:
|
errors:
|
||||||
models:
|
models:
|
||||||
|
meal:
|
||||||
|
attributes:
|
||||||
|
ingredients:
|
||||||
|
duplicated_ingredient: 'each ingredient can only be specified once per meal'
|
||||||
measurement:
|
measurement:
|
||||||
attributes:
|
attributes:
|
||||||
readouts:
|
readouts:
|
||||||
duplicated_quantity_unit_pair: 'you can define each quantity/unit pair only
|
duplicated_quantity_unit_pair: 'each quantity+unit pair can only be specified
|
||||||
once per measurement'
|
once per measurement'
|
||||||
food:
|
food:
|
||||||
attributes:
|
attributes:
|
||||||
@ -55,15 +60,27 @@ en:
|
|||||||
heading_diet: 'Diet'
|
heading_diet: 'Diet'
|
||||||
heading_common: 'Common'
|
heading_common: 'Common'
|
||||||
link_summary: 'Summary'
|
link_summary: 'Summary'
|
||||||
link_meals: 'Meals'
|
|
||||||
link_measurements: 'Measurements'
|
link_measurements: 'Measurements'
|
||||||
|
link_meals: 'Meals'
|
||||||
link_foods: 'Foods'
|
link_foods: 'Foods'
|
||||||
link_nutrients: 'Nutrients'
|
link_nutrients: 'Nutrients'
|
||||||
link_sources: 'Data sources'
|
link_sources: 'Data sources'
|
||||||
link_quantities: 'Quantities'
|
link_quantities: 'Quantities'
|
||||||
link_units: 'Units'
|
link_units: 'Units'
|
||||||
link_defaults: 'Load defaults'
|
link_defaults: 'Load defaults'
|
||||||
confirm_defaults: 'This will load default quantities and units. Continue?'
|
confirm_defaults: 'This will load default data sources, quantities and units. Continue?'
|
||||||
|
meals:
|
||||||
|
contextual:
|
||||||
|
link_new_meal: 'New meal'
|
||||||
|
form:
|
||||||
|
button_new_ingredient: 'Add ingredient'
|
||||||
|
button_delete_ingredient: 'Delete'
|
||||||
|
new_form:
|
||||||
|
heading_new_meal: 'New meal'
|
||||||
|
index:
|
||||||
|
heading: 'Meals'
|
||||||
|
show:
|
||||||
|
label_meal: 'Meal'
|
||||||
measurements:
|
measurements:
|
||||||
contextual:
|
contextual:
|
||||||
link_new_measurement: 'New measurement'
|
link_new_measurement: 'New measurement'
|
||||||
|
@ -28,6 +28,7 @@ resources :projects, shallow: true do
|
|||||||
get 'nutrients'
|
get 'nutrients'
|
||||||
post 'toggle_column'
|
post 'toggle_column'
|
||||||
get 'filter'
|
get 'filter'
|
||||||
|
get 'autocomplete'
|
||||||
post 'import'
|
post 'import'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,8 +27,8 @@ class CreateSchema < ActiveRecord::Migration
|
|||||||
t.timestamps null: false
|
t.timestamps null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table :quantity_columns do |t|
|
create_table :exposures do |t|
|
||||||
t.references :column_view, polymorphic: true
|
t.references :view, polymorphic: true
|
||||||
t.references :quantity
|
t.references :quantity
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -94,9 +94,9 @@ class CreateSchema < ActiveRecord::Migration
|
|||||||
create_table :ingredients do |t|
|
create_table :ingredients do |t|
|
||||||
t.references :composition, polymorphic: true
|
t.references :composition, polymorphic: true
|
||||||
t.references :food
|
t.references :food
|
||||||
|
t.decimal :amount, precision: 12, scale: 6
|
||||||
t.references :part_of
|
t.references :part_of
|
||||||
t.decimal :ready_ratio, precision: 12, scale: 6
|
t.decimal :ready_ratio, precision: 12, scale: 6
|
||||||
t.decimal :amount, precision: 12, scale: 6
|
|
||||||
t.timestamps null: false
|
t.timestamps null: false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
2
init.rb
2
init.rb
@ -16,7 +16,7 @@ Redmine::Plugin.register :body_tracking do
|
|||||||
meals: [:index],
|
meals: [:index],
|
||||||
measurement_routines: [:show],
|
measurement_routines: [:show],
|
||||||
measurements: [:index, :readouts, :filter],
|
measurements: [:index, :readouts, :filter],
|
||||||
foods: [:index, :nutrients, :filter],
|
foods: [:index, :nutrients, :filter, :autocomplete],
|
||||||
sources: [:index],
|
sources: [:index],
|
||||||
quantities: [:index, :parents, :filter],
|
quantities: [:index, :parents, :filter],
|
||||||
units: [:index],
|
units: [:index],
|
||||||
|
@ -12,9 +12,9 @@ module BodyTracking::ProjectPatch
|
|||||||
has_many :quantities, -> { order "lft" }, dependent: :destroy
|
has_many :quantities, -> { order "lft" }, dependent: :destroy
|
||||||
has_many :units, dependent: :destroy
|
has_many :units, dependent: :destroy
|
||||||
|
|
||||||
has_many :nutrient_columns, as: :column_view, dependent: :destroy,
|
has_many :nutrient_exposures, as: :view, dependent: :destroy,
|
||||||
class_name: 'QuantityColumn', extend: BodyTracking::TogglableColumns
|
class_name: 'Exposure', extend: BodyTracking::TogglableColumns
|
||||||
has_many :nutrient_quantities, -> { order "lft" }, through: :nutrient_columns,
|
has_many :nutrient_quantities, -> { order "lft" }, through: :nutrient_exposures,
|
||||||
source: 'quantity'
|
source: 'quantity'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user