diff --git a/Gemfile b/Gemfile
index d52745d..0c42c44 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,8 @@
gem 'awesome_nested_set'
group :development do
- gem "web-console"
+ gem 'web-console'
+ gem 'active_record_query_trace'
end
group :development, :test do
diff --git a/app/controllers/ingredients_controller.rb b/app/controllers/ingredients_controller.rb
index ce43d42..fac62f7 100644
--- a/app/controllers/ingredients_controller.rb
+++ b/app/controllers/ingredients_controller.rb
@@ -9,7 +9,7 @@ class IngredientsController < ApplicationController
@ingredient = Ingredient.new(project: @project)
# passing attr for after_initialize
@ingredient.nutrients.new(ingredient: @ingredient)
- @ingredients = @project.ingredients
+ @ingredients = @project.ingredients.includes(:ref_unit)
end
def create
@@ -18,7 +18,7 @@ class IngredientsController < ApplicationController
flash[:notice] = 'Created new ingredient'
redirect_to project_ingredients_url(@project)
else
- @ingredients = @project.ingredients
+ @ingredients = @project.ingredients.includes(:ref_unit)
render :index
end
end
@@ -37,7 +37,7 @@ class IngredientsController < ApplicationController
if params.has_key?(:file)
quantities = @project.quantities.map { |q| [q.name, q] }.to_h
units = @project.units.map { |u| [u.shortname, u] }.to_h
- ingredients = []
+ ingredients_params = []
column_units = {}
CSV.foreach(params[:file].path, headers: true).with_index(2) do |row, line|
@@ -45,7 +45,7 @@ class IngredientsController < ApplicationController
unless r.has_key?('Name')
warnings << "Line 1: required 'Name' column is missing" if line == 2
end
- i = {
+ i_params = {
name: r.delete('Name'),
ref_amount: 100.0,
ref_unit: units['g'],
@@ -88,25 +88,34 @@ class IngredientsController < ApplicationController
next if quantities[quantity].blank?
if quantity == 'Reference'
- i.update({
+ i_params.update({
ref_amount: amount.to_d,
ref_unit: unit
})
else
- i[:nutrients_attributes] << {
+ i_params[:nutrients_attributes] << {
quantity: quantities[quantity],
amount: amount.to_d,
unit: unit
}
end
end
- ingredients << i
+
+ ingredients_params << i_params
end
else
warnings << 'No file selected'
end
- if warnings.present?
+ if warnings.empty?
+ ingredients = @project.ingredients.create(ingredients_params)
+ flash[:notice] = "Imported #{ingredients.map(&:persisted?).count(true)} out of" \
+ " #{ingredients_params.length} ingredients"
+ skipped = ingredients.select { |i| !i.persisted? }
+ skipped_desc = skipped.map { |i| "#{i.name} - #{i.errors.full_messages.join(', ')}" }
+ flash[:warning] = "Ingredients skipped due to errors:
" \
+ " #{skipped_desc.join('
').truncate(1024)}"
+ else
warnings.unshift("Problems encountered during import - fix and try again:")
flash[:warning] = warnings.join("
").truncate(1024, omission: '...(and other)')
end
diff --git a/app/models/ingredient.rb b/app/models/ingredient.rb
index d65b3da..0a25f40 100644
--- a/app/models/ingredient.rb
+++ b/app/models/ingredient.rb
@@ -4,26 +4,24 @@ class Ingredient < ActiveRecord::Base
meat: 1
}
- belongs_to :project
- belongs_to :ref_unit, class_name: 'Unit'
+ belongs_to :project, required: true
+ belongs_to :ref_unit, class_name: 'Unit', required: true
- has_many :nutrients, inverse_of: :ingredient, dependent: :destroy
+ has_many :nutrients, inverse_of: :ingredient, dependent: :destroy, validate: true
+ validates :nutrients, presence: true
accepts_nested_attributes_for :nutrients, allow_destroy: true, reject_if: proc { |attrs|
attrs['quantity_id'].blank? && attrs['amount'].blank?
}
- validates_associated :nutrients
# Nutrient quantity_id uniqueness check for nested attributes
- validate on: :create do
+ validate do
quantities = self.nutrients.map { |n| n.quantity_id }
if quantities.length != quantities.uniq.length
errors.add(:nutrients, :duplicated_quantity)
end
end
- validates :project, associated: true
validates :name, presence: true, uniqueness: {scope: :project_id}
validates :ref_amount, numericality: {greater_than: 0}
- validates :ref_unit, presence: true, associated: true
validates :group, inclusion: {in: groups.keys}
after_initialize do
@@ -32,6 +30,7 @@ class Ingredient < ActiveRecord::Base
units = self.project.units
self.ref_unit ||= units.find_by(shortname: 'g') || units.first
self.group ||= :other
+ self.hidden = false if self.hidden.nil?
end
end
diff --git a/app/models/nutrient.rb b/app/models/nutrient.rb
index df60400..1abc0b1 100644
--- a/app/models/nutrient.rb
+++ b/app/models/nutrient.rb
@@ -1,13 +1,10 @@
class Nutrient < ActiveRecord::Base
- belongs_to :ingredient, inverse_of: :nutrients
- belongs_to :quantity
- belongs_to :unit
+ belongs_to :ingredient, inverse_of: :nutrients, required: true
+ belongs_to :quantity, required: true
+ belongs_to :unit, required: true
- # disabled to avoid loop with Ingredient 'validates_associated :nutrients'
- #validates :ingredient, presence: true, associated: true
- validates :quantity, presence: true, associated: true, uniqueness: {scope: :ingredient_id}
- validates :amount, numericality: {greater_than: 0}
- validates :unit, presence: true, associated: true
+ validates :quantity, uniqueness: {scope: :ingredient_id}
+ validates :amount, numericality: {greater_thani_or_equal_to: 0.0}
after_initialize do
if new_record?
diff --git a/app/models/quantity.rb b/app/models/quantity.rb
index 3dedc3f..c065821 100644
--- a/app/models/quantity.rb
+++ b/app/models/quantity.rb
@@ -1,18 +1,15 @@
class Quantity < ActiveRecord::Base
- acts_as_nested_set dependent: :nullify, scope: :project
-
enum domain: {
diet: 0,
measurement: 1,
exercise: 2
}
- belongs_to :project
+ acts_as_nested_set dependent: :nullify, scope: :project
+ belongs_to :project, required: false
- validates :project, associated: true
validates :name, presence: true, uniqueness: {scope: :project_id}
validates :domain, inclusion: {in: domains.keys}
- validates :parent, associated: true
validate if: -> { parent.present? } do
errors.add(:parent, :parent_domain_mismatch) unless domain == parent.domain
end
diff --git a/app/models/unit.rb b/app/models/unit.rb
index c446468..7aeff43 100644
--- a/app/models/unit.rb
+++ b/app/models/unit.rb
@@ -1,6 +1,5 @@
class Unit < ActiveRecord::Base
- belongs_to :project
+ belongs_to :project, required: true
- validates :project, associated: true
validates :shortname, presence: true, uniqueness: {scope: :project_id}
end