diff --git a/Dockerfile b/Dockerfile index 918a649..04dce4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,7 @@ ENV PASSENGER_APP_ENV docker RUN mkdir -p /home/app/parsley/ COPY Gemfile /home/app/parsley/ COPY Gemfile.lock /home/app/parsley/ +RUN gem install bundler RUN cd /home/app/parsley/ && bundle install --deployment # Copy the app into the image diff --git a/app/controllers/recipes_controller.rb b/app/controllers/recipes_controller.rb index a7a24e7..af6fe81 100644 --- a/app/controllers/recipes_controller.rb +++ b/app/controllers/recipes_controller.rb @@ -37,12 +37,15 @@ class RecipesController < ApplicationController end end + @recipe = RecipeDecorator.decorate(@recipe, view_context) + end # GET /recipes/1 def scale @scale = params[:factor] @recipe.scale(@scale, true) + @recipe = RecipeDecorator.decorate(@recipe, view_context) render :show end @@ -84,7 +87,7 @@ class RecipesController < ApplicationController ensure_owner(@recipe) do @recipe.deleted = true - if @recipe.save + if @recipe.save(validate: false) redirect_to recipes_url, notice: 'Recipe was successfully destroyed.' else redirect_to recipes_url, error: 'Recipe could not be destroyed.' diff --git a/app/decorators/base_decorator.rb b/app/decorators/base_decorator.rb new file mode 100644 index 0000000..bbed4ff --- /dev/null +++ b/app/decorators/base_decorator.rb @@ -0,0 +1,50 @@ +require 'delegate' + +# Minimal Decorator Base Class +# +# Implements a SimpleDelegator, provides access to the view_context through the `h` method, and provides +# a factory method to construct Delegators or collections of Delegators +# +# In a controller, the view_context can be retrieved by calling a method of the same name +# In a view or view helper, the context is `self` +# +# See also ApplicationHelper#decorate +class BaseDecorator < SimpleDelegator + + class << self + # Decorates a single object or a collection of objects. If the given objects are `BaseDecorators`, they will be + # unwrapped first + def decorate(obj, view_context) + decorated = Array.wrap(obj).map do |o| + case o + when nil + nil + when BaseDecorator + new(o.__getobj__, view_context) + else + new(o, view_context) + end + end + obj.respond_to?(:each) ? decorated : decorated.first + end + end + + def initialize(base, view_context) + super(base) + @view_context = view_context + end + + def h + @view_context + end + + # For some reason, view_context.html_escape is marked as private. To provide access to the same functionality, + # define it here + def html_escape(*args) + ERB::Util.html_escape(*args) + end + + def wrapped + __getobj__ + end +end \ No newline at end of file diff --git a/app/decorators/nutrition_data_decorator.rb b/app/decorators/nutrition_data_decorator.rb new file mode 100644 index 0000000..d43a935 --- /dev/null +++ b/app/decorators/nutrition_data_decorator.rb @@ -0,0 +1,19 @@ +class NutritionDataDecorator < BaseDecorator + + [:protein, :lipids, :carbohydrates, :kcal, :fiber, :sugar].each do |m| + + def format_number(n) + '%.1f' % n + end + + define_method m do + format_number(super()) + end + + define_method "#{m}_per" do |per| + format_number(wrapped.send(m) / per) + end + + end + +end \ No newline at end of file diff --git a/app/decorators/recipe_decorator.rb b/app/decorators/recipe_decorator.rb new file mode 100644 index 0000000..9a65715 --- /dev/null +++ b/app/decorators/recipe_decorator.rb @@ -0,0 +1,17 @@ +class RecipeDecorator < BaseDecorator + + def source_markup + uri = begin + URI.parse(self.source) + rescue URI::InvalidURIError + nil + end + + if uri.is_a? URI::HTTP + h.link_to(uri.host, uri.to_s) + else + h.content_tag('span', self.source) + end + end + +end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1238a1a..fe2e5a1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,18 @@ module ApplicationHelper + # Given a model or collection of models, returns them with the given decorator. If a block is passed, yields the + # decorated objects as well + # + # Useful in this context: + # <% decorate(@model_obj, ModelObjDecorator) do |model_obj| %> + # <%= model_obj.decorator_method %> + # <% end %> + def decorate(obj, decorator_class) + decorated = decorator_class.decorate(obj, self) + yield(decorated) if block_given? + decorated + end + def timestamp(time) time ? time.strftime('%D %R') : '' end diff --git a/app/views/ingredients/_form.html.erb b/app/views/ingredients/_form.html.erb index 2458bf7..2061cee 100644 --- a/app/views/ingredients/_form.html.erb +++ b/app/views/ingredients/_form.html.erb @@ -58,7 +58,7 @@
- <%= f.label :carbohydrates, "Grams of Fat", class: 'control-label' %> + <%= f.label :carbohydrates, "Grams of Carbohydrates", class: 'control-label' %> <%= f.text_field :carbohydrates, class: 'form-control' %>
diff --git a/app/views/recipes/index.html.erb b/app/views/recipes/index.html.erb index a6e517d..7616540 100644 --- a/app/views/recipes/index.html.erb +++ b/app/views/recipes/index.html.erb @@ -14,13 +14,12 @@ Name - <% if current_user? %> - - <% end %> Yields Time Created - Modified + <% if current_user? %> + + <% end %> @@ -28,7 +27,9 @@ <% @recipes.each do |recipe| %> <%= link_to recipe.display_name, recipe %> - + <%= recipe.yields %> + <%= recipe_time(recipe) %> + <%= timestamp(recipe.created_at) %> <% if current_user? %> <%= link_to edit_recipe_path(recipe), class: 'btn btn-sm btn-primary' do %> @@ -39,11 +40,6 @@ <% end %> <% end %> - - <%= recipe.yields %> - <%= recipe_time(recipe) %> - <%= timestamp(recipe.created_at) %> - <%= timestamp(recipe.updated_at) %> <% end %> diff --git a/app/views/recipes/show.html.erb b/app/views/recipes/show.html.erb index e828b12..5811135 100644 --- a/app/views/recipes/show.html.erb +++ b/app/views/recipes/show.html.erb @@ -32,7 +32,7 @@ <% if @recipe.source.present? %>
-

Source

<%= @recipe.source %>

+

Source

<%= @recipe.source_markup %>

<% end %> @@ -88,59 +88,61 @@

Nutrition Data

- - + <% decorate(@recipe.nutrition_data, NutritionDataDecorator) do |nutrition_data| %> +
+ + + + <% if @recipe.parsed_yield %> + + <% end %> + + + - + <% if @recipe.parsed_yield %> - + <% end %> - + - - - - <% if @recipe.parsed_yield %> - - <% end %> - - - - - <% if @recipe.parsed_yield %> - - <% end %> - - - - - <% if @recipe.parsed_yield %> - - <% end %> - - - - - <% if @recipe.parsed_yield %> - - <% end %> - - - - - <% if @recipe.parsed_yield %> - - <% end %> - - - - - <% if @recipe.parsed_yield %> - - <% end %> - - -
Item<%= @recipe.parsed_yield.label %>Total
ItemCalories<%= @recipe.parsed_yield.label %><%= nutrition_data.kcal_per(@recipe.parsed_yield.number) %>Total<%= nutrition_data.kcal %>
Calories<%= @recipe.nutrition_data.kcal / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.kcal %>
Grams Protein<%= @recipe.nutrition_data.protein / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.protein %>
Grams Fat<%= @recipe.nutrition_data.lipids / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.lipids %>
Grams Carbohydrates<%= @recipe.nutrition_data.carbohydrates / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.carbohydrates %>
Grams Sugar<%= @recipe.nutrition_data.sugar / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.sugar %>
Grams Fiber<%= @recipe.nutrition_data.fiber / @recipe.parsed_yield.number %><%= @recipe.nutrition_data.fiber %>
+ + Grams Protein + <% if @recipe.parsed_yield %> + <%= nutrition_data.protein_per(@recipe.parsed_yield.number) %> + <% end %> + <%= nutrition_data.protein %> + + + Grams Fat + <% if @recipe.parsed_yield %> + <%= nutrition_data.lipids_per(@recipe.parsed_yield.number) %> + <% end %> + <%= nutrition_data.lipids %> + + + Grams Carbohydrates + <% if @recipe.parsed_yield %> + <%= nutrition_data.carbohydrates_per(@recipe.parsed_yield.number) %> + <% end %> + <%= nutrition_data.carbohydrates %> + + + Grams Sugar + <% if @recipe.parsed_yield %> + <%= nutrition_data.sugar_per(@recipe.parsed_yield.number) %> + <% end %> + <%= nutrition_data.sugar %> + + + Grams Fiber + <% if @recipe.parsed_yield %> + <%= nutrition_data.fiber_per(@recipe.parsed_yield.number) %> + <% end %> + <%= nutrition_data.fiber %> + + + <% end %>

Nutrition Calculation Warnings