├── app ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── concerns │ │ ├── .keep │ │ ├── calorie.rb │ │ └── copier.rb │ ├── utils.rb │ ├── ingredient_group.rb │ ├── role.rb │ ├── diet_item.rb │ ├── rations_users.rb │ ├── ckeditor │ │ ├── picture.rb │ │ ├── attachment_file.rb │ │ └── asset.rb │ ├── ability.rb │ ├── plan_item_ingredient.rb │ ├── blog.rb │ ├── post.rb │ ├── diet.rb │ ├── eaten.rb │ ├── ration.rb │ ├── dish_composition.rb │ ├── admin_ability.rb │ ├── setting.rb │ ├── dish.rb │ ├── ingredient.rb │ ├── user.rb │ ├── meal.rb │ └── plan_item.rb ├── assets │ ├── images │ │ └── .keep │ ├── javascripts │ │ ├── client.js │ │ ├── active_admin.js.coffee │ │ ├── home.js.coffee │ │ ├── application.js │ │ └── active_admin_utils.js │ └── stylesheets │ │ ├── home.css.scss │ │ ├── blog-post.css │ │ ├── client.css │ │ ├── application.css │ │ └── active_admin.css.scss ├── controllers │ ├── concerns │ │ └── .keep │ ├── home_controller.rb │ ├── application_controller.rb │ └── sitemap_controller.rb ├── views │ ├── admin │ │ ├── eatens │ │ │ ├── select_ingredient.html.arb │ │ │ ├── _form.html.erb │ │ │ └── select_type.html.arb │ │ ├── ingredients │ │ │ └── rations.html.arb │ │ └── plans │ │ │ ├── _show_top.html.arb │ │ │ ├── _total_target.html.arb │ │ │ ├── _show_meal.html.arb │ │ │ └── _show_item.html.arb │ ├── home │ │ ├── index.html.erb │ │ ├── post.html.erb │ │ ├── _entry.html.erb │ │ ├── _diet.html.erb │ │ └── _dish.html.erb │ ├── sitemap │ │ └── index.html.haml │ ├── layouts │ │ ├── _side_search.html.erb │ │ ├── _side_popular.html.erb │ │ ├── _disqus.html.erb │ │ └── application.html.erb │ └── active_admin │ │ └── devise │ │ └── registrations │ │ └── new.html.erb ├── admin │ ├── ingredient_group.rb │ ├── active_admin_comment.rb │ ├── user.rb │ ├── plan_item_ingredient.rb │ ├── select_ingredient.rb │ ├── plans.rb │ ├── eatens.rb │ ├── rations.rb │ ├── dashboard.rb │ ├── diets.rb │ ├── plan_items.rb │ ├── posts.rb │ ├── settings.rb │ ├── dish.rb │ └── ingredients.rb ├── helpers │ ├── exhibits_helper.rb │ ├── application_helper.rb │ ├── home_helper.rb │ └── active_admin │ │ └── views_helper.rb ├── exhibits │ ├── diet_post_exhibit.rb │ ├── dish_post_exhibit.rb │ └── exhibit.rb └── uploaders │ ├── ckeditor_attachment_file_uploader.rb │ └── ckeditor_picture_uploader.rb ├── lib ├── assets │ └── .keep ├── tasks │ ├── .keep │ └── import.rake └── active_admin │ └── post_action.rb ├── public ├── favicon.ico ├── robots.txt ├── 500.html ├── 422.html ├── 404.html └── javascripts │ └── autocomplete-rails.js ├── test ├── helpers │ └── .keep ├── mailers │ └── .keep ├── models │ └── .keep ├── controllers │ └── .keep ├── fixtures │ └── .keep ├── integration │ └── .keep └── test_helper.rb ├── .ruby-version ├── README.md ├── vendor └── assets │ ├── javascripts │ └── .keep │ ├── stylesheets │ └── .keep │ └── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── config ├── initializers │ ├── blog.rb │ ├── better_errors.rb │ ├── default_settings.rb │ ├── filter_parameter_logging.rb │ ├── mime_types.rb │ ├── session_store.rb │ ├── rolify.rb │ ├── backtrace_silencers.rb │ ├── active_admin_devise.rb │ ├── wrap_parameters.rb │ ├── tableless.rb │ ├── inflections.rb │ ├── active_admin_comments.rb │ ├── ckeditor.rb │ └── friendly_id.rb ├── boot.rb ├── environment.rb ├── database.yml.example ├── locales │ ├── en.yml │ ├── ru.yml │ ├── devise.en.yml │ └── devise.ru.yml ├── default_settings.yml ├── application.rb ├── environments │ ├── development.rb │ ├── test.rb │ └── production.rb └── routes.rb ├── bin ├── rake ├── bundle └── rails ├── spec ├── factories │ ├── plan_items.rb │ ├── diets.rb │ ├── posts.rb │ ├── plan_item_ingredients.rb │ ├── plans.rb │ ├── eatens.rb │ ├── settings.rb │ ├── rations.rb │ ├── dish_compositions.rb │ ├── users.rb │ ├── dishes.rb │ └── ingredients.rb ├── models │ ├── rations_users_spec.rb │ ├── plan_item_ingredient_spec.rb │ ├── plan_item_spec.rb │ ├── setting_spec.rb │ ├── eaten_spec.rb │ ├── dish_composition_spec.rb │ ├── ingredient_spec.rb │ ├── ration_spec.rb │ ├── user_spec.rb │ ├── dish_spec.rb │ └── plan_spec.rb ├── views │ └── home │ │ └── index.html.erb_spec.rb ├── requests │ ├── admin │ │ ├── auth_spec.rb │ │ ├── diet_spec.rb │ │ ├── plan_spec.rb │ │ ├── rations_spec.rb │ │ ├── plan_items_spec.rb │ │ └── ingredient_spec.rb │ └── home │ │ └── post_spec.rb ├── support │ └── helpers │ │ ├── ingredient_helper.rb │ │ └── dish_helper.rb ├── controllers │ └── home_controller_spec.rb ├── helpers │ └── home_helper_spec.rb └── spec_helper.rb ├── config.ru ├── db ├── migrate │ ├── 20131112154607_add_user_id_to_eatens.rb │ ├── 20140612213519_add_published_at_to_diets.rb │ ├── 20140413142700_add_meals_num_to_plans.rb │ ├── 20140616151140_add_slug_to_diets.rb │ ├── 20140707193442_add_slug_to_posts.rb │ ├── 20140423131814_add_group_id_to_ingredients.rb │ ├── 20131013172526_add_portion_unit_to_ingredients.rb │ ├── 20140313113821_add_portions_to_dish_compositions.rb │ ├── 20131013190915_create_dishes.rb │ ├── 20140423131002_create_ingredient_groups.rb │ ├── 20140709101742_add_meta_fields_to_posts.rb │ ├── 20140217120322_create_rations_users.rb │ ├── 20140110155326_create_plans.rb │ ├── 20140210110407_create_rations.rb │ ├── 20140406211132_add_eatable_to_plan_items.rb │ ├── 20140611123539_create_diets.rb │ ├── 20131013193157_create_dish_compositions.rb │ ├── 20140715064415_add_prep_fields_to_dishes.rb │ ├── 20131013223444_add_weight_and_nutrients_to_dishes.rb │ ├── 20140611133430_create_diet_items.rb │ ├── 20140112083851_create_plan_items.rb │ ├── 20131013134429_create_ingredients.rb │ ├── 20140123143320_create_plan_item_ingredients.rb │ ├── 20140428184924_add_sessions_table.rb │ ├── 20140703101827_create_posts.rb │ ├── 20140219151724_seed_shared_default_ration.rb │ ├── 20140305200245_add_user_id_to_ingredients.rb │ ├── 20140225092159_add_user_id_to_dishes.rb │ ├── 20131015214831_create_eatens.rb │ ├── 20131105144428_create_settings.rb │ ├── 20131111195438_rolify_create_roles.rb │ ├── 20140210112630_seed_default_ration.rb │ ├── 20140616144939_create_friendly_id_slugs.rb │ ├── 20130930230518_create_active_admin_comments.rb │ ├── 20140621104652_create_ckeditor_assets.rb │ └── 20130930230513_devise_create_users.rb └── seeds.rb ├── Rakefile ├── .gitignore ├── README.rdoc └── Gemfile /app/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-1.9.3-p448 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mangajo 2 | ======= 3 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/utils.rb: -------------------------------------------------------------------------------- 1 | module Utils 2 | end 3 | -------------------------------------------------------------------------------- /app/views/admin/eatens/select_ingredient.html.arb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/initializers/blog.rb: -------------------------------------------------------------------------------- 1 | THE_BLOG = Blog.new 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/client.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require bootstrap 3 | 4 | 5 | -------------------------------------------------------------------------------- /config/initializers/better_errors.rb: -------------------------------------------------------------------------------- 1 | BetterErrors.editor = :macvim if defined? BetterErrors 2 | -------------------------------------------------------------------------------- /app/admin/ingredient_group.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register IngredientGroup do 2 | menu :parent => "Ingredients" 3 | end 4 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /app/admin/active_admin_comment.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register ActiveAdmin::Comment do 2 | menu :label => "Comments" 3 | end 4 | -------------------------------------------------------------------------------- /spec/factories/plan_items.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :plan_item do 3 | weight { rand(100) + 1 } 4 | end 5 | end 6 | 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin.js.coffee: -------------------------------------------------------------------------------- 1 | #= require active_admin/base 2 | #= require jquery.ui.autocomplete 3 | #= require jquery_ujs 4 | -------------------------------------------------------------------------------- /spec/factories/diets.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :diet do 3 | sequence(:name) { |n| "Diet_#{n}" } 4 | 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/posts.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :post do 3 | sequence(:title) { |n| "Post_#{n}" } 4 | 5 | end 6 | end 7 | 8 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bob/mangajo/master/vendor/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bob/mangajo/master/vendor/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/models/ingredient_group.rb: -------------------------------------------------------------------------------- 1 | class IngredientGroup < ActiveRecord::Base 2 | default_scope { order(:name) } 3 | has_many :ingredients 4 | 5 | end 6 | -------------------------------------------------------------------------------- /vendor/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bob/mangajo/master/vendor/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/helpers/exhibits_helper.rb: -------------------------------------------------------------------------------- 1 | module ExhibitsHelper 2 | 3 | def exhibit(model, context) 4 | Exhibit.exhibit(model, context) 5 | end 6 | 7 | end 8 | 9 | -------------------------------------------------------------------------------- /spec/models/rations_users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe RationsUsers do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/plan_item_ingredients.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :plan_item_ingredient do 3 | weight { rand(100) + 1 } 4 | end 5 | end 6 | 7 | 8 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /spec/models/plan_item_ingredient_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PlanItemIngredient do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /spec/views/home/index.html.erb_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "home/index.html.erb" do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /db/migrate/20131112154607_add_user_id_to_eatens.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToEatens < ActiveRecord::Migration 2 | def change 3 | add_column :eatens, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/role.rb: -------------------------------------------------------------------------------- 1 | class Role < ActiveRecord::Base 2 | has_and_belongs_to_many :users, :join_table => :users_roles 3 | belongs_to :resource, :polymorphic => true 4 | 5 | scopify 6 | end 7 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 5 | -------------------------------------------------------------------------------- /db/migrate/20140612213519_add_published_at_to_diets.rb: -------------------------------------------------------------------------------- 1 | class AddPublishedAtToDiets < ActiveRecord::Migration 2 | def change 3 | add_column :diets, :published_at, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/requests/admin/auth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Authentication" do 4 | describe "Signup" do 5 | it "should create user" do 6 | 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140413142700_add_meals_num_to_plans.rb: -------------------------------------------------------------------------------- 1 | class AddMealsNumToPlans < ActiveRecord::Migration 2 | def change 3 | add_column :plans, :meals_num, :integer, :default => 1 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140616151140_add_slug_to_diets.rb: -------------------------------------------------------------------------------- 1 | class AddSlugToDiets < ActiveRecord::Migration 2 | def change 3 | add_column :diets, :slug, :string 4 | add_index :diets, :slug 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20140707193442_add_slug_to_posts.rb: -------------------------------------------------------------------------------- 1 | class AddSlugToPosts < ActiveRecord::Migration 2 | def change 3 | add_column :posts, :slug, :string 4 | add_index :posts, :slug 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/home.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/models/diet_item.rb: -------------------------------------------------------------------------------- 1 | class DietItem < ActiveRecord::Base 2 | belongs_to :plan 3 | belongs_to :diet 4 | 5 | attr_accessible :plan_id, :diet_id, :order_num 6 | 7 | validates :plan, :presence => true 8 | end 9 | -------------------------------------------------------------------------------- /app/models/rations_users.rb: -------------------------------------------------------------------------------- 1 | class RationsUsers < ActiveRecord::Base 2 | def change 3 | create_table :rations_users do |t| 4 | t.belongs_to :ration 5 | t.belongs_to :user 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/plans.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :plan do 3 | sequence(:name) { |n| "Plan_#{n}" } 4 | 5 | factory :plan_second do 6 | name "Second" 7 | 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/ckeditor/picture.rb: -------------------------------------------------------------------------------- 1 | class Ckeditor::Picture < Ckeditor::Asset 2 | mount_uploader :data, CkeditorPictureUploader, :mount_on => :data_file_name 3 | 4 | def url_content 5 | url(:content) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140423131814_add_group_id_to_ingredients.rb: -------------------------------------------------------------------------------- 1 | class AddGroupIdToIngredients < ActiveRecord::Migration 2 | def change 3 | add_column :ingredients, :ingredient_group_id, :integer, :default => 0 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/eatens.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :eaten do 3 | eatable { create(:dish_sample) } 4 | weight "200" 5 | proteins "38.5" 6 | fats "60.5" 7 | carbs "82.5" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/settings.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :setting do 3 | sequence(:var) { |n| "var#{n}" } 4 | sequence(:title) { |n| "Title_#{n}" } 5 | value { rand(100) } 6 | 7 | end 8 | end 9 | 10 | -------------------------------------------------------------------------------- /spec/models/plan_item_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PlanItem do 4 | describe "Associations" do 5 | it { should belong_to(:plan) } 6 | it { should belong_to(:eatable) } 7 | 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/views/admin/eatens/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= semantic_form_for [:admin, @eaten] do |f| %> 2 | <%= "#{@eaten.eatable.class.model_name.human} '#{@eaten.eatable.name}'" %> 3 | <%= f.inputs :weight %> 4 | <%= f.actions %> 5 | <% end %> 6 | -------------------------------------------------------------------------------- /config/initializers/default_settings.rb: -------------------------------------------------------------------------------- 1 | conf = YAML.load_file("#{Rails.root}/config/default_settings.yml") 2 | 3 | conf.values.each do |c| 4 | #Setting[c["var"].to_sym] = c 5 | end 6 | 7 | #Setting.save_default(:some_key, "123") 8 | -------------------------------------------------------------------------------- /db/migrate/20131013172526_add_portion_unit_to_ingredients.rb: -------------------------------------------------------------------------------- 1 | class AddPortionUnitToIngredients < ActiveRecord::Migration 2 | def change 3 | add_column :ingredients, :portion_unit, :string, :after => :portion 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20140313113821_add_portions_to_dish_compositions.rb: -------------------------------------------------------------------------------- 1 | class AddPortionsToDishCompositions < ActiveRecord::Migration 2 | def change 3 | add_column :dish_compositions, :portions, :integer, :default => 0 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/helpers/ingredient_helper.rb: -------------------------------------------------------------------------------- 1 | module IngredientHelper 2 | def create_ingredient_user_ration(factory, user) 3 | ing = create(factory, :user => user, :ration => Ration.find(user.setting(:ration))) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | user ||= User.new 6 | 7 | can :access, :ckeditor 8 | can :manage, Ckeditor::Picture, :assetable_id => user.id 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /app/assets/javascripts/home.js.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /db/migrate/20131013190915_create_dishes.rb: -------------------------------------------------------------------------------- 1 | class CreateDishes < ActiveRecord::Migration 2 | def change 3 | create_table :dishes do |t| 4 | t.string :name 5 | t.text :description 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20140423131002_create_ingredient_groups.rb: -------------------------------------------------------------------------------- 1 | class CreateIngredientGroups < ActiveRecord::Migration 2 | def change 3 | create_table :ingredient_groups do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def yield_with_default(name, default, joins = ", ") 3 | if content_for?(name) 4 | [content_for(name).chomp, default].join(joins) 5 | else 6 | default 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140709101742_add_meta_fields_to_posts.rb: -------------------------------------------------------------------------------- 1 | class AddMetaFieldsToPosts < ActiveRecord::Migration 2 | def change 3 | add_column :posts, :meta_keywords, :text, :limit => 1024 4 | add_column :posts, :meta_description, :text, :limit => 1024 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/blog-post.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 100px; /* 100px is double the height of the navbar - I made it a big larger for some more space - keep it at 50px at least if you want to use the fixed top nav */ 3 | } 4 | 5 | footer { 6 | margin: 50px 0; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /app/models/ckeditor/attachment_file.rb: -------------------------------------------------------------------------------- 1 | class Ckeditor::AttachmentFile < Ckeditor::Asset 2 | mount_uploader :data, CkeditorAttachmentFileUploader, :mount_on => :data_file_name 3 | 4 | def url_thumb 5 | @url_thumb ||= Ckeditor::Utils.filethumb(filename) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Mealness::Application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/controllers/home_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe HomeController do 4 | 5 | describe "GET 'index'" do 6 | xit "returns http success" do 7 | get 'index' 8 | response.should be_success 9 | end 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20140217120322_create_rations_users.rb: -------------------------------------------------------------------------------- 1 | class CreateRationsUsers < ActiveRecord::Migration 2 | def change 3 | create_table :rations_users do |t| 4 | t.integer :ration_id 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | Encoding.default_external = Encoding::UTF_8 5 | Encoding.default_internal = Encoding::UTF_8 6 | 7 | # Initialize the Rails application. 8 | Mealness::Application.initialize! 9 | -------------------------------------------------------------------------------- /db/migrate/20140110155326_create_plans.rb: -------------------------------------------------------------------------------- 1 | class CreatePlans < ActiveRecord::Migration 2 | def change 3 | create_table :plans do |t| 4 | t.integer :user_id 5 | t.string :name 6 | t.text :description 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140210110407_create_rations.rb: -------------------------------------------------------------------------------- 1 | class CreateRations < ActiveRecord::Migration 2 | def change 3 | create_table :rations do |t| 4 | t.integer :user_id 5 | t.string :name 6 | t.text :description 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140406211132_add_eatable_to_plan_items.rb: -------------------------------------------------------------------------------- 1 | class AddEatableToPlanItems < ActiveRecord::Migration 2 | def change 3 | rename_column :plan_items, :dish_id, :eatable_id 4 | add_column :plan_items, :eatable_type, :string, :default => "Dish", :after => :eatable_id 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/models/ckeditor/asset.rb: -------------------------------------------------------------------------------- 1 | class Ckeditor::Asset < ActiveRecord::Base 2 | include Ckeditor::Orm::ActiveRecord::AssetBase 3 | 4 | belongs_to :assetable, polymorphic: true 5 | 6 | delegate :url, :current_path, :content_type, :to => :data 7 | 8 | validates_presence_of :data 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140611123539_create_diets.rb: -------------------------------------------------------------------------------- 1 | class CreateDiets < ActiveRecord::Migration 2 | def change 3 | create_table :diets do |t| 4 | t.integer :user_id, :null => false 5 | t.string :name 6 | t.text :description 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/helpers/dish_helper.rb: -------------------------------------------------------------------------------- 1 | module DishHelper 2 | def create_dish_user_ration(factory, user) 3 | dish = create(factory, :user => user) 4 | create(:dish_composition, :dish => dish, 5 | :ingredient => create(:ingredient_empty, :ration_id => user.setting(:ration))) 6 | dish 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render :partial => "/home/entry", :collection => @posts %> 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /app/views/admin/ingredients/rations.html.arb: -------------------------------------------------------------------------------- 1 | div link_to("Return to start", session[:ingredient_referer]) 2 | 3 | panel "Select a ration" do 4 | table_for rations do 5 | column("Name") { |e| link_to e.name, admin_ration_select_ingredients_path(e.id) } 6 | column("Ingredients") { |e| e.ingredients.count } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20131013193157_create_dish_compositions.rb: -------------------------------------------------------------------------------- 1 | class CreateDishCompositions < ActiveRecord::Migration 2 | def change 3 | create_table :dish_compositions do |t| 4 | t.integer :dish_id 5 | t.integer :ingredient_id 6 | t.integer :weight 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140715064415_add_prep_fields_to_dishes.rb: -------------------------------------------------------------------------------- 1 | class AddPrepFieldsToDishes < ActiveRecord::Migration 2 | def change 3 | add_column :dishes, :prep_time, :integer, :default => 0 4 | add_column :dishes, :cook_time, :integer, :default => 0 5 | add_column :dishes, :portions, :integer, :default => 0 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20131013223444_add_weight_and_nutrients_to_dishes.rb: -------------------------------------------------------------------------------- 1 | class AddWeightAndNutrientsToDishes < ActiveRecord::Migration 2 | def change 3 | add_column :dishes, :proteins, :float 4 | add_column :dishes, :fats, :float 5 | add_column :dishes, :carbs, :float 6 | add_column :dishes, :weight, :integer 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/sitemap/index.html.haml: -------------------------------------------------------------------------------- 1 | - base_url = "http://#{request.host_with_port}" 2 | !!! XML 3 | %urlset{:xmlns => "http://www.sitemaps.org/schemas/sitemap/0.9"} 4 | - for post in @posts 5 | %url 6 | %loc #{post_url(post)} 7 | %lastmod=post.updated_at.to_date 8 | %changefreq monthly 9 | %priority 0.5 10 | -------------------------------------------------------------------------------- /db/migrate/20140611133430_create_diet_items.rb: -------------------------------------------------------------------------------- 1 | class CreateDietItems < ActiveRecord::Migration 2 | def change 3 | create_table :diet_items do |t| 4 | t.integer :diet_id, :null => false 5 | t.integer :plan_id, :null => false 6 | t.integer :order_num 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/exhibits/diet_post_exhibit.rb: -------------------------------------------------------------------------------- 1 | require_relative 'exhibit' 2 | 3 | class DietPostExhibit < Exhibit 4 | def render_body 5 | @context.render partial: "/home/diet", locals: { entry: self } 6 | end 7 | 8 | def self.applicable_to?(object) 9 | object.is_a?(Diet) #&& (!object.picture?) 10 | end 11 | 12 | end 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/factories/rations.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :ration do 3 | sequence(:name) { |n| "Ration_#{n}" } 4 | 5 | factory :ration_second do 6 | name "Ration Second" 7 | 8 | end 9 | 10 | factory :ration_user do 11 | association :user, :factory => :user_simple 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /app/exhibits/dish_post_exhibit.rb: -------------------------------------------------------------------------------- 1 | require_relative 'exhibit' 2 | 3 | class DishPostExhibit < Exhibit 4 | def render_body 5 | @context.render partial: "/home/dish", locals: { entry: self } 6 | end 7 | 8 | def self.applicable_to?(object) 9 | object.is_a?(Dish) #&& (!object.picture?) 10 | end 11 | 12 | end 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /db/migrate/20140112083851_create_plan_items.rb: -------------------------------------------------------------------------------- 1 | class CreatePlanItems < ActiveRecord::Migration 2 | def change 3 | create_table :plan_items do |t| 4 | t.integer :plan_id 5 | t.integer :dish_id 6 | t.integer :meal_id 7 | t.float :weight, :default => 0 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20131013134429_create_ingredients.rb: -------------------------------------------------------------------------------- 1 | class CreateIngredients < ActiveRecord::Migration 2 | def change 3 | create_table :ingredients do |t| 4 | t.string :name 5 | t.integer :portion 6 | t.float :carbs 7 | t.float :fats 8 | t.float :proteins 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Mealness::Application.config.session_store :active_record_store, key: '_mealness_session' 4 | ActiveRecord::SessionStore::Session.attr_accessible :data, :session_id 5 | 6 | #Mealness::Application.config.session_store :cookie_store, key: '_mealness_session' 7 | -------------------------------------------------------------------------------- /db/migrate/20140123143320_create_plan_item_ingredients.rb: -------------------------------------------------------------------------------- 1 | class CreatePlanItemIngredients < ActiveRecord::Migration 2 | def change 3 | create_table :plan_item_ingredients do |t| 4 | t.integer :plan_item_id 5 | t.integer :ingredient_id 6 | t.float :weight, :default => 0 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | before_filter :side_posts 3 | 4 | def index 5 | @posts = Post.published 6 | end 7 | 8 | def post 9 | @post = Post.published.friendly.find(params[:post_id]) 10 | end 11 | 12 | private 13 | def side_posts 14 | @side_posts = Post.published.limit(7) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/views/layouts/_side_search.html.erb: -------------------------------------------------------------------------------- 1 |

Поиск

2 |
3 | 4 | 5 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /config/initializers/rolify.rb: -------------------------------------------------------------------------------- 1 | Rolify.configure do |config| 2 | # By default ORM adapter is ActiveRecord. uncomment to use mongoid 3 | # config.use_mongoid 4 | 5 | # Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false 6 | # Enable this feature _after_ running rake db:migrate as it relies on the roles table 7 | # config.use_dynamic_shortcuts 8 | end -------------------------------------------------------------------------------- /db/migrate/20140428184924_add_sessions_table.rb: -------------------------------------------------------------------------------- 1 | class AddSessionsTable < ActiveRecord::Migration 2 | def change 3 | create_table :sessions do |t| 4 | t.string :session_id, :null => false 5 | t.text :data 6 | t.timestamps 7 | end 8 | 9 | add_index :sessions, :session_id, :unique => true 10 | add_index :sessions, :updated_at 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/home/post_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Post show page" do 4 | it "should be ok for diet" do 5 | diet = create(:diet, :user => create(:user)) 6 | post = create(:post, :published_at => Time.now, :postable => diet, :user => diet.user) 7 | 8 | visit "/posts/#{post.id}" 9 | 10 | page.should have_selector("div#diet_content") 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rbc 2 | *.sassc 3 | .sass-cache 4 | capybara-*.html 5 | .rspec 6 | .rvmrc 7 | /.bundle 8 | /vendor/bundle 9 | /log/* 10 | /tmp/* 11 | /db/*.sqlite3 12 | config/database.yml 13 | /public/system/* 14 | /public/assets/ 15 | public/uploads/ 16 | /coverage/ 17 | /spec/tmp/* 18 | **.orig 19 | rerun.txt 20 | pickle-email-*.html 21 | .project 22 | config/initializers/secret_token.rb 23 | *.sw? 24 | -------------------------------------------------------------------------------- /spec/factories/dish_compositions.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :dish_composition do 3 | #association :dish 4 | #association :ingredient 5 | weight { rand(100) } 6 | 7 | factory :dish_composition_schema_a1 do 8 | weight "150" 9 | end 10 | 11 | factory :dish_composition_schema_a2 do 12 | weight "50" 13 | end 14 | 15 | end 16 | end 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /db/migrate/20140703101827_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration 2 | def change 3 | create_table :posts do |t| 4 | t.integer :user_id 5 | t.string :title 6 | t.text :short_description 7 | t.integer :postable_id 8 | t.string :postable_type, :limit => 50 9 | t.datetime :published_at 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20140219151724_seed_shared_default_ration.rb: -------------------------------------------------------------------------------- 1 | class SeedSharedDefaultRation < ActiveRecord::Migration 2 | def change 3 | default_ration = Ration.find 1 4 | if default_ration 5 | User.all.each do |user| 6 | next if user.own_rations.include? default_ration 7 | default_ration.customers << user 8 | end 9 | default_ration.save 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20140305200245_add_user_id_to_ingredients.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToIngredients < ActiveRecord::Migration 2 | def migrate(direction) 3 | super 4 | 5 | if direction == :up 6 | Ingredient.all.each do |i| 7 | i.update_column(:user_id, i.ration.user.id) 8 | end 9 | end 10 | end 11 | 12 | def change 13 | add_column :ingredients, :user_id, :integer 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/client.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require bootstrap 3 | */ 4 | 5 | body { 6 | margin-top: 50px; /* 100px is double the height of the navbar - I made it a big larger for some more space - keep it at 50px at least if you want to use the fixed top nav */ 7 | } 8 | 9 | footer { 10 | margin: 50px 0; 11 | } 12 | 13 | .well.ads { 14 | padding: 11px; 15 | } 16 | 17 | .published { 18 | margin-top: 5px; 19 | } 20 | -------------------------------------------------------------------------------- /db/migrate/20140225092159_add_user_id_to_dishes.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToDishes < ActiveRecord::Migration 2 | def migrate(direction) 3 | super 4 | 5 | if direction == :up 6 | admin = User.find(1) 7 | if admin 8 | Dish.all.each { |d| d.update_column(:user_id, admin.id) } 9 | end 10 | end 11 | end 12 | 13 | def change 14 | add_column :dishes, :user_id, :integer 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/views/home/post.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :page_title do -%> 2 | <%= @post.title.html_safe %> 3 | <% end -%> 4 | 5 | <% content_for :meta_keywords do -%> 6 | <%= @post.meta_keywords.try(:html_safe) %> 7 | <% end -%> 8 | 9 | <% content_for :meta_description do -%> 10 | <%= @post.meta_description.try(:html_safe) %> 11 | <% end -%> 12 | 13 | <% entry = exhibit(@post.postable, self) -%> 14 | <%= entry.render_body %> 15 | 16 | 17 | -------------------------------------------------------------------------------- /db/migrate/20131015214831_create_eatens.rb: -------------------------------------------------------------------------------- 1 | class CreateEatens < ActiveRecord::Migration 2 | def change 3 | create_table :eatens do |t| 4 | t.integer :eatable_id 5 | t.string :eatable_type 6 | t.integer :weight, :default => 0 7 | t.float :proteins, :default => 0 8 | t.float :fats, :default => 0 9 | t.float :carbs, :default => 0 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/views/home/_entry.html.erb: -------------------------------------------------------------------------------- 1 | 2 |

<%= link_to entry.title.html_safe, post_path(entry) %>

3 |

от admin

4 |
5 |

<%= published_datetime(entry) %>

6 |
7 | 8 |

<%= entry.short_description.try(:html_safe) %>

9 | <%= link_to post_path(entry), :class => "btn btn-primary" do %> 10 | Далее 11 | <% end -%> 12 |
13 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | before_filter :init_blog 6 | 7 | def access_denied(exception) 8 | redirect_to admin_root_path, :alert => exception.message 9 | end 10 | 11 | private 12 | def init_blog 13 | @blog = THE_BLOG 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /app/controllers/sitemap_controller.rb: -------------------------------------------------------------------------------- 1 | class SitemapController < ApplicationController 2 | layout false 3 | respond_to :html, :xml 4 | 5 | def index 6 | headers['Content-Type'] = 'application/xml' 7 | last_post = Post.last 8 | @posts = Post.published 9 | 10 | if stale?(:etag => last_post, :last_modified => last_post.updated_at.utc) 11 | respond_to do |format| 12 | format.html {} 13 | format.xml {} 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/helpers/home_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the HomeHelper. For example: 5 | # 6 | # describe HomeHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # expect(helper.concat_strings("this","that")).to eq("this that") 10 | # end 11 | # end 12 | # end 13 | describe HomeHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /app/models/plan_item_ingredient.rb: -------------------------------------------------------------------------------- 1 | class PlanItemIngredient < ActiveRecord::Base 2 | include Copier 3 | 4 | belongs_to :plan_item 5 | belongs_to :ingredient 6 | 7 | attr_accessible :weight, :portion 8 | 9 | def display_name 10 | ingredient.name 11 | end 12 | 13 | def portion 14 | self.ingredient.portion.present? ? (self.weight / self.ingredient.portion) : 0 15 | end 16 | 17 | def portion=(value) 18 | self.weight = self.ingredient.weight.to_f * value.to_f 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20131105144428_create_settings.rb: -------------------------------------------------------------------------------- 1 | class CreateSettings < ActiveRecord::Migration 2 | def self.up 3 | create_table :settings do |t| 4 | t.string :var, :null => false 5 | t.text :value, :null => true 6 | t.integer :thing_id, :null => true 7 | t.string :thing_type, :limit => 30, :null => true 8 | t.timestamps 9 | end 10 | 11 | add_index :settings, [ :thing_type, :thing_id, :var ], :unique => true 12 | end 13 | 14 | def self.down 15 | drop_table :settings 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/blog.rb: -------------------------------------------------------------------------------- 1 | class Blog 2 | 3 | def initialize(entry_fetcher = Post.public_method(:all)) 4 | @entry_fetcher = entry_fetcher 5 | end 6 | 7 | def new_post(resource, *args) 8 | p = post_source.call(*args) 9 | p.blog = self 10 | p.title = resource.name 11 | p.postable = resource 12 | p.user = resource.user 13 | p 14 | end 15 | 16 | private 17 | def fetch_entries 18 | @entry_fetcher.() 19 | end 20 | 21 | def post_source 22 | @post_source ||= Post.public_method(:new) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /config/initializers/active_admin_devise.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Devise 3 | 4 | def self.controllers 5 | { 6 | :sessions => "active_admin/devise/sessions", 7 | :passwords => "active_admin/devise/passwords", 8 | :unlocks => "active_admin/devise/unlocks", 9 | :registrations => "active_admin/devise/registrations" 10 | } 11 | end 12 | 13 | class RegistrationsController < ::Devise::RegistrationsController 14 | include ::ActiveAdmin::Devise::Controller 15 | end 16 | 17 | end 18 | end 19 | 20 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | ActiveRecord::Migration.check_pending! 7 | 8 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 9 | # 10 | # Note: You'll currently still have to declare fixtures explicitly in integration tests 11 | # -- they do not yet inherit this setting 12 | fixtures :all 13 | 14 | # Add more helper methods to be used by all tests here... 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20131111195438_rolify_create_roles.rb: -------------------------------------------------------------------------------- 1 | class RolifyCreateRoles < ActiveRecord::Migration 2 | def change 3 | create_table(:roles) do |t| 4 | t.string :name 5 | t.references :resource, :polymorphic => true 6 | 7 | t.timestamps 8 | end 9 | 10 | create_table(:users_roles, :id => false) do |t| 11 | t.references :user 12 | t.references :role 13 | end 14 | 15 | add_index(:roles, :name) 16 | add_index(:roles, [ :name, :resource_type, :resource_id ]) 17 | add_index(:users_roles, [ :user_id, :role_id ]) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | 3 | factory :user do 4 | after(:build) { |user| user.class.set_callback(:create, :after, :add_rations) } 5 | before(:create) { |user| create(:ration_user, :id => 1) unless Ration.find_by_id(1) } 6 | 7 | sequence(:email) { |n| "test#{n}@example.com" } 8 | password 'password' 9 | end 10 | 11 | factory :user_simple, :class => User do 12 | after(:build) { |user| user.class.skip_callback(:create, :after, :add_rations) } 13 | 14 | sequence(:email) { |n| "test_2#{n}@example.com" } 15 | password 'password' 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | -------------------------------------------------------------------------------- /app/models/concerns/calorie.rb: -------------------------------------------------------------------------------- 1 | module Calorie 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | end 6 | 7 | def kcal 8 | Calorie.calculate(self.proteins, self.fats, self.carbs).round(2) 9 | end 10 | 11 | def calculate_kcal_weight(weight) 12 | Calorie.calculate( 13 | calculate_nutrient_weight(:proteins, weight), 14 | calculate_nutrient_weight(:fats, weight), 15 | calculate_nutrient_weight(:carbs, weight) 16 | ).round(2) 17 | end 18 | 19 | def self.calculate(proteins, fats, carbs) 20 | ((proteins || 0) * 4 + (carbs || 0) * 4 + (fats || 0) * 9) 21 | end 22 | 23 | 24 | end 25 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | 9 | admin = User.create( {:email =>'admin@example.com', :password => 'changeme'}) 10 | admin.add_role :admin 11 | 12 | default_ration = Ration.new(:name => "Common", :description => "Default ration") 13 | default_ration.user = admin 14 | default_ration.save 15 | -------------------------------------------------------------------------------- /db/migrate/20140210112630_seed_default_ration.rb: -------------------------------------------------------------------------------- 1 | class SeedDefaultRation < ActiveRecord::Migration 2 | def migrate(direction) 3 | super 4 | 5 | if direction == :up 6 | admin = User.find(1) 7 | 8 | if admin 9 | default_ration = Ration.new(:name => "Default", :description => "Default ration") 10 | default_ration.user = admin 11 | default_ration.save 12 | end 13 | 14 | if default_ration 15 | execute("UPDATE ingredients SET ration_id = ?", default_ration.id) 16 | end 17 | end 18 | 19 | end 20 | 21 | def change 22 | add_column :ingredients, :ration_id, :integer 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /db/migrate/20140616144939_create_friendly_id_slugs.rb: -------------------------------------------------------------------------------- 1 | class CreateFriendlyIdSlugs < ActiveRecord::Migration 2 | def change 3 | create_table :friendly_id_slugs do |t| 4 | t.string :slug, :null => false 5 | t.integer :sluggable_id, :null => false 6 | t.string :sluggable_type, :limit => 50 7 | t.string :scope 8 | t.datetime :created_at 9 | end 10 | add_index :friendly_id_slugs, :sluggable_id 11 | add_index :friendly_id_slugs, [:slug, :sluggable_type] 12 | add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true 13 | add_index :friendly_id_slugs, :sluggable_type 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /config/initializers/tableless.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord 2 | module Tableless 3 | module ClassMethods 4 | def connection 5 | conn = Object.new() 6 | def conn.quote_table_name(*args) 7 | "" 8 | end 9 | def conn.substitute_at(*args) 10 | nil 11 | end 12 | def conn.schema_cache(*args) 13 | schema_cache = Object.new() 14 | def schema_cache.columns_hash(*args) 15 | Hash.new() 16 | end 17 | schema_cache 18 | end 19 | def conn.sanitize_limit(limit) 20 | limit 21 | end 22 | conn 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/models/setting_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Setting do 4 | context "Associations" do 5 | it { should belong_to(:thing) } 6 | end 7 | 8 | context "Recalculating" do 9 | it "should calculate nutritions based on weight" do 10 | user = create(:user) 11 | weight_setting = create(:setting, :var => "weight", :value => 80) 12 | user.settings << weight_setting 13 | 14 | weight_setting.recalculate! 15 | 16 | user.setting_by_var("proteins").value.should == "160.0" 17 | user.setting_by_var("fats").value.should == "40.0" 18 | user.setting_by_var("carbs").value.should == "320.0" 19 | end 20 | end 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /app/admin/user.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register User do 2 | index do 3 | column :email 4 | column :current_sign_in_at 5 | column :last_sign_in_at 6 | column :sign_in_count 7 | column "Roles" do |user| 8 | user.roles.map{|r| r.name }.join(', ') 9 | end 10 | default_actions 11 | end 12 | 13 | filter :email 14 | 15 | form do |f| 16 | f.inputs "Admin Details" do 17 | f.input :email 18 | f.input :password 19 | f.input :password_confirmation 20 | end 21 | f.actions 22 | end 23 | controller do 24 | def permitted_params 25 | params.permit admin_user: [:email, :password, :password_confirmation] 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/concerns/copier.rb: -------------------------------------------------------------------------------- 1 | module Copier 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | end 6 | 7 | def do_copy &block 8 | wrap_copy do 9 | block.call if block 10 | end 11 | end 12 | 13 | def wrap_copy &block 14 | new_item = nil; message = "Empty Message #{self.class.name}" 15 | self.class.transaction do 16 | @copied_item = self.class.new 17 | @copied_item.attributes = self.attributes 18 | 19 | block.call if block 20 | 21 | if @copied_item.save 22 | else 23 | message = @copied_item.errors.full_messages 24 | raise ActiveRecord::Rollback 25 | end 26 | end 27 | 28 | [@copied_item, message] 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /db/migrate/20130930230518_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.string :resource_id, :null => false 7 | t.string :resource_type, :null => false 8 | t.references :author, :polymorphic => true 9 | t.timestamps 10 | end 11 | add_index :active_admin_comments, [:namespace] 12 | add_index :active_admin_comments, [:author_type, :author_id] 13 | add_index :active_admin_comments, [:resource_type, :resource_id] 14 | end 15 | 16 | def self.down 17 | drop_table :active_admin_comments 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/views/admin/eatens/select_type.html.arb: -------------------------------------------------------------------------------- 1 | columns do 2 | column do 3 | panel I18n.t("titles.ingredient") do 4 | form do |f| 5 | f.input :type => :text, :name => 'ingredient', :id => "ingredient_text", "data-autocomplete" => eaten_autocomplete_list_admin_ingredients_path 6 | f.input :type => :hidden, :name => 'ingredient_id', :id => "ingredient_id" 7 | f.input :type => :submit, :value => I18n.t("buttons.next") 8 | end 9 | 10 | table_for ingredients do 11 | column(I18n.t("titles.name")) { |c| link_to c.name, new_admin_ingredient_eaten_path(c) } 12 | end 13 | end 14 | end 15 | column do 16 | panel I18n.t("titles.dish") do 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/database.yml.example: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: mysql2 8 | timeout: 5000 9 | encoding: utf8 10 | pool: 5 11 | database: mealness_development 12 | username: root 13 | password: 14 | 15 | # Warning: The database defined as "test" will be erased and 16 | # re-generated from your development database when you run "rake". 17 | # Do not set this db to the same as development or production. 18 | test: 19 | adapter: sqlite3 20 | database: db/test.sqlite3 21 | pool: 5 22 | timeout: 5000 23 | 24 | production: 25 | adapter: sqlite3 26 | database: db/production.sqlite3 27 | pool: 5 28 | timeout: 5000 29 | -------------------------------------------------------------------------------- /app/views/layouts/_side_popular.html.erb: -------------------------------------------------------------------------------- 1 | <% @side_posts ||= [] -%> 2 | 3 |

Популярное

4 |
5 |
6 | 12 |
13 | 25 |
26 | 27 | -------------------------------------------------------------------------------- /app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | extend FriendlyId 3 | friendly_id :title, use: :slugged 4 | 5 | belongs_to :user 6 | belongs_to :postable, :polymorphic => true 7 | attr_accessible :title, :short_description, :meta_keywords, :meta_description 8 | 9 | scope :published, -> { where.not(:published_at => nil).order("published_at DESC") } 10 | 11 | attr_accessor :blog 12 | 13 | def should_generate_new_friendly_id? 14 | title_changed? 15 | end 16 | 17 | def published? 18 | !self.published_at.nil? 19 | end 20 | 21 | def publish!(clock = DateTime) 22 | return false unless valid? 23 | 24 | self.published_at = clock.now 25 | self.save 26 | end 27 | 28 | def unpublish! 29 | self.published_at = nil 30 | self.save 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | 25 | menu: 26 | settings: Settings 27 | food: Food 28 | -------------------------------------------------------------------------------- /app/admin/plan_item_ingredient.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register PlanItemIngredient do 2 | belongs_to :plan_item 3 | 4 | form do |f| 5 | f.inputs do 6 | if f.object.ingredient.portion_unit == "gramm" 7 | f.input :weight 8 | elsif f.object.ingredient.portion_unit == "item" 9 | f.input :portion 10 | end 11 | end 12 | f.actions 13 | end 14 | 15 | controller do 16 | def update 17 | update! { 18 | @plan_item.recalculate_weight 19 | redirect_to admin_plan_path(@plan_item.plan) and return 20 | } 21 | end 22 | 23 | def destroy 24 | destroy! do |format| 25 | @plan_item.recalculate_weight 26 | redirect_to admin_plan_path(@plan_item.plan) and return 27 | end 28 | end 29 | 30 | end 31 | 32 | end 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require jquery-ui 16 | //= require autocomplete-rails 17 | //= require turbolinks 18 | //= require_tree . 19 | -------------------------------------------------------------------------------- /app/views/active_admin/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= title "#{render_or_call_method_or_proc_on(self, active_admin_application.site_title)} Sign up" %>

3 | 4 | <%= active_admin_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :id => "registration_new" }) do |f| 5 | devise_error_messages! 6 | 7 | f.inputs do 8 | f.input :email, :label => :email, :autofocus => true 9 | f.input :password, :label => :password 10 | f.input :password_confirmation, :label => :password_confirmation 11 | end 12 | 13 | f.actions do 14 | f.action :submit, :label => "Sign up", :button_html => { :value => "Sign up" } 15 | end 16 | end %> 17 | 18 | <%= render "devise/shared/links" %> 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /db/migrate/20140621104652_create_ckeditor_assets.rb: -------------------------------------------------------------------------------- 1 | class CreateCkeditorAssets < ActiveRecord::Migration 2 | def change 3 | create_table :ckeditor_assets do |t| 4 | t.string :data_file_name, :null => false 5 | t.string :data_content_type 6 | t.integer :data_file_size 7 | 8 | t.integer :assetable_id 9 | t.string :assetable_type, :limit => 30 10 | t.string :type, :limit => 30 11 | 12 | # Uncomment it to save images dimensions, if your need it 13 | t.integer :width 14 | t.integer :height 15 | 16 | t.timestamps 17 | end 18 | 19 | add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], :name => "idx_ckeditor_assetable_type" 20 | add_index "ckeditor_assets", ["assetable_type", "assetable_id"], :name => "idx_ckeditor_assetable" 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/exhibits/exhibit.rb: -------------------------------------------------------------------------------- 1 | require 'delegate' 2 | 3 | class Exhibit < SimpleDelegator 4 | def initialize(model, context) 5 | @context = context 6 | super(model) 7 | end 8 | 9 | def self.exhibits 10 | [ 11 | DietPostExhibit, 12 | DishPostExhibit 13 | ] 14 | end 15 | 16 | def self.exhibit(object, context) 17 | exhibits.inject(object) do |object, exhibit| 18 | exhibit.exhibit_if_applicable(object, context) 19 | end 20 | end 21 | 22 | def self.exhibit_if_applicable(object, context) 23 | if applicable_to?(object) 24 | new(object, context) 25 | else 26 | object 27 | end 28 | end 29 | 30 | def self.applicable_to?(object) 31 | false 32 | end 33 | 34 | def to_model 35 | __getobj__ 36 | end 37 | 38 | def class 39 | __getobj__.class 40 | end 41 | 42 | end 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /spec/models/eaten_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Eaten do 4 | describe "Associations" do 5 | it { should belong_to(:eatable) } 6 | it { should belong_to(:user) } 7 | end 8 | 9 | describe "Day" do 10 | let(:past) { create(:eaten, :created_at => "2013-11-04 14:00") } 11 | let(:present) { create(:eaten, :created_at => "2013-11-05 14:00") } 12 | 13 | before(:each) do 14 | Date.stub(:today).and_return("2013-11-05 15:00:00") 15 | end 16 | 17 | it "should find for today" do 18 | eatens = Eaten.find_day 19 | eatens.should include(present) 20 | eatens.should_not include(past) 21 | end 22 | 23 | it "should find for yesterday" do 24 | eatens = Eaten.find_day("2013-11-04") 25 | eatens.should include(past) 26 | eatens.should_not include(present) 27 | end 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /app/models/diet.rb: -------------------------------------------------------------------------------- 1 | class Diet < ActiveRecord::Base 2 | extend FriendlyId 3 | friendly_id :name, use: :slugged 4 | 5 | attr_accessible :name, :description, :diet_items_attributes 6 | 7 | belongs_to :user 8 | 9 | has_many :diet_items 10 | accepts_nested_attributes_for :diet_items, :allow_destroy => true 11 | 12 | scope :published, -> { where.not(:published_at => nil).order("published_at DESC") } 13 | has_one :post, :as => :postable, :dependent => :destroy 14 | 15 | 16 | def should_generate_new_friendly_id? 17 | name_changed? 18 | end 19 | 20 | def published? 21 | self.published_at.present? 22 | end 23 | 24 | def publish(clock=DateTime) 25 | return false unless valid? 26 | 27 | self.published_at = clock.now 28 | self.save 29 | end 30 | 31 | def unpublish 32 | self.published_at = nil 33 | self.save 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/models/eaten.rb: -------------------------------------------------------------------------------- 1 | class Eaten < ActiveRecord::Base 2 | include Calorie 3 | attr_accessible :weight, :eatable_id, :eatable_type 4 | 5 | belongs_to :eatable, :polymorphic => true 6 | belongs_to :user 7 | 8 | after_save :after_saved 9 | 10 | def after_saved 11 | eated = self.eatable 12 | self.update_column(:proteins, eated.calculate_nutrient_weight(:proteins, self.weight)) 13 | self.update_column(:fats, eated.calculate_nutrient_weight(:fats, self.weight)) 14 | self.update_column(:carbs, eated.calculate_nutrient_weight(:carbs, self.weight)) 15 | end 16 | 17 | def display_name 18 | 19 | end 20 | 21 | class << self 22 | def find_day(date=nil) 23 | db_date = date ? date.to_date : Date.today.to_date 24 | where("created_at <= '#{db_date.end_of_day}' AND created_at >= '#{db_date.beginning_of_day}'") 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /config/initializers/active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Comments 3 | module Views 4 | class Comments < ActiveAdmin::Views::Panel 5 | def build_comment(comment) 6 | div :for => comment do 7 | div :class => "active_admin_comment_meta" do 8 | user_name = comment.author ? auto_link(comment.author) : "Anonymous" 9 | h4(user_name, :class => "active_admin_comment_author") 10 | span(pretty_format(comment.created_at)) 11 | end 12 | div :class => "active_admin_comment_body" do 13 | simple_format(comment.body) 14 | end 15 | div :style => "clear:both;" 16 | div link_to "Edit comment", "/admin/active_admin_comments/#{comment.id}/edit" 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/ration.rb: -------------------------------------------------------------------------------- 1 | class Ration < ActiveRecord::Base 2 | belongs_to :user 3 | has_many :ingredients 4 | has_and_belongs_to_many :customers, :class_name => User 5 | attr_accessible :name, :description 6 | 7 | validate :name, :presence => true 8 | 9 | # we check if deleting ration currently selected in settings 10 | # if yes, then switch setting to default ration 11 | # assuming that user deleting his own ration 12 | before_destroy :check_setting 13 | 14 | def check_setting 15 | if self.user and self.user.setting(:ration).to_i == self.id 16 | Ration.set_setting_to_default(self.user) 17 | end 18 | end 19 | 20 | class << self 21 | def set_setting_to_default(user) 22 | user.setting_by_var("ration").update_attribute(:value, Ration.get_default.id) 23 | end 24 | 25 | def get_default 26 | Ration.find(1) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/models/dish_composition.rb: -------------------------------------------------------------------------------- 1 | class DishComposition < ActiveRecord::Base 2 | include Calorie 3 | attr_accessible :dish_id, :ingredient_id, :weight, :portions 4 | 5 | belongs_to :dish 6 | belongs_to :ingredient 7 | 8 | validates :ingredient_id, :presence => true 9 | 10 | before_save :calculate_portions_weight, :if => proc{ |i| i.ingredient.portion_unit == "item" } 11 | 12 | def portion_unit 13 | self.ingredient.portion_unit rescue nil 14 | end 15 | 16 | def calculate_portions_weight 17 | self.weight = self.ingredient.portion * self.portions 18 | end 19 | 20 | def proteins 21 | self.ingredient.calculate_nutrient_weight(:proteins, self.weight) 22 | end 23 | 24 | def fats 25 | self.ingredient.calculate_nutrient_weight(:fats, self.weight) 26 | end 27 | 28 | def carbs 29 | self.ingredient.calculate_nutrient_weight(:carbs, self.weight) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/views/admin/plans/_show_top.html.arb: -------------------------------------------------------------------------------- 1 | columns do 2 | column :min_width => "30%" do 3 | " ".html_safe 4 | end 5 | column :max_width => "8%" do 6 | strong "Weight" 7 | end 8 | [:proteins, :fats, :carbs].each do |n| 9 | column :max_width => "8%" do 10 | strong n.capitalize 11 | end 12 | end 13 | column :max_width => "8%" do 14 | strong "kCal" 15 | end 16 | 17 | column do 18 | end 19 | end 20 | 21 | render :partial => "total_target", :locals => { 22 | :totals => { 23 | :weight => s.total_weight.round(2), 24 | :proteins => s.total_nutrition(:proteins).round(2), 25 | :fats => s.total_nutrition(:fats).round(2), 26 | :carbs => s.total_nutrition(:carbs).round(2), 27 | :kcal => s.total_kcal.round(2) 28 | }, 29 | :targets => { 30 | :proteins => current_user.setting(:proteins), 31 | :fats => current_user.setting(:fats), 32 | :carbs => current_user.setting(:carbs) 33 | } 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/views/layouts/_disqus.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 13 | 14 | comments powered by Disqus 15 | 16 | -------------------------------------------------------------------------------- /app/views/admin/plans/_total_target.html.arb: -------------------------------------------------------------------------------- 1 | columns :class => "columns total" do 2 | column :min_width => "30%" do 3 | strong "Total", :style => "float: right;" 4 | end 5 | 6 | column :max_width => "8%" do 7 | strong totals[:weight] 8 | end 9 | 10 | [:proteins, :fats, :carbs].each do |n| 11 | column :max_width => "8%" do 12 | status_tag totals[n].to_s, (totals[n] > targets[n].to_i) ? :error : :ok 13 | end 14 | end 15 | 16 | column :max_width => "8%" do 17 | strong totals[:kcal] 18 | end 19 | 20 | column do 21 | end 22 | end 23 | 24 | columns :class => "columns" do 25 | column :min_width => "30%" do 26 | strong "Target", :style => "float: right;" 27 | end 28 | 29 | column :max_width => "8%" do 30 | " ".html_safe 31 | end 32 | 33 | [:proteins, :fats, :carbs].each do |n| 34 | column :max_width => "8%" do 35 | targets[n] 36 | end 37 | end 38 | 39 | column :max_width => "8%" do 40 | " ".html_safe 41 | end 42 | 43 | column do 44 | end 45 | end 46 | 47 | -------------------------------------------------------------------------------- /spec/requests/admin/diet_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Diets" do 4 | 5 | describe "Postable" do 6 | let(:user) { create(:user) } 7 | 8 | before(:each) do 9 | ration = create(:ration, :user => user) 10 | ration_setting = create(:setting, :var => "ration", :value => ration.id) 11 | user.settings << ration_setting 12 | login_as user 13 | end 14 | 15 | it "should work about diet" do 16 | diet = create(:diet, :user => user) 17 | 18 | visit admin_diets_path 19 | 20 | click_link diet.name 21 | click_link "Create post" 22 | 23 | page.should have_selector('h2', :text => "Edit Post") 24 | 25 | fill_in "Title", :with => "DDD" 26 | click_button "Update Post" 27 | 28 | within "span.action_item" do 29 | click_link "Diet" 30 | end 31 | 32 | click_link "Edit post" 33 | click_button "Update Post" 34 | click_link "Preview" 35 | 36 | page.should have_selector('h1', :text => "DDD") 37 | end 38 | 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /spec/requests/admin/plan_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Plan" do 4 | include DishHelper 5 | 6 | let(:user) { create(:user) } 7 | 8 | before(:each) do 9 | ration = create(:ration, :user => user) 10 | ration_setting = create(:setting, :var => "ration", :value => ration.id) 11 | user.settings << ration_setting 12 | login_as user 13 | end 14 | 15 | describe "Manage" do 16 | it "should add a dish" do 17 | plan = create(:plan, :user => user) 18 | dish = create_dish_user_ration(:dish, user) 19 | 20 | visit admin_plan_path(plan) 21 | 22 | page.should have_selector("h2#page_title", plan.name) 23 | within("div.panel h3", :match => :first) do 24 | click_link "Add" 25 | end 26 | 27 | page.should have_selector("h2#page_title", "New Plan Item") 28 | select(dish.name, :from => "Dish") 29 | click_button "Create Plan item" 30 | 31 | page.should have_selector("h2#page_title", plan.name) 32 | page.should have_selector("div.panel_contents a", dish.name) 33 | end 34 | 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /app/views/admin/plans/_show_meal.html.arb: -------------------------------------------------------------------------------- 1 | panel "#{m.name} (#{Meal.meal_time(m, current_user).strftime('%H:%M')}) #{Meal.meal_percents(m, s.meals_num)}% #{link_to("Add", new_admin_plan_plan_item_path(s, :meal_id => m), :style => "float: right;")}".html_safe do 2 | 3 | s.plan_items.where(:meal_id => m.id).each_with_index do |i, index| 4 | render :partial => "show_item", :locals => {:i => i, :index => index, :s => s} 5 | end 6 | 7 | render :partial => "total_target", :locals => { 8 | :totals => { 9 | :weight => s.meal_total_weight(m).round(2), 10 | :proteins => s.meal_total_nutrition(:proteins, m).round(2), 11 | :fats => s.meal_total_nutrition(:fats, m).round(2), 12 | :carbs => s.meal_total_nutrition(:carbs, m).round(2), 13 | :kcal => s.meal_total_kcal(m).round(2) 14 | }, 15 | :targets => { 16 | :proteins => Meal.meal_target(:proteins, m, current_user, s.meals_num), 17 | :fats => Meal.meal_target(:fats, m, current_user, s.meals_num), 18 | :carbs => Meal.meal_target(:carbs, m, current_user, s.meals_num) 19 | } 20 | } 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /spec/models/dish_composition_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DishComposition do 4 | describe "Associations" do 5 | it { should belong_to(:dish) } 6 | it { should belong_to(:ingredient) } 7 | end 8 | 9 | describe "Calculations" do 10 | let(:dish) { create(:dish) } 11 | let(:ingredient) { create(:ingredient, :portion_unit => "item", :portion => 55) } 12 | 13 | it "should calc weight for portion" do 14 | dc = DishComposition.new 15 | dc.dish = dish 16 | dc.ingredient = ingredient 17 | dc.portions = 3 18 | dc.weight = 100 19 | 20 | dc.save.should be_true 21 | 22 | dc.reload 23 | dc.weight.should eq 165 24 | end 25 | 26 | it "should not calc" do 27 | ingredient = create(:ingredient, :portion_unit => "gramm", :portion => 55) 28 | 29 | dc = DishComposition.new 30 | dc.dish = dish 31 | dc.ingredient = ingredient 32 | dc.portions = 3 33 | dc.weight = 100 34 | 35 | dc.save.should be_true 36 | 37 | dc.reload 38 | dc.weight.should eq 100 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/models/ingredient_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Ingredient do 4 | it "should calculate nutrient weight" do 5 | ingredient = create(:ingredient, :portion => 100, :portion_unit => "gramm", :proteins => 55) 6 | ingredient.calculate_nutrient_weight(:proteins, 180).should == 99 7 | end 8 | 9 | context "List" do 10 | it "should be for available rations" do 11 | first = create(:user) 12 | second = create(:user) 13 | 14 | own_ration = create(:ration, :user => first) 15 | shared_ration = create(:ration, :user => second) 16 | first.shared_rations << shared_ration 17 | alien_ration = create(:ration, :user => second) 18 | 19 | ingredient1 = create(:ingredient, :ration => own_ration) 20 | ingredient2 = create(:ingredient, :ration => shared_ration) 21 | ingredient3 = create(:ingredient, :ration => alien_ration) 22 | 23 | list = Ingredient.by_available_rations(first) 24 | 25 | list.should include(ingredient1) 26 | list.should include(ingredient2) 27 | list.should_not include(ingredient3) 28 | end 29 | 30 | 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/admin/select_ingredient.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Ingredient, :as => "SelectIngredient" do 2 | 3 | belongs_to :ration 4 | config.batch_actions = false 5 | config.clear_action_items! 6 | actions :index 7 | 8 | filter :name 9 | filter :group, :as => :select, :collection => IngredientGroup.all 10 | filter :proteins 11 | filter :fats 12 | filter :carbs 13 | 14 | index :title => "Select ingredient" do 15 | div link_to("Return to start", session[:ingredient_referer]) 16 | 17 | column :name do |c| 18 | link_to c.name, copy_to_my_admin_ingredient_path(c, :redirect => "edit_selected"), :method => :post 19 | end 20 | column :group do |c| 21 | c.group.name rescue nil 22 | end 23 | column :portion do |p| 24 | portion_caption(p) 25 | end 26 | column :proteins 27 | column :fats 28 | column :carbs 29 | column :kcal 30 | end 31 | 32 | controller do 33 | 34 | def scoped_collection 35 | if params[:ration_id] 36 | Ingredient.by_ration params[:ration_id] 37 | else 38 | current_user.all_ingredients 39 | end 40 | end 41 | 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /app/models/admin_ability.rb: -------------------------------------------------------------------------------- 1 | # All back end users (i.e. Active Admin users) are authorized using this class 2 | class AdminAbility 3 | include CanCan::Ability 4 | 5 | def initialize(user) 6 | user ||= User.new 7 | alias_action :read, :new, :create, :edit, :update, :destroy, :copy, :to => :change 8 | alias_action :read, :create, :to => :read_create 9 | 10 | can :read, ActiveAdmin::Page, :name => "Dashboard" 11 | can :manage, Diet 12 | can :manage, Plan 13 | can :manage, PlanItem 14 | can :manage, PlanItemIngredient 15 | can :manage, Dish 16 | can :manage, Eaten 17 | 18 | #can :read, Ingredient 19 | #can :change, Ingredient, :ration => {:user_id => user.id} 20 | can :manage, Ingredient 21 | 22 | can :manage, ActiveAdmin::Page, :name => "Settings" 23 | can :manage, Ration 24 | can [:change, :preview, :preview_short], Post, :user_id => user.id 25 | 26 | # A super_admin can do the following: 27 | if user.has_role? 'admin' 28 | can :manage, :all 29 | can :manage, User 30 | can :manage, Role 31 | can :manage, ActiveAdmin::Comment 32 | 33 | end 34 | 35 | end 36 | end 37 | 38 | -------------------------------------------------------------------------------- /config/default_settings.yml: -------------------------------------------------------------------------------- 1 | ration: 2 | var: ration 3 | title: Current Ration 4 | description: Your current ration 5 | value: 0 6 | hidden: true 7 | 8 | height: 9 | var: height 10 | title: Height 11 | description: You height in sm 12 | value: 180 13 | hidden: false 14 | 15 | weight: 16 | var: weight 17 | title: Weight 18 | description: Your weight in kg 19 | value: 80 20 | hidden: false 21 | 22 | proteins: 23 | var: proteins 24 | title: Proteins 25 | description: Proteins per day in grams (2g per kg) 26 | value: 160.0 27 | hidden: false 28 | 29 | fats: 30 | var: fats 31 | title: Fats 32 | description: Fats per day in grams (0.5g per kg) 33 | value: 40.0 34 | hidden: false 35 | 36 | carbs: 37 | var: carbs 38 | title: Carbohydrates 39 | description: Carbs per day in grams (4g per kg) 40 | value: 320.0 41 | hidden: false 42 | 43 | meals: 44 | var: meals 45 | title: Meals 46 | description: Number of meals per day 47 | value: 4 48 | hidden: true 49 | 50 | breakfast_time: 51 | var: breakfast_time 52 | title: "Breakfast time" 53 | description: Time your first meal start 54 | value: "8:00" 55 | hidden: false 56 | -------------------------------------------------------------------------------- /config/initializers/ckeditor.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure ckeditor 2 | Ckeditor.setup do |config| 3 | # ==> ORM configuration 4 | # Load and configure the ORM. Supports :active_record (default), :mongo_mapper and 5 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 6 | # available as additional gems. 7 | require "ckeditor/orm/active_record" 8 | 9 | # Allowed image file types for upload. 10 | # Set to nil or [] (empty array) for all file types 11 | # config.image_file_types = ["jpg", "jpeg", "png", "gif", "tiff"] 12 | 13 | # Allowed attachment file types for upload. 14 | # Set to nil or [] (empty array) for all file types 15 | # config.attachment_file_types = ["doc", "docx", "xls", "odt", "ods", "pdf", "rar", "zip", "tar", "swf"] 16 | 17 | # Setup authorization to be run as a before filter 18 | config.authorize_with :cancan 19 | end 20 | 21 | Ckeditor::PicturesController.class_eval do 22 | 23 | def index 24 | 25 | @pictures = Ckeditor.picture_adapter.find_all(ckeditor_pictures_scope(:assetable => ckeditor_current_user)) 26 | @pictures = Ckeditor::Paginatable.new(@pictures).page(params[:page]) 27 | 28 | respond_with(@pictures, :layout => @pictures.first_page?) 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /app/uploaders/ckeditor_attachment_file_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | class CkeditorAttachmentFileUploader < CarrierWave::Uploader::Base 3 | include Ckeditor::Backend::CarrierWave 4 | 5 | # Include RMagick or ImageScience support: 6 | # include CarrierWave::RMagick 7 | # include CarrierWave::MiniMagick 8 | # include CarrierWave::ImageScience 9 | 10 | # Choose what kind of storage to use for this uploader: 11 | storage :file #:fog 12 | 13 | # Override the directory where uploaded files will be stored. 14 | # This is a sensible default for uploaders that are meant to be mounted: 15 | def store_dir 16 | "uploads/ckeditor/attachments/#{model.id}" 17 | end 18 | 19 | # Provide a default URL as a default if there hasn't been a file uploaded: 20 | # def default_url 21 | # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 22 | # end 23 | 24 | # Process files as they are uploaded: 25 | # process :scale => [200, 300] 26 | # 27 | # def scale(width, height) 28 | # # do something 29 | # end 30 | 31 | # Add a white list of extensions which are allowed to be uploaded. 32 | # For images you might use something like this: 33 | def extension_white_list 34 | Ckeditor.attachment_file_types 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/tasks/import.rake: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'rake/packagetask' 3 | 4 | namespace :import do 5 | 6 | desc "Imports default ingredients from given CSV file" 7 | task(:ingredients => :environment) do 8 | require 'csv' 9 | 10 | ration = Ration.get_default 11 | groups = {} 12 | CSV.parse(File.open("#{Rails.root}/lib/assets/racion_only.csv", 'rb')) do |row| 13 | name = row[0] 14 | name = name.force_encoding("UTF-8") 15 | 16 | portion = row[1] 17 | proteins = row[2] 18 | fats = row[3] 19 | carbs = row[4] 20 | 21 | group = row[6] 22 | group = group.force_encoding("UTF-8").mb_chars.capitalize 23 | 24 | unless groups.include? group 25 | ingroup = IngredientGroup.find_or_create_by_name(group) 26 | groups[group] = ingroup.id 27 | end 28 | 29 | puts "#{group}. #{name} - #{proteins}, #{fats}, #{carbs}" 30 | 31 | ing = Ingredient.new 32 | ing.user = ration.user 33 | ing.ration = ration 34 | ing.ingredient_group_id = groups[group] 35 | ing.name = name 36 | ing.portion = portion 37 | ing.portion_unit = 'gramm' 38 | ing.proteins = proteins 39 | ing.fats = fats 40 | ing.carbs = carbs 41 | ing.save! 42 | 43 | end 44 | end 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(:default, Rails.env) 8 | 9 | module Mealness 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | 15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 17 | # config.time_zone = 'Central Time (US & Canada)' 18 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 21 | # config.i18n.default_locale = :de 22 | 23 | config.encoding = "utf-8" 24 | #I18n.enforce_available_locales = false 25 | 26 | config.i18n.enforce_available_locales = true 27 | config.i18n.default_locale = :ru 28 | config.assets.paths << "#{Rails}/vendor/assets/fonts" 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Mealness::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | config.action_mailer.default_url_options = { :host => 'localhost:3000' } 31 | end 32 | -------------------------------------------------------------------------------- /spec/factories/dishes.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :dish do 3 | sequence(:name) { |n| "Dish_#{n}" } 4 | dish_compositions { [ 5 | create(:dish_composition, :ingredient => create(:ingredient_empty)) 6 | ] } 7 | 8 | factory :dish_schema_a do 9 | dish_compositions { [ 10 | create(:dish_composition_schema_a1, :ingredient => create(:ingredient_schema_a1)), 11 | create(:dish_composition_schema_a2, :ingredient => create(:ingredient_schema_a2)) 12 | ] } 13 | end 14 | 15 | factory :dish_sample do 16 | dish_compositions { [ 17 | create(:dish_composition, :ingredient => create(:ingredient, :proteins => 19.25, :fats => 30.25, :carbs => 41.25), :weight => 200) 18 | ] } 19 | name "Dish_sample" 20 | weight "200" 21 | proteins "38.5" 22 | fats "60.5" 23 | carbs "82.5" 24 | end 25 | 26 | factory :flakes do 27 | name "Flakes" 28 | weight "95" 29 | proteins "7.06" 30 | fats "1.975" 31 | carbs "61.825" 32 | 33 | #dish_compositions { [ 34 | #create(:dish_composition, :weight => 80, :ingredient => create(:nestle_fitness)), 35 | #create(:dish_composition, :weight => 15, :ingredient => create(:milk)) 36 | #] } 37 | 38 | end 39 | 40 | factory :omelet do 41 | name "Omelet" 42 | weight "91" 43 | proteins "11.557" 44 | fats "0.273" 45 | carbs "0.637" 46 | end 47 | end 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /spec/models/ration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Ration do 4 | let(:user) { create(:user) } 5 | 6 | describe "Associations" do 7 | it { should have_many(:ingredients) } 8 | it { should have_and_belong_to_many(:customers) } 9 | 10 | end 11 | 12 | it "should create new" do 13 | ration = Ration.new(:name => "Common", :description => "Test") 14 | ration.user = user 15 | ration.save 16 | 17 | ration.reload 18 | ration.name.should == "Common" 19 | ration.user.should == user 20 | end 21 | 22 | it "should have customer" do 23 | ration = create(:ration) 24 | customer = create(:user) 25 | ration.customers << customer 26 | 27 | ration.customers.first.should == customer 28 | end 29 | 30 | it "should set setting to default" do 31 | user = create(:user) 32 | ration = create(:ration, :user => user) 33 | ration_setting = create(:setting, :var => "ration", :value => ration.id) 34 | user.settings << ration_setting 35 | 36 | expect { Ration.set_setting_to_default(user) }.to change{user.setting(:ration)}.from(ration.id.to_s).to(1) 37 | end 38 | 39 | it "should set setting when delete" do 40 | user = create(:user) 41 | ration_2 = create(:ration, :user => user) 42 | ration_setting = create(:setting, :var => "ration", :value => ration_2.id) 43 | user.settings << ration_setting 44 | 45 | expect{ ration_2.destroy }.to change{user.setting(:ration)}.to(1) 46 | end 47 | 48 | 49 | end 50 | -------------------------------------------------------------------------------- /app/uploaders/ckeditor_picture_uploader.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | class CkeditorPictureUploader < CarrierWave::Uploader::Base 3 | include Ckeditor::Backend::CarrierWave 4 | 5 | # Include RMagick or ImageScience support: 6 | # include CarrierWave::RMagick 7 | include CarrierWave::MiniMagick 8 | # include CarrierWave::ImageScience 9 | 10 | # Choose what kind of storage to use for this uploader: 11 | storage :file #:fog 12 | 13 | # Override the directory where uploaded files will be stored. 14 | # This is a sensible default for uploaders that are meant to be mounted: 15 | def store_dir 16 | "uploads/ckeditor/pictures/#{model.id}" 17 | end 18 | 19 | # Provide a default URL as a default if there hasn't been a file uploaded: 20 | # def default_url 21 | # "/images/fallback/" + [version_name, "default.png"].compact.join('_') 22 | # end 23 | 24 | # Process files as they are uploaded: 25 | # process :scale => [200, 300] 26 | # 27 | # def scale(width, height) 28 | # # do something 29 | # end 30 | 31 | process :read_dimensions 32 | 33 | # Create different versions of your uploaded files: 34 | version :thumb do 35 | process :resize_to_fill => [118, 100] 36 | end 37 | 38 | version :content do 39 | process :resize_to_limit => [800, 800] 40 | end 41 | 42 | # Add a white list of extensions which are allowed to be uploaded. 43 | # For images you might use something like this: 44 | def extension_white_list 45 | Ckeditor.image_file_types 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

We're sorry, but something went wrong.

54 |
55 |

If you are the application owner check the logs for more information.

56 | 57 | 58 | -------------------------------------------------------------------------------- /lib/active_admin/post_action.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module PostAction 3 | 4 | def self.included(base) 5 | 6 | base.instance_eval do 7 | resource_name = self.config.resource_class.name.split('::').last.downcase 8 | 9 | member_action "post_#{resource_name}".to_sym, :method => :post do 10 | if resource.post 11 | redirect_to admin_post_path(resource.post) and return 12 | end 13 | 14 | post = @blog.new_post(resource) 15 | if post.save 16 | redirect_to edit_admin_post_path(post), :notice => "Post created." 17 | else 18 | redirect_to eval("admin_#{resource_name}_path(resource)"), :alert => "Post NOT created. #{post.errors.full_messages}" 19 | end 20 | end 21 | 22 | end 23 | 24 | end # self.included 25 | 26 | def self.new_path(name) 27 | "post_#{name}_admin_#{name}_path" 28 | end 29 | 30 | 31 | end 32 | 33 | module ActiveAdmin::ViewsHelper 34 | 35 | def post_action_link(resource) 36 | resource_name = resource.class.name.downcase 37 | 38 | if resource.post 39 | link_to I18n.t("links.edit_post", :default => "Edit post"), edit_admin_post_path(resource.post) 40 | else 41 | link_to I18n.t("links.create_post", :default => "Create post"), eval("#{ActiveAdmin::PostAction.new_path(resource_name)}(resource)"), :method => :post, :data => {:confirm => I18n.t("links.confirm_publish")} 42 | end 43 | end 44 | 45 | end 46 | 47 | 48 | 49 | 50 | end 51 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The change you wanted was rejected.

54 |

Maybe you tried to change something you didn't have access to.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 48 | 49 | 50 | 51 | 52 |
53 |

The page you were looking for doesn't exist.

54 |

You may have mistyped the address or the page may have moved.

55 |
56 |

If you are the application owner check the logs for more information.

57 | 58 | 59 | -------------------------------------------------------------------------------- /app/admin/plans.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Plan do 2 | config.batch_actions = false 3 | menu :priority => 3, :parent => I18n.t("menu.food") 4 | scope_to :current_user, :association_method => :all_plans 5 | 6 | filter :name 7 | filter :created_at 8 | 9 | action_item :only => :show do 10 | html = '' 11 | html += link_to "Copy", copy_admin_plan_path(plan), :method => :post 12 | html += link_to "Auto weights", auto_weights_admin_plan_path(plan), :method => :post, :data => {:confirm => "Are you sure?"} 13 | html.html_safe 14 | end 15 | 16 | member_action :copy, :method => :post do 17 | @plan = current_user.plans.find(params[:id]) 18 | @new_plan, message = @plan.do_copy 19 | 20 | if @new_plan 21 | redirect_to admin_plan_path(@new_plan), :notice => "Plan copied" 22 | else 23 | redirect_to amdin_plan_path(@plan), :alert => "Plan NOT copied: #{message}" 24 | end 25 | end 26 | 27 | member_action :auto_weights, :method => :post do 28 | @plan = Plan.find(params[:id]) 29 | @plan.auto_weights! 30 | 31 | redirect_to admin_plan_path(@plan), :notice => "Weigths auto calculated!" 32 | end 33 | 34 | show do |s| 35 | render :partial => "show_top", :locals => {:s => s} 36 | 37 | Meal.find_for(s.meals_num).each do |m| 38 | render :partial => "show_meal", :locals => {:m => m, :current_user => current_user, :s => s} 39 | end 40 | end 41 | 42 | form do |f| 43 | f.inputs do 44 | f.input :name 45 | f.input :meals_num, :as => :select, :collection => (1...8) 46 | f.input :description 47 | end 48 | 49 | f.actions 50 | end 51 | 52 | end 53 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin_utils.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $('#ingredient_text').railsAutocomplete({ 3 | select: function( event, ui ) { 4 | $( "#ingredient_text" ).val( ui.item.title ); 5 | $( "#ingredient_id" ).val( ui.item.id ); 6 | } 7 | }); 8 | 9 | $('#edit_dish, #new_dish').on("change", ".dish_ingredient_select", function() { 10 | var num = $(this).parents("li[id^='dish_dish_compositions_attributes']").attr('id').match(/[0-9]+/); 11 | toggle_dish_ingredient($(this), num); 12 | }); 13 | 14 | $('#new_dish, #edit_dish').on("click", ".new_ingredient", function() { 15 | //alert($(this).attr('id')); 16 | var f = $(this).parents("form"); 17 | f.find('input[name=_method]').remove(); 18 | f.attr('action', "/admin/dishes/ingredients/new"); 19 | f.submit(); 20 | 21 | return false; 22 | }); 23 | 24 | 25 | 26 | }); 27 | 28 | // FUNCTIONS 29 | function switch_dish_ingredients() { 30 | $('#new_dish,#edit_dish div.dish_compositions select[id^=\'dish_dish_compositions_attributes\']').each(function() { 31 | var num = $(this).attr('id').match(/[0-9]+/); 32 | toggle_dish_ingredient($(this), num); 33 | }); 34 | } 35 | 36 | function toggle_dish_ingredient(selem, num) { 37 | var pu = $('option:selected', selem).attr('pu'); 38 | 39 | if(pu == 'gramm') { 40 | $("#dish_dish_compositions_attributes_"+ num + "_portions_input").hide(); 41 | $("#dish_dish_compositions_attributes_"+ num + "_weight_input").show(); 42 | } 43 | 44 | if(pu == 'item') { 45 | $("#dish_dish_compositions_attributes_"+ num + "_portions_input").show(); 46 | $("#dish_dish_compositions_attributes_"+ num + "_weight_input").hide(); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | include ActiveAdmin::ViewsHelper 3 | include ISO8601 4 | 5 | def duration_iso8601(value) 6 | (Duration.new(value.to_i) + Duration.new(0)).to_s 7 | end 8 | 9 | def duration_localed(value) 10 | return 0 unless value.to_i > 0 11 | 12 | res = nil 13 | durations_array(600).map{ |a| res = a[0] if a[1] == value } 14 | res 15 | end 16 | 17 | def published_datetime(post) 18 | html = '' 19 | html += content_tag :span, "", :class => "glyphicon glyphicon-time" 20 | html += " #{I18n.t(:published)} " 21 | 22 | publish_date = post.published_at.presence || ::Time.now 23 | html += content_tag :time, l(publish_date, :format => :long), :datetime => publish_date.to_s(:db), :itemprop => "published" 24 | 25 | html.html_safe 26 | end 27 | 28 | def plan_item_quantity(item) 29 | if item.plan_item_ingredients.count == 1 30 | pi = item.plan_item_ingredients[0] 31 | if pi.ingredient.portion_unit == "item" 32 | res = "#{nice_float(pi.portion)} #{I18n.t("item_abbr")}" 33 | else 34 | res = "#{nice_float(pi.weight)} #{I18n.t("gramm_abbr")}" 35 | end 36 | else 37 | res = "#{nice_float(item.weight)} #{I18n.t("gramm_abbr")}" 38 | end 39 | res.html_safe 40 | end 41 | 42 | def ingredient_quantity(ingredient) 43 | if ingredient.portion_unit == "item" 44 | res = "#{nice_float(ingredient.portions)} #{I18n.t("item_abbr")}" 45 | else 46 | res = "#{nice_float(ingredient.weight)} #{I18n.t("gramm_abbr")}" 47 | end 48 | res.html_safe 49 | end 50 | 51 | def nice_float(float) 52 | (float == float.floor) ? float.to_i : float.round(2) 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/factories/ingredients.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :ingredient do 3 | ration { Ration.find_by_id(1) || create(:ration, :id => 1)} 4 | 5 | sequence(:name) { |n| "Ingredient_#{n}" } 6 | portion { 100 } 7 | portion_unit "gramm" 8 | proteins { rand(100) } 9 | fats { rand(100) } 10 | carbs { rand(100) } 11 | 12 | factory :ingredient_schema_a1 do 13 | proteins "11" 14 | fats "22" 15 | carbs "33" 16 | end 17 | 18 | factory :ingredient_schema_a2 do 19 | proteins "44" 20 | fats "55" 21 | carbs "66" 22 | end 23 | 24 | factory :ingredient_sample do 25 | proteins "38.5" 26 | fats "60.5" 27 | carbs "82.5" 28 | end 29 | 30 | factory :nestle_fitness do 31 | name "Nestle Fitness" 32 | proteins "8.3" 33 | fats "2.0" 34 | carbs "76.4" 35 | end 36 | 37 | factory :milk do 38 | name "Milk 2.5" 39 | proteins "2.8" 40 | fats "2.5" 41 | carbs "4.7" 42 | end 43 | 44 | factory :glair do 45 | name "Glair" 46 | proteins "12.7" 47 | fats "0.3" 48 | carbs "0.7" 49 | end 50 | 51 | factory :salt do 52 | name "Salt" 53 | proteins "0" 54 | fats "0" 55 | carbs "0" 56 | end 57 | 58 | factory :cheese do 59 | name "Cheese" 60 | proteins "23.2" 61 | fats "29.5" 62 | carbs "0" 63 | end 64 | 65 | factory :sugar do 66 | name "Sugar" 67 | proteins "0" 68 | fats "0" 69 | carbs "99.9" 70 | end 71 | 72 | factory :ingredient_empty do 73 | name "Empty" 74 | proteins "0" 75 | fats "0" 76 | carbs "0" 77 | end 78 | 79 | 80 | end 81 | end 82 | 83 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Mealness::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_assets = true 17 | config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | 37 | config.i18n.default_locale = :en 38 | end 39 | -------------------------------------------------------------------------------- /db/migrate/20130930230513_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def migrate(direction) 3 | super 4 | # Create a default user 5 | User.create!(:email => 'admin@example.com', :password => 'password', :password_confirmation => 'password') if direction == :up 6 | end 7 | 8 | def change 9 | create_table(:users) do |t| 10 | ## Database authenticatable 11 | t.string :email, :null => false, :default => "" 12 | t.string :encrypted_password, :null => false, :default => "" 13 | 14 | ## Recoverable 15 | t.string :reset_password_token 16 | t.datetime :reset_password_sent_at 17 | 18 | ## Rememberable 19 | t.datetime :remember_created_at 20 | 21 | ## Trackable 22 | t.integer :sign_in_count, :default => 0, :null => false 23 | t.datetime :current_sign_in_at 24 | t.datetime :last_sign_in_at 25 | t.string :current_sign_in_ip 26 | t.string :last_sign_in_ip 27 | 28 | ## Confirmable 29 | # t.string :confirmation_token 30 | # t.datetime :confirmed_at 31 | # t.datetime :confirmation_sent_at 32 | # t.string :unconfirmed_email # Only if using reconfirmable 33 | 34 | ## Lockable 35 | # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts 36 | # t.string :unlock_token # Only if unlock strategy is :email or :both 37 | # t.datetime :locked_at 38 | 39 | 40 | t.timestamps 41 | end 42 | 43 | add_index :users, :email, :unique => true 44 | add_index :users, :reset_password_token, :unique => true 45 | # add_index :users, :confirmation_token, :unique => true 46 | # add_index :users, :unlock_token, :unique => true 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /app/admin/eatens.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Eaten do 2 | config.batch_actions = false 3 | menu :priority => 20, :parent => I18n.t("menu.diary") 4 | scope_to :current_user 5 | #config.clear_action_items! 6 | 7 | # step 1 8 | collection_action :select_type, :method => :get, :title => I18n.t("titles.select_type") do 9 | render :template => "admin/eatens/select_type", :locals => {:ingredients => current_user.all_ingredients.limit(10)} 10 | end 11 | 12 | collection_action :select_ingredient, :method => :get, :title => I18n.t("titles.select_ingredient") do 13 | render :template => "admin/eatens/select_ingredient" 14 | end 15 | 16 | filter :eatable_type 17 | filter :proteins 18 | filter :fats 19 | filter :carbs 20 | filter :created_at 21 | 22 | index do 23 | #selectable_column 24 | 25 | column :eatable 26 | column :weight 27 | column("Proteins") { |c| c.proteins.round(2) } 28 | column("Fats") { |c| c.fats.round(2) } 29 | column("Carbs") { |c| c.carbs.round(2) } 30 | column :kcal 31 | column :created_at 32 | 33 | default_actions 34 | end 35 | 36 | #form :partial => "form" 37 | form do |f| 38 | f.inputs "#{f.object.eatable.class.model_name.human} '#{f.object.eatable.name}'" do 39 | f.input :weight 40 | f.input :eatable_id, :as => :hidden 41 | f.input :eatable_type, :as => :hidden 42 | end 43 | f.actions 44 | end 45 | 46 | controller do 47 | def new 48 | new! do |format| 49 | if params[:dish_id].present? 50 | @eated = Dish.find(params[:dish_id]) 51 | elsif params[:ingredient_id].present? 52 | @eated = Ingredient.find(params[:ingredient_id]) 53 | else 54 | redirect_to admin_eatens_path, :alert => "Please select what to eat" 55 | return 56 | end 57 | @eaten.eatable = @eated 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/admin/rations.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Ration do 2 | menu :priority => 6, :parent => I18n.t("menu.food") 3 | config.batch_actions = false 4 | scope_to :current_user, :association_method => :all_rations 5 | 6 | before_create do |ration| 7 | ration.user = current_user 8 | end 9 | 10 | filter :name 11 | filter :created_at 12 | 13 | member_action :ingredients_list, :method => :get do 14 | collection = resource.ingredients.page(params[:page]) 15 | render :template => "admin/rations/ingredients", :locals => {:ingredients => collection } 16 | end 17 | 18 | index do 19 | #selectable_column 20 | #column :id 21 | column :name do |c| 22 | auto_link(c, c.name) 23 | end 24 | column :description 25 | column :ingredients do |c| 26 | #link_to c.ingredients.count, admin_rationingredients_path(:ration_id => c.id) 27 | link_to c.ingredients.count, admin_ration_ingredients_path(:ration_id => c.id) 28 | end 29 | column :updated_at 30 | 31 | column "" do |resource| 32 | links = "".html_safe 33 | if current_user.id == resource.user.id 34 | links += link_to I18n.t('active_admin.edit'), edit_resource_path(resource), :class => "member_link edit_link" 35 | links += link_to I18n.t('active_admin.delete'), resource_path(resource), :method => :delete, :data => {:confirm => I18n.t('active_admin.delete_confirmation')}, :class => "member_link delete_link" 36 | links += current_user.setting(:ration).to_i == resource.id ? "Current " : link_to("Choose", admin_settings_update_path(:var => "ration", :value => resource.id, :ref => admin_rations_path), :method => :post, :class => "member_link") 37 | end 38 | 39 | links 40 | end 41 | end 42 | 43 | 44 | form do |f| 45 | f.inputs do 46 | f.input :name 47 | f.input :description 48 | end 49 | 50 | f.actions 51 | end 52 | 53 | controller do 54 | end 55 | 56 | 57 | end 58 | 59 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin.css.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | body.active_admin { 15 | form { 16 | input[type="text"][size], 17 | input[type="number"][size] { 18 | width: auto; 19 | } 20 | } 21 | } 22 | 23 | // Overriding any non-variable SASS must be done after the fact. 24 | // For example, to change the default status-tag color: 25 | // 26 | // .status_tag { background: #6090DB; } 27 | 28 | //.even div { background: $table-stripe-color; } 29 | .even { background: darken($table-stripe-color, 3%); } 30 | .small_i { 31 | font-size: 0.8em; 32 | font-style: italic; 33 | margin-bottom: 0px; 34 | } 35 | 36 | .total { 37 | border-top: 1px solid #e8e8e8; 38 | margin-top: 10px; 39 | } 40 | 41 | .cke_chrome { 42 | width: 76% !important; 43 | overflow: hidden; 44 | } 45 | 46 | .big_link .panel_contents { 47 | text-align: center; 48 | font-size: 2em; 49 | 50 | } 51 | 52 | .ui-autocomplete{ 53 | width: 245px; 54 | border: 1px solid #c9d0d6; 55 | background-color: #fff; 56 | list-style-type: none; 57 | margin: 0; 58 | padding: 0; 59 | //@include border-radius(3px ); 60 | li{ 61 | a{ 62 | text-decoration: none; 63 | display: block; 64 | padding: 5px 10px; 65 | &.ui-state-focus{ 66 | background-color: #f4f4f4; 67 | padding: 5px 10px; 68 | } 69 | } 70 | } 71 | } 72 | .ui-helper-hidden-accessible { 73 | border: 0; 74 | clip: rect(0 0 0 0); 75 | height: 1px; 76 | margin: -1px; 77 | overflow: hidden; 78 | padding: 0; 79 | position: absolute; 80 | width: 1px; 81 | } 82 | -------------------------------------------------------------------------------- /app/views/home/_diet.html.erb: -------------------------------------------------------------------------------- 1 | <% @diet = entry -%> 2 | 3 |

<%= @post.title.html_safe %>

4 | 5 |

от admin

6 |
7 |

<%= published_datetime(@post) %>

8 |
9 | 10 |
11 | <%= @diet.description.try(:html_safe) %> 12 |
13 |

14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | <% @diet.diet_items.each_with_index do |item, index| -%> 27 | <% Meal.find_for(item.plan.meals_num).each_with_index do |m, index2| -%> 28 | <% item.plan.plan_items.where(:meal_id => m.id).each_with_index do |i, index3| -%> 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | <% end -%> 40 | <% end -%> 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | <% end -%> 54 | 55 |
БелкиЖирыУглеводыКкал
<%= "День #{index + 1}".html_safe if index2 == 0 and index3 == 0 %><%= "#{I18n.t(m.key.to_sym)}".html_safe if index3 == 0 %><%= i.eatable.name %><%= plan_item_quantity(i) %><%= nice_float(i.calculate_nutrient_weight(:proteins, i.weight)) %><%= nice_float i.calculate_nutrient_weight(:fats, i.weight) %><%= nice_float i.calculate_nutrient_weight(:carbs, i.weight) %><%= nice_float i.calculate_kcal_weight(i.weight) %>
<%= item.plan.total_nutrition(:proteins) %><%= item.plan.total_nutrition(:fats) %><%= item.plan.total_nutrition(:carbs) %><%= item.plan.total_kcal %>
56 |

57 |
58 | 59 | <%= render :partial => "layouts/disqus" %> 60 |
61 | -------------------------------------------------------------------------------- /app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | 3 | menu :priority => 1, :label => proc{ I18n.t("active_admin.dashboard") } 4 | 5 | content :title => proc{ I18n.t("active_admin.dashboard") } do 6 | div :style => "text-align: center; margin: 1em;" do 7 | span :style => "margin-right: 3em; font-size: 1.5em" do 8 | link_to "<<", admin_dashboard_path(:d => params_day_date - 1.day) 9 | end 10 | span :style => "font-size: 3em;" do 11 | params_day_date 12 | end 13 | span :style => "margin-left: 3em; font-size: 1.5em" do 14 | link_to ">>", admin_dashboard_path(:d => params_day_date + 1.day) 15 | end 16 | end 17 | 18 | #div :class => "blank_slate_container", :id => "dashboard_default_message" do 19 | #span :class => "blank_slate" do 20 | #span I18n.t("active_admin.dashboard_welcome.welcome") 21 | #small I18n.t("active_admin.dashboard_welcome.call_to_action") 22 | #end 23 | #end 24 | 25 | columns do 26 | column do 27 | panel "Eated #{link_to("Add", select_type_admin_eatens_path, :style => "float: right;")}".html_safe do 28 | table_for current_user.eatens.find_day(params[:d]) do 29 | column("Name") {|e| link_to e.eatable.name, admin_eaten_path(e)} 30 | column("Proteins") {|e| e.proteins.round(2)} 31 | column("Fats") {|e| e.fats.round(2)} 32 | column("Carbs") {|e| e.carbs.round(2)} 33 | column("At") {|e| e.updated_at.to_s(:short)} 34 | end 35 | end 36 | end 37 | 38 | column do 39 | panel "Info" do 40 | para "Proteins: #{current_user.eatens.find_day(params[:d]).sum(:proteins).round(2)} (#{current_user.setting(:proteins)})" 41 | para "Fats: #{current_user.eatens.find_day(params[:d]).sum(:fats).round(2)} (#{current_user.setting(:fats)})" 42 | para "Carbs: #{current_user.eatens.find_day(params[:d]).sum(:carbs).round(2)} (#{current_user.setting(:carbs)})" 43 | end 44 | end 45 | end 46 | end # content 47 | end 48 | -------------------------------------------------------------------------------- /app/views/admin/plans/_show_item.html.arb: -------------------------------------------------------------------------------- 1 | columns :class => "columns #{(index % 2 > 0) ? "even" : "odd"}" do 2 | column :min_width => "30%" do 3 | span auto_link(i, i.eatable.name) 4 | end 5 | 6 | column :max_width => "8%" do 7 | span i.weight.round(2) 8 | end 9 | 10 | [:proteins, :fats, :carbs].each do |n| 11 | column :max_width => "8%" do 12 | i.calculate_nutrient_weight(n, i.weight).round(2) 13 | end 14 | end 15 | 16 | column :max_width => "8%" do 17 | i.calculate_kcal_weight(i.weight).round(2) 18 | end 19 | 20 | column do 21 | link_to(I18n.t('active_admin.edit'), edit_admin_plan_plan_item_path(s, i)) + " | " + 22 | link_to(I18n.t('active_admin.delete'), admin_plan_plan_item_path(s, i), :method => :delete, :data => {:confirm => I18n.t('active_admin.delete_confirmation')}, :class => "member_link delete_link") 23 | end 24 | 25 | end 26 | 27 | i.plan_item_ingredients.each do |pi| 28 | columns :class => "small_i columns #{(index % 2 > 0) ? "even" : "odd"}" do 29 | column :min_width => "30%" do 30 | span pi.ingredient.name 31 | end 32 | 33 | column :max_width => "8%" do 34 | span do 35 | if pi.ingredient.portion_unit == "item" 36 | "#{pi.portion.round(2)} items" 37 | else 38 | "#{pi.weight.round(2)} g" 39 | end 40 | end 41 | end 42 | 43 | [:proteins, :fats, :carbs].each do |n| 44 | column :max_width => "8%" do 45 | span pi.ingredient.calculate_nutrient_weight(n, pi.weight).round(2) 46 | end 47 | end 48 | 49 | column :max_width => "8%" do 50 | span pi.ingredient.calculate_kcal_weight(pi.weight) 51 | end 52 | 53 | column do 54 | link_to(I18n.t('active_admin.edit'), edit_admin_plan_item_plan_item_ingredient_path(i, pi)) + " | " + 55 | link_to(I18n.t('active_admin.delete'), admin_plan_item_plan_item_ingredient_path(i, pi), :method => :delete, :data => {:confirm => I18n.t('active_admin.delete_confirmation')}, :class => "member_link delete_link") 56 | end 57 | 58 | end 59 | end 60 | span " ".html_safe 61 | 62 | -------------------------------------------------------------------------------- /app/admin/diets.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/post_action' 2 | 3 | ActiveAdmin.register Diet do 4 | include ActiveAdmin::PostAction 5 | 6 | config.batch_actions = false 7 | menu :priority => 2, :parent => I18n.t("menu.food") 8 | scope_to :current_user, :association_method => :all_diets 9 | 10 | index do 11 | column :id 12 | column :name do |c| 13 | auto_link c, c.name 14 | end 15 | column :description do |c| 16 | truncate c.description, :length => 60 17 | end 18 | column :user if current_user.admin? 19 | column :published_at 20 | column :updated_at 21 | 22 | default_actions 23 | end 24 | 25 | action_item :only => [:show] do 26 | links = '' 27 | links += post_action_link(resource) 28 | links.html_safe 29 | end 30 | 31 | show do |d| 32 | attributes_table do 33 | row :name 34 | row :user do |r| 35 | auto_link r.user, r.user.email 36 | end if current_user.admin? 37 | row :description 38 | row :created_at 39 | row :updated_at 40 | row :published_at 41 | end 42 | 43 | panel "Day plans" do 44 | table_for diet.diet_items do 45 | column "name" do |appointment| 46 | auto_link(appointment.plan, appointment.plan.name) 47 | end 48 | [:proteins, :fats, :carbs].each do |n| 49 | column n do |c| 50 | c.plan.total_nutrition(n) 51 | end 52 | end 53 | column :kcal do |c| 54 | c.plan.total_kcal 55 | end 56 | 57 | end 58 | end 59 | 60 | active_admin_comments 61 | end 62 | 63 | form do |f| 64 | f.semantic_errors *f.object.errors.keys 65 | 66 | f.inputs "Details" do 67 | f.input :name 68 | f.input :description, :as => :ckeditor 69 | end 70 | 71 | f.has_many :diet_items, :allow_destroy => true, :heading => "Day plans" do |i| 72 | i.input :plan_id, :as => :select, :collection => current_user.plans, :input_html => {} 73 | #i.input :order_num 74 | end 75 | 76 | f.actions 77 | end 78 | 79 | controller do 80 | defaults :finder => :find_by_slug 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/requests/admin/rations_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Rations" do 4 | describe "Index" do 5 | let(:user) { create(:user) } 6 | 7 | before(:each) do 8 | login_as user 9 | end 10 | 11 | it "should show own and shared rations" do 12 | ration = create(:ration, :user => user) 13 | user_2 = create(:user) 14 | ration_2 = create(:ration, :user => user_2) 15 | user.shared_rations << ration_2 16 | 17 | visit admin_rations_path 18 | 19 | page.should have_selector('h2', :text => "Rations") 20 | page.should have_selector('table tbody tr td.col-name', :text => ration.name) 21 | page.should have_selector('table tbody tr td.col-name', :text => ration_2.name) 22 | end 23 | 24 | it "should add new ration" do 25 | visit admin_rations_path 26 | 27 | page.should have_selector('h2', :text => "Rations") 28 | within("span.blank_slate") do 29 | click_link "Create one" 30 | end 31 | 32 | page.should have_selector('h2', :text => "New Ration") 33 | within("#new_ration") do 34 | fill_in "Name", :with => "Test_ration" 35 | click_button "Create Ration" 36 | end 37 | 38 | page.should have_selector('h2', :text => "Test_ration") 39 | 40 | end 41 | 42 | it "should not have delete link for not owned ration" do 43 | ration = create(:ration, :user => user) 44 | user_2 = create(:user) 45 | ration_2 = create(:ration, :user => user_2) 46 | user.shared_rations << ration_2 47 | 48 | visit admin_rations_path 49 | 50 | page.should have_selector('h2', :text => "Rations") 51 | page.should have_selector('table tbody tr td.col-name', :text => ration.name) 52 | page.should have_selector('table tbody tr td.col-name', :text => ration_2.name) 53 | 54 | page.should have_selector("table tbody tr td.col a.delete_link[href='#{admin_ration_path(ration.id)}']", :text => "Delete") 55 | page.should_not have_selector("table tbody tr td.col a.delete_link[href='#{admin_ration_path(ration_2.id)}']", :text => "Delete") 56 | 57 | 58 | end 59 | 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/admin/plan_items.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register PlanItem do 2 | belongs_to :plan 3 | 4 | form do |f| 5 | f.inputs do 6 | f.input :dish_id, :as => :select, :collection => current_user.all_dishes 7 | #f.form_buffers.last << content_tag(:div, link_to("Create new Dish", new_admin_dish_path), :style => "padding-left: 10px;") 8 | f.input :meal_id, :as => :hidden 9 | end 10 | 11 | f.form_buffers.last << Arbre::Context.new({}, f.template) do 12 | div "OR " 13 | end 14 | 15 | f.inputs do 16 | f.input(:ingredient_id, :as => :select, :collection => current_user.all_ingredients) 17 | f.form_buffers.last << Arbre::Context.new({}, f.template) do 18 | li link_to "Create ingredient", new_admin_ingredient_path 19 | end 20 | 21 | end 22 | f.actions 23 | end 24 | 25 | controller do 26 | def new 27 | new! do |format| 28 | if params[:meal_id].present? 29 | @plan_item.meal = Meal.find(params[:meal_id]) 30 | end 31 | end 32 | end 33 | 34 | def edit 35 | edit! { 36 | @plan_item.send("#{@plan_item.eatable_type.downcase}_id=", @plan_item.eatable_id) 37 | } 38 | end 39 | 40 | def create 41 | parse_eatable 42 | create!{ admin_plan_path(@plan) } 43 | end 44 | 45 | def update 46 | parse_eatable 47 | update! { 48 | @plan_item.update_ingredients 49 | redirect_to admin_plan_path(@plan) and return 50 | } 51 | end 52 | 53 | def destroy 54 | destroy! do |format| 55 | redirect_to admin_plan_path(@plan) and return 56 | end 57 | end 58 | 59 | private 60 | def parse_eatable 61 | @dish = current_user.all_dishes.find(params[:plan_item].delete(:dish_id)) rescue nil 62 | @ingredient = current_user.all_ingredients.find(params[:plan_item].delete(:ingredient_id)) rescue nil 63 | 64 | obj = @dish.present? ? @dish : @ingredient 65 | 66 | params[:plan_item][:eatable_id] = obj.id 67 | params[:plan_item][:eatable_type] = obj.class.to_s 68 | params[:plan_item][:weight] = obj.weight 69 | end 70 | 71 | 72 | end 73 | 74 | end 75 | 76 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 4 | gem 'rails', '4.0.0' 5 | 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 8 | 9 | # Use SCSS for stylesheets 10 | gem 'sass-rails', '~> 4.0.0' 11 | 12 | # Use Uglifier as compressor for JavaScript assets 13 | gem 'uglifier', '>= 1.3.0' 14 | 15 | # Use CoffeeScript for .js.coffee assets and views 16 | gem 'coffee-rails', '~> 4.0.0' 17 | 18 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 19 | # gem 'therubyracer', platforms: :ruby 20 | 21 | # Use jquery as the JavaScript library 22 | gem 'jquery-rails' 23 | 24 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 25 | gem 'turbolinks' 26 | 27 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 28 | gem 'jbuilder', '~> 1.2' 29 | 30 | group :doc do 31 | # bundle exec rake doc:rails generates the API under doc/api. 32 | gem 'sdoc', require: false 33 | end 34 | 35 | # Use ActiveModel has_secure_password 36 | # gem 'bcrypt-ruby', '~> 3.0.0' 37 | 38 | # Use unicorn as the app server 39 | # gem 'unicorn' 40 | 41 | # Use Capistrano for deployment 42 | # gem 'capistrano', group: :development 43 | 44 | # Use debugger 45 | # gem 'debugger', group: [:development, :test] 46 | 47 | gem 'mysql2' 48 | gem 'protected_attributes' 49 | gem 'activeadmin', github: 'gregbell/active_admin' 50 | gem 'thin' 51 | gem "devise" 52 | gem "cancan" 53 | gem "rolify" 54 | gem "activerecord-tableless", "~> 1.0" 55 | gem 'activerecord-session_store', github: 'rails/activerecord-session_store' 56 | gem 'rails-i18n', '~> 4.0.0' 57 | 58 | group :development, :test do 59 | gem 'rspec-rails', '~> 2.0' 60 | gem 'factory_girl_rails', "~> 4.0", :require => false 61 | gem 'shoulda-matchers' 62 | gem 'spork-rails', :github => 'sporkrb/spork-rails' 63 | gem 'capybara' 64 | gem 'launchy' 65 | end 66 | 67 | gem 'quiet_assets', :group => :development 68 | gem 'friendly_id', '~> 5.0.0' 69 | gem "haml-rails" 70 | gem 'ckeditor' 71 | gem "carrierwave" 72 | gem "fog" 73 | gem "mini_magick" 74 | gem "iso8601" 75 | gem 'rails4-autocomplete' 76 | -------------------------------------------------------------------------------- /app/models/setting.rb: -------------------------------------------------------------------------------- 1 | class Setting < ActiveRecord::Base #RailsSettings::ScopedSettings 2 | attr_accessible :var, :value 3 | attr_accessor :title, :description, :hidden 4 | 5 | belongs_to :thing, :polymorphic => true 6 | 7 | validates :value, :presence => true 8 | before_save :is_ration_owner 9 | 10 | after_initialize :set_attrs 11 | 12 | def is_ration_owner 13 | if self.var == "ration" 14 | ration = Ration.find self.value 15 | if thing_type == "User" and thing_id != ration.user.id 16 | errors.add(:base, "You can choose as current only own ration") 17 | return false 18 | end 19 | end 20 | end 21 | 22 | def recalculate! 23 | if self.var == "weight" 24 | user = self.thing 25 | 26 | proteins_setting = user.setting_by_var("proteins") || user.settings.build(:var => "proteins") 27 | proteins_setting.value = self.value.to_f * 2 28 | proteins_setting.save 29 | 30 | fats_setting = user.setting_by_var("fats") || user.settings.build(:var => "fats") 31 | fats_setting.value = self.value.to_f * 0.5 32 | fats_setting.save 33 | 34 | carbs_setting = user.setting_by_var("carbs") || user.settings.build(:var => "carbs") 35 | carbs_setting.value = self.value.to_f * 4 36 | carbs_setting.save 37 | 38 | end 39 | end 40 | 41 | def set_attrs 42 | if self.var.present? 43 | self.title = get_conf_value(self.var, "title") 44 | self.description = get_conf_value(self.var, "description") 45 | self.hidden = get_conf_value(self.var, "hidden") 46 | end 47 | end 48 | 49 | def to_hash 50 | {"var" => self.var, "title" => self.title, "description" => self.description, "value" => self.value, "hidden" => self.hidden} 51 | end 52 | 53 | def get_conf_value(var_name, value_name) 54 | conf = Setting.default_conf 55 | conf[var_name][value_name] 56 | end 57 | 58 | def self.default_conf 59 | YAML.load_file("#{Rails.root}/config/default_settings.yml") 60 | end 61 | 62 | def self.from_hash(h) 63 | n = self.new 64 | n.var = h["var"] 65 | n.title = h["title"] 66 | n.description = h["description"] 67 | n.value = h["value"] 68 | n.hidden = h["hidden"] 69 | n 70 | end 71 | 72 | end 73 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | context "Associations" do 5 | it { should have_many(:settings) } 6 | it { should have_and_belong_to_many(:shared_rations) } 7 | it "should return dishes for current ration" do 8 | user = create(:user) 9 | dish = double(:dish) 10 | Dish.should_receive(:by_ration_and_own).and_return([dish]) 11 | user.all_dishes.should include(dish) 12 | end 13 | it { should have_many(:dishes) } 14 | end 15 | 16 | context "Settings" do 17 | let(:user) { create(:user) } 18 | 19 | it "should return saved value" do 20 | user.settings << create(:setting, :var => "proteins", :value => 111) 21 | user.setting(:proteins).should == "111" 22 | end 23 | 24 | it "should return default value" do 25 | conf = Setting.default_conf 26 | first_var = conf.keys.first 27 | 28 | user.settings.destroy_all 29 | 30 | user.setting(first_var).should == conf[first_var]["value"] 31 | end 32 | 33 | it "should get full settings (with defaults)" do 34 | conf = Setting.default_conf 35 | last_var = conf.keys.last 36 | 37 | first_var = conf.keys.first # should be 'ration' 38 | user.settings << create(:setting, :var => first_var, :value => create(:ration, :user => create(:user))) 39 | 40 | defaults = user.full_settings.map(&:var) 41 | 42 | defaults.should include(last_var) 43 | defaults.should include(first_var) 44 | end 45 | 46 | it "should not create 'ration' for not own ration" do 47 | other_ration = create(:ration, :user => create(:user)) 48 | 49 | ration_setting = build(:setting, :var => "ration", :value => other_ration.id, :thing => user) 50 | ration_setting.save 51 | 52 | user.reload 53 | 54 | ration_setting.errors.keys.should include(:base) 55 | user.setting(:ration).should_not == other_ration.id 56 | end 57 | 58 | it "should set default ration after create" do 59 | real_ration = create(:ration, :user => create(:user)) 60 | ration = double(Ration, :id => real_ration.id).as_null_object 61 | Ration.should_receive(:new).and_return(ration) 62 | 63 | user.setting(:ration).should == ration.id 64 | end 65 | 66 | end 67 | 68 | end 69 | -------------------------------------------------------------------------------- /spec/models/dish_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Dish do 4 | describe "Associations" do 5 | it { should have_many(:dish_compositions).dependent(:destroy) } 6 | it { should have_many(:ingredients) } 7 | it { should have_many(:eatens) } 8 | 9 | end 10 | 11 | describe "Scopes" do 12 | it "should get by ration" do 13 | user = create(:user) 14 | ration = create(:ration, :user => user) 15 | ration_2 = create(:ration) 16 | ingredient_a = create(:ingredient, :ration => ration) 17 | ingredient_b = create(:ingredient, :ration => ration) 18 | ingredient_2 = create(:ingredient, :ration => ration_2) 19 | dish_1 = create(:dish, :user => user) 20 | 21 | dish_2 = create(:dish) 22 | dish_2.ingredients.delete_all 23 | 24 | dc_a = create(:dish_composition, :ingredient => ingredient_a, :dish => dish_1) 25 | dc_b = create(:dish_composition, :ingredient => ingredient_b, :dish => dish_1) 26 | 27 | dc_2 = create(:dish_composition, :ingredient => ingredient_2, :dish => dish_2) 28 | 29 | res = Dish.by_ration_and_own(ration.id) 30 | res.should == [dish_1] 31 | end 32 | end 33 | 34 | describe "Ingredients" do 35 | it "should be valid" do 36 | dish = create(:dish) 37 | dish.should be_valid 38 | end 39 | 40 | it "should be invalid without ingredients" do 41 | dish = create(:dish) 42 | dish.dish_compositions = [] 43 | 44 | dish.ingredients.count.should == 0 45 | dish.should_not be_valid 46 | end 47 | 48 | context "#calculate_params" do 49 | it "should calculate params" do 50 | dish = create(:dish_schema_a) 51 | dish_sample = build(:dish_sample) 52 | 53 | dish.name.should be_present 54 | 55 | dish.calculate_params 56 | dish.weight.should == dish_sample.weight 57 | dish.proteins.should == dish_sample.proteins 58 | dish.fats.should == dish_sample.fats 59 | dish.carbs.should == dish_sample.carbs 60 | end 61 | 62 | it "should calculate with zero weight ingredient" do 63 | dish = create(:dish) 64 | dish.dish_compositions.count.should == 1 65 | dish.dish_compositions.first.weight = nil 66 | 67 | dish.calculate_params 68 | end 69 | end 70 | 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /app/helpers/active_admin/views_helper.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin::ViewsHelper #camelized file name 2 | def params_day_date 3 | (params[:d] || Date.today).to_date 4 | end 5 | 6 | def durations_array(limit=120) 7 | options = (5..limit).step(5).map do |i| 8 | if i >= 60 9 | caption = "#{i / 60} #{I18n.t("h")}" 10 | m = i % 60 11 | caption += " #{m} #{I18n.t("min")}" if m > 0 12 | else 13 | caption = "#{i} #{I18n.t("min")}" 14 | end 15 | [caption, i * 60] 16 | end 17 | end 18 | 19 | def durations_options(selected=nil) 20 | options = durations_array 21 | options_for_select(options, selected) 22 | end 23 | 24 | def ingredients_options_with_portion_unit(selected=nil) 25 | #ingredients = Ingredient.by_ration(current_user.setting(:ration)).map do |i| 26 | ingredients = current_user.all_ingredients.map do |i| 27 | [i.name, i.id, {:pu => i.portion_unit}] 28 | end 29 | 30 | options_for_select(ingredients, selected) 31 | end 32 | 33 | def edit_delete_links(resource) 34 | links = '' 35 | links += link_to I18n.t('active_admin.edit'), edit_resource_path(resource), :class => "member_link edit_link" 36 | links += link_to I18n.t('active_admin.delete'), resource_path(resource), :method => :delete, :data => {:confirm => I18n.t('active_admin.delete_confirmation')}, :class => "member_link delete_link" 37 | links.html_safe 38 | end 39 | 40 | def dish_links(resource) 41 | links = ''.html_safe 42 | if current_user.id == resource.user.id 43 | links += edit_delete_links(resource) 44 | end 45 | links += link_to "Eat", new_admin_dish_eaten_path(resource) 46 | links 47 | end 48 | 49 | def ingredient_links(resource) 50 | links = ''.html_safe 51 | 52 | if current_user.id == resource.user.id 53 | links += edit_delete_links(resource) 54 | else 55 | links += link_to "Copy to my", copy_to_my_admin_ingredient_path(resource), :method => :post, :class => "member_link edit_link" 56 | end 57 | 58 | links += link_to "Eat", new_admin_ingredient_eaten_path(resource) 59 | links 60 | end 61 | 62 | def portion_caption(p) 63 | "#{p.portion} #{(Ingredient::PORTION_UNITS[:gramm] + "/") if p.portion_unit != "gramm" }#{Ingredient::PORTION_UNITS[p.portion_unit.to_sym]}" 64 | end 65 | 66 | end 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/models/dish.rb: -------------------------------------------------------------------------------- 1 | class Dish < ActiveRecord::Base 2 | include Calorie 3 | attr_accessible :name, :description, :dish_compositions_attributes, :prep_time, :cook_time, :portions 4 | 5 | has_many :dish_compositions, :dependent => :destroy 6 | has_many :ingredients, :through => :dish_compositions 7 | has_many :eatens, :as => :eatable 8 | has_many :plan_items, :dependent => :destroy, :as => :eatable 9 | belongs_to :user 10 | has_one :post, :as => :postable, :dependent => :destroy 11 | 12 | #scope :by_ration, ->(ration_id) { includes(:ingredients).where(:ingredients => {:ration_id => ration_id }).order("dishes.created_at DESC") } 13 | 14 | accepts_nested_attributes_for :dish_compositions, :allow_destroy => true 15 | 16 | validates :name, :presence => true 17 | validate :validate_ingredients 18 | 19 | after_save :after_saved 20 | 21 | def after_saved 22 | if ingredients.present? 23 | calculate_params 24 | self.update_column(:weight, self.weight) 25 | self.update_column(:proteins, self.proteins) 26 | self.update_column(:fats, self.fats) 27 | self.update_column(:carbs, self.carbs) 28 | end 29 | end 30 | 31 | def self.by_ration_and_own(ration_id, user = nil) 32 | ration = Ration.find(ration_id) 33 | user ||= ration.user 34 | 35 | self.includes(:ingredients) 36 | .where(:ingredients => {:ration_id => ration_id }) 37 | .where("dishes.user_id = ? OR dishes.user_id = ?", ration.user_id, user.id) 38 | .order("dishes.created_at DESC") 39 | end 40 | 41 | def validate_ingredients 42 | unless dish_compositions.present? 43 | errors.add(:base, "At least one ingredient should be defined") 44 | end 45 | end 46 | 47 | def calculate_params 48 | self.weight = 0 49 | self.proteins = 0 50 | self.fats = 0 51 | self.carbs = 0 52 | 53 | dish_compositions.each do |dc| 54 | self.weight += dc.weight || 0 55 | self.proteins += dc.proteins 56 | #p "PROTEINS: #{self.proteins}" 57 | self.fats += dc.fats 58 | self.carbs += dc.carbs 59 | end 60 | end 61 | 62 | def calculate_nutrient_weight(nutrient, weight_in) 63 | return 0 if self.weight.to_i == 0 64 | weight_in.to_i * self.send(nutrient) / self.weight.to_i 65 | end 66 | 67 | def published_at 68 | updated_at 69 | end 70 | 71 | def portion_value(attr) 72 | return 0 if self.portions.to_i == 0 73 | (self.send(attr) / self.portions).round 74 | end 75 | 76 | end 77 | -------------------------------------------------------------------------------- /app/models/ingredient.rb: -------------------------------------------------------------------------------- 1 | class Ingredient < ActiveRecord::Base 2 | include Calorie 3 | attr_accessible :name, :portion, :portion_unit, :carbs, :fats, :proteins, :ingredient_group_id 4 | 5 | has_many :dish_compositions, :dependent => :restrict_with_exception 6 | has_many :dishes, :through => :dish_compositions 7 | has_many :eatens, :as => :eatable 8 | has_many :plan_items, :dependent => :destroy, :as => :eatable 9 | has_many :plan_item_ingredients, :dependent => :destroy 10 | belongs_to :ration 11 | belongs_to :user 12 | belongs_to :group, :class_name => IngredientGroup, :foreign_key => :ingredient_group_id 13 | 14 | scope :by_ration, ->(ration_id) { where(:ration_id => ration_id)} 15 | 16 | PORTION_UNITS = {:gramm => "g", :item => "item", :teaspoon => "t.s."} 17 | 18 | validates_presence_of :name, :portion, :portion_unit 19 | 20 | after_initialize :after_init 21 | after_update :recalculate_dependencies 22 | 23 | def after_init 24 | self.portion_unit ||= PORTION_UNITS.invert["g"] 25 | end 26 | 27 | def recalculate_dependencies 28 | if portion_changed? or carbs_changed? or fats_changed? or proteins_changed? 29 | # calls order below is important 30 | self.dish_compositions.each { |dc| dc.save } 31 | self.dishes.each{ |d| d.save } 32 | end 33 | end 34 | 35 | def weight 36 | self.portion 37 | end 38 | 39 | def calculate_nutrient_weight(nutrient, weight) 40 | weight ||= 0 41 | n = self.send(nutrient) || 0 42 | case self.portion_unit 43 | when "gramm" 44 | weight * n / self.portion 45 | when "item" 46 | #p "WEIGHT: #{weight}, #{nutrient}: #{self.send(nutrient)}, PORTION: #{self.portion}" 47 | weight * n / self.portion 48 | else 49 | 0 50 | end 51 | end 52 | 53 | def self.by_ration_and_own(ration_id, user = nil) 54 | ration = Ration.find(ration_id) 55 | user ||= ration.user 56 | 57 | #self.where("ration_id = ? OR (ration_id = ? AND user_id = ?)", ration.id, ration.id, user.id) 58 | self.where("ration_id = ? AND user_id = ?", ration.id, user.id) 59 | .order("ingredients.created_at DESC") 60 | end 61 | 62 | def self.by_available_rations(user) 63 | temp = user.own_rations + user.shared_rations 64 | return nil unless temp.count 65 | self.where("ration_id IN (?)", temp.map(&:id)).order("updated_at DESC") 66 | end 67 | 68 | def self.autocomplete_list(user, term='') 69 | self.by_available_rations(user).where(["LOWER(name) LIKE ?", "%#{term.downcase}%"]).limit(10) 70 | end 71 | 72 | end 73 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Mealness::Application.routes.draw do 2 | mount Ckeditor::Engine => '/ckeditor' 3 | 4 | root :to => "home#index" 5 | 6 | get '/sitemap.xml' => 'sitemap#index', :as => :sitemap, :format => :xml 7 | get 'posts/:post_id' => 'home#post', :as => :post 8 | 9 | devise_for :users, ActiveAdmin::Devise.config 10 | ActiveAdmin.routes(self) 11 | 12 | # new_admin_eaten GET /admin/eatens/new(.:format) admin/eatens#new 13 | get 'admin/dishes/:dish_id/eatens/new' => 'admin/eatens#new', :as => :new_admin_dish_eaten 14 | get 'admin/ingredients/:ingredient_id/eatens/new' => 'admin/eatens#new', :as => :new_admin_ingredient_eaten 15 | get 'admin/rations/:ration_id/ingredients' => 'admin/ingredients#index', :as => :admin_ration_ingredients 16 | post 'admin/dishes/ingredients/new' => 'admin/dishes#new_ingredient', :as => :new_admin_ingredient_dishes 17 | 18 | # The priority is based upon order of creation: first created -> highest priority. 19 | # See how all your routes lay out with "rake routes". 20 | 21 | # You can have the root of your site routed with "root" 22 | # root 'welcome#index' 23 | 24 | # Example of regular route: 25 | # get 'products/:id' => 'catalog#view' 26 | 27 | # Example of named route that can be invoked with purchase_url(id: product.id) 28 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 29 | 30 | # Example resource route (maps HTTP verbs to controller actions automatically): 31 | # resources :products 32 | 33 | # Example resource route with options: 34 | # resources :products do 35 | # member do 36 | # get 'short' 37 | # post 'toggle' 38 | # end 39 | # 40 | # collection do 41 | # get 'sold' 42 | # end 43 | # end 44 | 45 | # Example resource route with sub-resources: 46 | # resources :products do 47 | # resources :comments, :sales 48 | # resource :seller 49 | # end 50 | 51 | # Example resource route with more complex sub-resources: 52 | # resources :products do 53 | # resources :comments 54 | # resources :sales do 55 | # get 'recent', on: :collection 56 | # end 57 | # end 58 | 59 | # Example resource route with concerns: 60 | # concern :toggleable do 61 | # post 'toggle' 62 | # end 63 | # resources :posts, concerns: :toggleable 64 | # resources :photos, concerns: :toggleable 65 | 66 | # Example resource route within a namespace: 67 | # namespace :admin do 68 | # # Directs /admin/products/* to Admin::ProductsController 69 | # # (app/controllers/admin/products_controller.rb) 70 | # resources :products 71 | # end 72 | end 73 | -------------------------------------------------------------------------------- /spec/requests/admin/plan_items_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Plan" do 4 | include DishHelper 5 | 6 | let(:user) { create(:user) } 7 | 8 | before(:each) do 9 | user.add_rations 10 | login_as user 11 | end 12 | 13 | describe "Add new" do 14 | it "should add existing ingredient" do 15 | plan = create(:plan, :user => user) 16 | ingredient = create(:ingredient, :user => user, :ration => Ration.find(user.setting(:ration))) 17 | 18 | visit new_admin_plan_plan_item_path(plan, :meal_id => 1) 19 | 20 | select ingredient.name, :from => "plan_item_ingredient_id" 21 | click_button "Create Plan item" 22 | 23 | current_path.should == admin_plan_path(plan) 24 | page.should have_selector("div.panel_contents div.column a", ingredient.name) 25 | end 26 | 27 | it "should add created ingredient" do 28 | plan = create(:plan, :user => user) 29 | ingredient = build(:ingredient) 30 | 31 | visit new_admin_plan_plan_item_path(plan, :meal_id => 1) 32 | click_link("Create ingredient") 33 | current_path.should == new_admin_ingredient_path 34 | 35 | fill_in "ingredient_name", :with => ingredient.name 36 | fill_in "ingredient_portion", :with => ingredient.portion 37 | click_button("Create Ingredient") 38 | 39 | current_path.should == new_admin_plan_plan_item_path(plan) 40 | 41 | select ingredient.name, :from => "plan_item_ingredient_id" 42 | click_button "Create Plan item" 43 | 44 | current_path.should == admin_plan_path(plan) 45 | page.should have_selector("div.panel_contents div.column a", ingredient.name) 46 | end 47 | 48 | it "should add copied ingredient" do 49 | default_ration = Ration.get_default 50 | plan = create(:plan, :user => user) 51 | ingredient = create(:ingredient, :ration => default_ration, :user => create(:user)) 52 | 53 | visit new_admin_plan_plan_item_path(plan, :meal_id => 1) 54 | click_link("Create ingredient") 55 | current_path.should == new_admin_ingredient_path 56 | 57 | find("span.action_item a", :text => "Rations").click # goto rations list 58 | click_link default_ration.name # goto to ingredients list 59 | click_link ingredient.name # select ingredient 60 | click_button("Update Ingredient") 61 | 62 | current_path.should == new_admin_plan_plan_item_path(plan) 63 | 64 | select ingredient.name, :from => "plan_item_ingredient_id" 65 | click_button "Create Plan item" 66 | 67 | current_path.should == admin_plan_path(plan) 68 | page.should have_selector("div.panel_contents div.column a", ingredient.name) 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /public/javascripts/autocomplete-rails.js: -------------------------------------------------------------------------------- 1 | (function(jQuery){var self=null;var options={};jQuery.fn.railsAutocomplete=function(){var handler=function(){if(!this.railsAutoCompleter){this.railsAutoCompleter=new jQuery.railsAutocomplete(this)}};options[this.selector.replace("#","")]=arguments[0];if(jQuery.fn.on!==undefined){return $(document).on("focus",this.selector,handler)}else{return this.live("focus",handler)}};jQuery.railsAutocomplete=function(e){_e=e;this.init(_e)};jQuery.railsAutocomplete.fn=jQuery.railsAutocomplete.prototype={railsAutocomplete:"0.0.1"};jQuery.railsAutocomplete.fn.extend=jQuery.railsAutocomplete.extend=jQuery.extend;jQuery.railsAutocomplete.fn.extend({init:function(e){e.delimiter=jQuery(e).attr("data-delimiter")||null;function split(val){return val.split(e.delimiter)}function extractLast(term){return split(term).pop().replace(/^\s+/,"")}jQuery(e).autocomplete($.extend({source:function(request,response){jQuery.getJSON(jQuery(e).attr("data-autocomplete"),{term:extractLast(request.term)},function(){if(arguments[0].length==0){arguments[0]=[];arguments[0][0]={id:"",label:"no existing match"}}jQuery(arguments[0]).each(function(i,el){var obj={};obj[el.id]=el;jQuery(e).data(obj)});response.apply(null,arguments)})},change:function(event,ui){if(jQuery(jQuery(this).attr("data-id-element")).val()==""){return}jQuery(jQuery(this).attr("data-id-element")).val(ui.item?ui.item.id:"");var update_elements=jQuery.parseJSON(jQuery(this).attr("data-update-elements"));var data=ui.item?jQuery(this).data(ui.item.id.toString()):{};if(update_elements&&jQuery(update_elements.id).val()==""){return}for(var key in update_elements){jQuery(update_elements[key]).val(ui.item?data[key]:"")}},search:function(){var term=extractLast(this.value);if(term.length<2){return false}},focus:function(){return false},select:function(event,ui){var terms=split(this.value);terms.pop();terms.push(ui.item.value);if(e.delimiter!=null){terms.push("");this.value=terms.join(e.delimiter)}else{this.value=terms.join("");if(jQuery(this).attr("data-id-element")){jQuery(jQuery(this).attr("data-id-element")).val(ui.item.id)}if(jQuery(this).attr("data-update-elements")){var data=jQuery(this).data(ui.item.id.toString());var update_elements=jQuery.parseJSON(jQuery(this).attr("data-update-elements"));for(var key in update_elements){jQuery(update_elements[key]).val(data[key])}}}var remember_string=this.value;jQuery(this).bind("keyup.clearId",function(){if(jQuery(this).val().trim()!=remember_string.trim()){jQuery(jQuery(this).attr("data-id-element")).val("");jQuery(this).unbind("keyup.clearId")}});jQuery(e).trigger("railsAutocomplete.select",ui);return false}},options[e.id]))}});jQuery(document).ready(function(){jQuery("input[data-autocomplete]").railsAutocomplete()})})(jQuery); 2 | -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | published: Опубликовано 3 | breakfast: "Завтрак" 4 | second_breakfast: "2-й завтрак" 5 | dinner: "Обед" 6 | tea: "Полдник" 7 | supper: "Ужин" 8 | second_supper: "2-й ужин" 9 | item_abbr: "шт" 10 | gramm_abbr: "г" 11 | min: "мин." 12 | h: "ч." 13 | portions: 14 | one: "%{count} порция" 15 | few: "%{count} порции" 16 | many: "%{count} порций" 17 | other: "%{count} порций" 18 | 19 | titles: 20 | name: Название 21 | select_type: "Выберите тип" 22 | ingredient: "Ингредиент" 23 | select_ingredient: "Выберите ингредиент" 24 | dish: Блюдо 25 | 26 | subtitles: 27 | details: "Детали" 28 | my_ingredients: "Мои ингредиенты" 29 | 30 | menu: 31 | settings: Настройки 32 | food: Питание 33 | diary: Дневник 34 | 35 | links: 36 | preview: Предпросмотр 37 | preview_short: Предпросмотр аннотации 38 | dish: Блюдо 39 | diet: Диета 40 | confirm_publish: Вы уверены, что хотите опубликовать это? 41 | create_post: Опубликовать 42 | edit_post: Изменить Пост 43 | 44 | buttons: 45 | update: Обновить 46 | reset: Сбросить 47 | next: Далее 48 | 49 | 50 | attributes: 51 | name: Название 52 | description: Описание 53 | created_at: Создано 54 | updated_at: Обновлено 55 | 56 | activerecord: 57 | models: 58 | post: 59 | one: Пост 60 | few: Посты 61 | many: Посты 62 | other: Посты 63 | plan: 64 | one: План на день 65 | few: Планы на день 66 | many: Планы на день 67 | other: Планы на день 68 | plan_item: 69 | one: Пункт плана 70 | few: Пункты плана 71 | many: Пункты плана 72 | other: Пункты плана 73 | ration: 74 | one: Рацион 75 | few: Рационы 76 | many: Рационы 77 | other: Рационы 78 | diet: 79 | one: Диета 80 | few: Диеты 81 | many: Диеты 82 | other: Диеты 83 | dish: 84 | one: Блюдо 85 | few: Блюда 86 | many: Блюда 87 | other: Блюда 88 | ingredient: 89 | one: Ингредиент 90 | few: Ингредиенты 91 | many: Ингредиенты 92 | other: Ингредиенты 93 | eaten: Съеденное 94 | attributes: 95 | ingredient: 96 | name: Название 97 | dish: 98 | prep_time: Время подготовки 99 | post: 100 | title: Заголовок 101 | short_description: Аннотация 102 | user: 103 | plan: 104 | name: Название 105 | 106 | errors: 107 | models: 108 | user: 109 | 110 | 111 | -------------------------------------------------------------------------------- /app/admin/posts.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Post do 2 | config.batch_actions = false 3 | config.clear_action_items! 4 | 5 | member_action :publish, :method => :post do 6 | if resource.publish! 7 | redirect_to request.referer, :notice => "Post published" 8 | else 9 | redirect_to request.referer, :alert => "Post NOT published. #{resource.errors.full_messages}" 10 | end 11 | end 12 | 13 | member_action :unpublish, :method => :post do 14 | resource.unpublish! 15 | redirect_to request.referer, :notice => "Post unpublished" 16 | end 17 | 18 | member_action :preview, :method => :get do 19 | render :template => "home/post", :locals => {:entry => resource}, :layout => "application" 20 | end 21 | 22 | member_action :preview_short, :method => :get do 23 | @posts = [resource] 24 | render :template => "home/index", :layout => "application" 25 | end 26 | 27 | action_item :only => [:show] do 28 | postablec = resource.postable.class.name 29 | 30 | links = '' 31 | links += link_to I18n.t("links.#{postablec.downcase}", :default => postablec), eval("admin_#{postablec.downcase}_path(resource.postable)") 32 | links += link_to I18n.t("links.preview", :default => "Preview"), preview_admin_post_path(resource), :target => "_blank" 33 | links += link_to I18n.t("links.preview_short", :default => "Preview annotation"), preview_short_admin_post_path(resource), :target => "_blank" 34 | links += edit_delete_links(resource) 35 | links.html_safe 36 | end 37 | 38 | index do 39 | if current_user.admin? 40 | column :user 41 | end 42 | column :name do |c| 43 | auto_link c.postable, c.postable.name 44 | end 45 | column :postable_type 46 | column :published_at 47 | column :created_at 48 | 49 | column "" do |resource| 50 | html = '' 51 | 52 | if current_user.admin? 53 | if resource.published? 54 | html += link_to "Unpublish", unpublish_admin_post_path(resource), :method => :post, :class => "member_link" 55 | else 56 | html += link_to "Publish", publish_admin_post_path(resource), :method => :post, :class => "member_link" 57 | end 58 | end 59 | 60 | html += link_to I18n.t('active_admin.delete'), resource_path(resource), :method => :delete, :data => {:confirm => I18n.t('active_admin.delete_confirmation')}, :class => "member_link delete_link" 61 | html.html_safe 62 | end 63 | end 64 | 65 | form do |f| 66 | f.semantic_errors *f.object.errors.keys 67 | 68 | f.inputs I18n.t("subtitles.details") do 69 | f.input :title 70 | f.input :short_description, :as => :ckeditor 71 | f.input :meta_keywords 72 | f.input :meta_description 73 | end 74 | 75 | f.actions 76 | 77 | end 78 | 79 | controller do 80 | defaults :finder => :find_by_slug 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | rolify 3 | # Include default devise modules. Others available are: 4 | # :token_authenticatable, :confirmable, 5 | # :lockable, :timeoutable and :omniauthable 6 | devise :database_authenticatable, :registerable, 7 | :recoverable, :rememberable, :trackable, :validatable 8 | 9 | has_many :settings, :as => :thing 10 | has_many :eatens, :dependent => :destroy 11 | has_many :plans, :dependent => :destroy 12 | has_many :own_rations, :class_name => Ration, :dependent => :destroy 13 | has_and_belongs_to_many :shared_rations, :class_name => Ration 14 | has_many :dishes, :dependent => :destroy 15 | has_many :ingredients, :dependent => :destroy 16 | has_many :diets, :dependent => :destroy 17 | 18 | attr_accessible :email, :password, :password_confirmation, :remember_me 19 | attr_accessible :email, :password, :password_confirmation, :role_ids, :signing_attributes, :as => :admin 20 | 21 | after_create :add_rations 22 | 23 | def admin? 24 | has_role?(:admin) 25 | end 26 | 27 | def add_rations 28 | def_ration = Ration.get_default 29 | def_ration.customers << self 30 | def_ration.save 31 | 32 | ration = Ration.new 33 | ration.user = self 34 | ration.name = "My ration" 35 | ration.save 36 | 37 | setting = self.settings.build(:var => "ration") 38 | setting.value = ration.id 39 | setting.save 40 | end 41 | 42 | def all_diets 43 | self.admin? ? Diet.all : diets 44 | end 45 | 46 | def all_plans 47 | self.admin? ? Plan.all : plans 48 | end 49 | 50 | def all_rations 51 | #(self.own_rations + self.shared_rations).sort! {|x,y| x.created_at <=> y.created_at} #=> accesible_by error 52 | #self.own_rations.merge(self.shared_rations) # => empty result 53 | 54 | #TODO should refactor to direct SQL query 55 | temp = self.own_rations + self.shared_rations 56 | Ration.where('id in (?)',temp.map(&:id)).order("created_at DESC") 57 | end 58 | 59 | def all_dishes 60 | Dish.by_ration_and_own(self.setting(:ration), self) 61 | end 62 | 63 | def all_ingredients 64 | Ingredient.by_ration_and_own(self.setting(:ration), self) 65 | end 66 | 67 | def setting(var) 68 | var = var.to_s 69 | var_setting = self.setting_by_var(var) 70 | return var_setting.value if var_setting 71 | 72 | conf = Setting.default_conf 73 | conf[var]["value"] 74 | end 75 | 76 | def full_settings 77 | conf = Setting.default_conf 78 | user_settings = self.settings.to_a 79 | res = [] 80 | 81 | conf.values.each do |c| 82 | s = setting_by_var(c["var"], user_settings) 83 | s = Setting.from_hash(c) unless s 84 | res << s 85 | end 86 | 87 | res 88 | end 89 | 90 | def setting_by_var(var, collection = nil) 91 | collection ||= self.settings.to_a 92 | collection.each do |c| 93 | return c if c.var == var 94 | end 95 | nil 96 | end 97 | 98 | end 99 | -------------------------------------------------------------------------------- /app/models/meal.rb: -------------------------------------------------------------------------------- 1 | class Meal < ActiveRecord::Base 2 | has_no_table :database => :pretend_success 3 | column :id, :integer 4 | column :name, :string 5 | column :key, :string 6 | 7 | attr_accessible :id, :name, :key 8 | 9 | class << self 10 | def meal_target(nutrient, meal, user, meals_num) 11 | if nutrient == :carbs 12 | a = self.carbs_allocation_presets(meals_num) 13 | percents = a[meal.id] 14 | else 15 | percents = self.meal_percents(meal, meals_num) 16 | end 17 | (user.setting(nutrient).to_f * percents / 100).round(2) 18 | end 19 | 20 | def meal_percents(meal, meals_num) 21 | a = self.allocation_presets(meals_num) 22 | a[meal.id] 23 | end 24 | 25 | def meal_time(meal, user) 26 | start = Time.parse(user.setting(:breakfast_time)) 27 | case meal.id 28 | when 1 29 | start 30 | when 2 31 | start + 3.hours 32 | when 3 33 | start + 6.hours 34 | when 4 35 | start + 9.hours 36 | when 5 37 | start + 12.hours 38 | when 6 39 | start + 15.hours 40 | else 41 | nil 42 | end 43 | end 44 | 45 | def carbs_allocation_presets(quan) 46 | case quan.to_i 47 | when 1 48 | q = {1 => 100} 49 | when 2 50 | q = {1 => 40, 2 => 60} 51 | when 3 52 | q = {1 => 40, 3 => 60, 5 => 0} 53 | when 4 54 | q = {1 => 40, 3 => 60, 4 => 0, 5 => 0} 55 | when 5 56 | q = {1 => 20, 2 => 10, 3 => 60, 4 => 10, 5 => 0} 57 | when 6 58 | q = {1 => 20, 2 => 10, 3 => 60, 4 => 10, 5 => 0, 6 => 0} 59 | else 60 | raise "Meals quantity incorrect" 61 | end 62 | end 63 | 64 | def allocation_presets(quan) 65 | case quan.to_i 66 | when 1 67 | q = {1 => 100} 68 | when 2 69 | q = {1 => 40, 2 => 60} 70 | when 3 71 | q = {1 => 30, 3 => 45, 5 => 25} 72 | when 4 73 | q = {1 => 25, 3 => 35, 4 => 15, 5 => 25} 74 | when 5 75 | q = {1 => 20, 2 => 10, 3 => 40, 4 => 20, 5 => 10} 76 | when 6 77 | q = {1 => 20, 2 => 10, 3 => 30, 4 => 15, 5 => 20, 6 => 5} 78 | else 79 | raise "Meals quantity incorrect" 80 | end 81 | end 82 | 83 | def find_for(quan) 84 | q = self.allocation_presets(quan).keys 85 | self.find(q) 86 | end 87 | 88 | def find_by_sql(*args) 89 | records 90 | end 91 | 92 | def find(id) 93 | if id.instance_of? Array 94 | res = [] 95 | id.each do |i| 96 | res << self.find(i) 97 | end 98 | res 99 | else 100 | records.find{ |r| r.id == id.to_i } 101 | end 102 | end 103 | 104 | def records 105 | [ 106 | Meal.new(:id => 1, :name => "Breakfast", :key => "breakfast"), 107 | Meal.new(:id => 2, :name => "Second breakfast", :key => "second_breakfast"), 108 | Meal.new(:id => 3, :name => "Dinner", :key => "dinner"), 109 | Meal.new(:id => 4, :name => "Tea", :key => "tea"), 110 | Meal.new(:id => 5, :name => "Supper", :key => "supper"), 111 | Meal.new(:id => 6, :name => "Second supper", :key => "second_supper") 112 | ] 113 | end 114 | 115 | end 116 | 117 | end 118 | -------------------------------------------------------------------------------- /app/models/plan_item.rb: -------------------------------------------------------------------------------- 1 | class PlanItem < ActiveRecord::Base 2 | include Calorie 3 | include Copier 4 | 5 | attr_accessible :plan_id, :meal_id, :weight, :eatable_id, :eatable_type 6 | 7 | attr_accessor :dish_id, :ingredient_id 8 | 9 | belongs_to :plan 10 | belongs_to :eatable, :polymorphic => true 11 | belongs_to :meal 12 | has_many :plan_item_ingredients, :dependent => :destroy 13 | has_many :ingredients, :through => :plan_item_ingredients 14 | 15 | validates :plan, :eatable, :meal, :presence => true 16 | 17 | after_create :add_ingredients, if: Proc.new { |obj| obj.plan_item_ingredients.empty? } 18 | 19 | def add_ingredients 20 | case self.eatable_type 21 | when "Dish" 22 | self.eatable.dish_compositions.each do |dc| 23 | pi = self.plan_item_ingredients.build(:weight => dc.weight) 24 | pi.ingredient = dc.ingredient 25 | pi.save 26 | end 27 | when "Ingredient" 28 | pi = self.plan_item_ingredients.build(:weight => eatable.weight) 29 | pi.ingredient = eatable 30 | pi.save 31 | else 32 | end 33 | end 34 | 35 | def do_copy 36 | wrap_copy do 37 | self.plan_item_ingredients.each do |i| 38 | new_item, message = i.do_copy 39 | new_item.ingredient_id = i.ingredient_id 40 | 41 | raise ActiveRecord::Rollback unless new_item 42 | @copied_item.plan_item_ingredients << new_item 43 | end 44 | end 45 | end 46 | 47 | def recalculate_weight 48 | weight = self.plan_item_ingredients.sum(:weight) rescue 0 49 | self.update_attribute(:weight, weight) 50 | end 51 | 52 | def update_ingredients 53 | self.plan_item_ingredients.destroy_all 54 | add_ingredients 55 | end 56 | 57 | def display_name 58 | eatable.name 59 | end 60 | 61 | def calculate_nutrient_weight(nutrient, weight) 62 | sum = 0 63 | self.plan_item_ingredients.each do |piing| 64 | sum += piing.ingredient.calculate_nutrient_weight(nutrient, piing.weight) 65 | end 66 | sum 67 | end 68 | 69 | def pi_ingredients_with_protein 70 | self.plan_item_ingredients.select{|i| i.ingredient.proteins > 0} 71 | end 72 | 73 | def pi_ingredients_without_protein 74 | self.plan_item_ingredients.select{|i| i.ingredient.proteins <= 0} 75 | end 76 | 77 | def ingredients_percentage 78 | res = {} 79 | if eatable_type == "Dish" 80 | self.plan_item_ingredients.each do |piing| 81 | res[piing.id] = (self.eatable.dish_compositions.find_by_ingredient_id(piing.ingredient_id).weight.to_f * 100 / self.eatable.weight).round(2) 82 | end 83 | elsif eatable_type == "Ingredient" 84 | piing = self.plan_item_ingredients.first 85 | res[piing.id] = 100 86 | end 87 | res 88 | end 89 | 90 | def ingredients_with_protein_percentage 91 | weights = {} 92 | self.pi_ingredients_with_protein.each do |piing| 93 | if eatable_type == "Dish" 94 | weights[piing.id] = self.eatable.dish_compositions.find_by_ingredient_id(piing.ingredient_id).weight.to_f 95 | elsif eatable_type == "Ingredient" 96 | weights[piing.id] = self.eatable.weight 97 | end 98 | 99 | end 100 | 101 | res = {} 102 | self.pi_ingredients_with_protein.each do |piing| 103 | res[piing.id] = (weights[piing.id] * 100 / weights.values.sum).round(2) 104 | end 105 | res 106 | end 107 | 108 | end 109 | -------------------------------------------------------------------------------- /app/views/home/_dish.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |

<%= @post.title.html_safe %>

4 | 5 | 6 |
7 |
8 | 9 |
10 |
11 | <%= published_datetime(@post) %> 12 |
13 |
14 | 15 |
16 | 17 | 18 | 19 | 23 | 24 |
25 |
26 |

Время подготовки:

27 |

Время приготовления:

28 |

Общее время:

29 |
30 |
31 |

Выход: <%= I18n.t("portions", :count => entry.portions) %>

32 |

33 | Для 1 порции: 34 |

    35 |
  • Вес: <%= entry.portion_value(:weight) %> г
  • 36 |
  • Белки: <%= entry.portion_value(:proteins) %> г, Жиры: <%= entry.portion_value(:fats) %> г, Угл-ды: <%= entry.portion_value(:carbs) %> г
  • 37 |
  • Калории: <%= entry.portion_value(:kcal) %>
  • 38 |
39 |

40 |
41 |
42 | 43 |
44 |

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | <% entry.dish_compositions.each do |dc| -%> 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | <% end -%> 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
ИнгредиентКол-воБелки, гЖиры, гУглеводы, гКкал
<%= dc.ingredient.name %><%= ingredient_quantity(dc) %><%= dc.proteins %><%= dc.fats %><%= dc.carbs %><%= dc.kcal %>
 <%= entry.weight %> г<%= entry.proteins %><%= entry.fats %><%= entry.carbs %><%= entry.kcal %>
75 |

76 |
77 | <%= entry.description.try(:html_safe) %> 78 |
79 | <%= render :partial => "layouts/disqus" %> 80 |
81 |
82 | -------------------------------------------------------------------------------- /config/initializers/friendly_id.rb: -------------------------------------------------------------------------------- 1 | # FriendlyId Global Configuration 2 | # 3 | # Use this to set up shared configuration options for your entire application. 4 | # Any of the configuration options shown here can also be applied to single 5 | # models by passing arguments to the `friendly_id` class method or defining 6 | # methods in your model. 7 | # 8 | # To learn more, check out the guide: 9 | # 10 | # http://norman.github.io/friendly_id/file.Guide.html 11 | 12 | FriendlyId.defaults do |config| 13 | # ## Reserved Words 14 | # 15 | # Some words could conflict with Rails's routes when used as slugs, or are 16 | # undesirable to allow as slugs. Edit this list as needed for your app. 17 | config.use :reserved 18 | 19 | config.reserved_words = %w(new edit index session login logout users admin 20 | stylesheets assets javascripts images) 21 | 22 | # ## Friendly Finders 23 | # 24 | # Uncomment this to use friendly finders in all models. By default, if 25 | # you wish to find a record by its friendly id, you must do: 26 | # 27 | # MyModel.friendly.find('foo') 28 | # 29 | # If you uncomment this, you can do: 30 | # 31 | # MyModel.find('foo') 32 | # 33 | # This is significantly more convenient but may not be appropriate for 34 | # all applications, so you must explicity opt-in to this behavior. You can 35 | # always also configure it on a per-model basis if you prefer. 36 | # 37 | # Something else to consider is that using the :finders addon boosts 38 | # performance because it will avoid Rails-internal code that makes runtime 39 | # calls to `Module.extend`. 40 | # 41 | # config.use :finders 42 | # 43 | # ## Slugs 44 | # 45 | # Most applications will use the :slugged module everywhere. If you wish 46 | # to do so, uncomment the following line. 47 | # 48 | # config.use :slugged 49 | # 50 | # By default, FriendlyId's :slugged addon expects the slug column to be named 51 | # 'slug', but you can change it if you wish. 52 | # 53 | # config.slug_column = 'slug' 54 | # 55 | # When FriendlyId can not generate a unique ID from your base method, it appends 56 | # a UUID, separated by a single dash. You can configure the character used as the 57 | # separator. If you're upgrading from FriendlyId 4, you may wish to replace this 58 | # with two dashes. 59 | # 60 | # config.sequence_separator = '-' 61 | # 62 | # ## Tips and Tricks 63 | # 64 | # ### Controlling when slugs are generated 65 | # 66 | # As of FriendlyId 5.0, new slugs are generated only when the slug field is 67 | # nil, but if you're using a column as your base method can change this 68 | # behavior by overriding the `should_generate_new_friendly_id` method that 69 | # FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave 70 | # more like 4.0. 71 | # 72 | # config.use Module.new { 73 | # def should_generate_new_friendly_id? 74 | # slug.blank? || _changed? 75 | # end 76 | # } 77 | # 78 | # FriendlyId uses Rails's `parameterize` method to generate slugs, but for 79 | # languages that don't use the Roman alphabet, that's not usually suffient. Here 80 | # we use the Babosa library to transliterate Russian Cyrillic slugs to ASCII. If 81 | # you use this, don't forget to add "babosa" to your Gemfile. 82 | # 83 | # config.use Module.new { 84 | # def normalize_friendly_id(text) 85 | # text.to_slug.normalize! :transliterations => [:russian, :latin] 86 | # end 87 | # } 88 | end 89 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Mealness::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both thread web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = true 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation can not be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | end 81 | -------------------------------------------------------------------------------- /app/admin/settings.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Settings" do 2 | menu :label => I18n.t("menu.settings"), :priority => 100 3 | 4 | page_action :update, :method => :post do 5 | setting = current_user.settings.find_by_var(params[:var]) 6 | 7 | if params[:reset] 8 | setting.destroy if setting 9 | redirect_to admin_settings_path, :notice => "Setting was reset" 10 | return 11 | end 12 | 13 | unless setting 14 | setting = current_user.settings.build(:var => params[:var]) 15 | end 16 | 17 | setting.value = params[:value] 18 | if setting.save 19 | setting.recalculate! 20 | 21 | redirect_to (params[:ref].blank? ? admin_settings_path : params[:ref]), :notice => "Setting '#{setting.title}' updated" 22 | else 23 | redirect_to admin_settings_path, :alert => "Setting '#{setting.title}' not updated. #{setting.errors.full_messages.join(', ')}" 24 | end 25 | end 26 | 27 | content :title => I18n.t("menu.settings") do 28 | current_user.full_settings.each do |s| 29 | next if s.hidden 30 | para do 31 | form :action => admin_settings_update_path, :method => :post do |f| 32 | f.input :type => :hidden, :name => 'authenticity_token', :value => form_authenticity_token.to_s 33 | f.input :type => :hidden, :name => 'var', :value => s.var 34 | 35 | para b f.label s.title 36 | para i s.description 37 | f.input :type => :text, :name => 'value', :value => s.value, :size => 60 38 | f.input :type => :submit, :value => I18n.t("buttons.update") 39 | f.input :type => :submit, :name => "reset", :value => I18n.t("buttons.reset") 40 | end 41 | end 42 | end 43 | end 44 | 45 | 46 | #page_action :update, :method => :post do 47 | 48 | #Settings.all.each do |s| 49 | #if !params[s[0]].nil? && params[s[0]] != s[1] 50 | #Settings[s[0]] = params[s[0]] 51 | #end 52 | #end 53 | 54 | #redirect_to admin_settings_path, :notice => "Settings updated" 55 | #end 56 | 57 | #content do 58 | #form :action => admin_settings_update_path, :method => :post, :class => 'settings' do |f| 59 | #f.input :name => 'authenticity_token', :type => :hidden, :value => form_authenticity_token.to_s 60 | 61 | #para 'Caution! Changes may cause undesired operation!', :class => 'warning' 62 | 63 | #Settings.all.each do |setting | 64 | #para do 65 | #label setting[0] 66 | #f.input :value =>setting[1] , :name => setting[0], :type => :text 67 | #end 68 | #end 69 | 70 | #f.input :type => :submit, :value => "Save" 71 | #end 72 | #end 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | #scope_to :current_user 82 | 83 | #config.batch_actions = false 84 | #actions :all, :except => [:new, :show] 85 | #config.filters = false 86 | 87 | #index do 88 | #column :var 89 | #column :title 90 | #column :value 91 | #column :updated_at 92 | #default_actions 93 | #end 94 | 95 | #form do |f| 96 | #f.inputs do 97 | #f.input :value, :as => :string, :label => "#{f.object.title}" 98 | #end 99 | #f.actions 100 | #end 101 | 102 | #controller do 103 | #def find_collection 104 | #res = current_user.settings 105 | #res = apply_pagination(res) 106 | 107 | #current_user.missed_settings.each do |d| 108 | #res << d 109 | #end 110 | 111 | #res 112 | #end 113 | 114 | 115 | #def resource 116 | #setting = current_user.settings.find_by_id(params[:id]) 117 | #unless setting 118 | #default_setting = Setting.unscoped.where("thing_type is NULL and thing_id is NULL").find(params[:id]) 119 | #current_user.settings[default_setting.var.to_sym] = default_setting.to_hash 120 | 121 | #setting = current_user.settings.object(default_setting.var) 122 | #end 123 | #Rails::logger.info "SETTING: #{setting.inspect}" 124 | #setting 125 | #end 126 | #end 127 | 128 | 129 | 130 | end 131 | 132 | -------------------------------------------------------------------------------- /config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | devise: 5 | confirmations: 6 | confirmed: "Your account was successfully confirmed. Please sign in." 7 | confirmed_and_signed_in: "Your account was successfully confirmed. You are now signed in." 8 | send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." 9 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." 10 | failure: 11 | already_authenticated: "You are already signed in." 12 | inactive: "Your account is not activated yet." 13 | invalid: "Invalid email or password." 14 | invalid_token: "Invalid authentication token." 15 | locked: "Your account is locked." 16 | not_found_in_database: "Invalid email or password." 17 | timeout: "Your session expired. Please sign in again to continue." 18 | unauthenticated: "You need to sign in or sign up before continuing." 19 | unconfirmed: "You have to confirm your account before continuing." 20 | mailer: 21 | confirmation_instructions: 22 | subject: "Confirmation instructions" 23 | reset_password_instructions: 24 | subject: "Reset password instructions" 25 | unlock_instructions: 26 | subject: "Unlock Instructions" 27 | omniauth_callbacks: 28 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 29 | success: "Successfully authenticated from %{kind} account." 30 | passwords: 31 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." 32 | send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes." 33 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." 34 | updated: "Your password was changed successfully. You are now signed in." 35 | updated_not_active: "Your password was changed successfully." 36 | registrations: 37 | destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." 38 | signed_up: "Welcome! You have signed up successfully." 39 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 40 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 41 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." 42 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." 43 | updated: "You updated your account successfully." 44 | sessions: 45 | signed_in: "Signed in successfully." 46 | signed_out: "Signed out successfully." 47 | unlocks: 48 | send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." 49 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." 50 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 51 | errors: 52 | messages: 53 | already_confirmed: "was already confirmed, please try signing in" 54 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 55 | expired: "has expired, please request a new one" 56 | not_found: "not found" 57 | not_locked: "was not locked" 58 | not_saved: 59 | one: "1 error prohibited this %{resource} from being saved:" 60 | other: "%{count} errors prohibited this %{resource} from being saved:" 61 | -------------------------------------------------------------------------------- /app/admin/dish.rb: -------------------------------------------------------------------------------- 1 | require 'active_admin/post_action' 2 | 3 | ActiveAdmin.register Dish do 4 | include ActiveAdmin::PostAction 5 | 6 | menu :priority => 4, :parent => I18n.t("menu.food") 7 | config.batch_actions = false 8 | config.clear_action_items! 9 | 10 | scope_to :current_user 11 | 12 | filter :name 13 | filter :proteins 14 | filter :fats 15 | filter :carbs 16 | 17 | collection_action :new_ingredient, :method => :post do 18 | session[:new_dish] = params[:dish] 19 | redirect_to new_admin_ingredient_path 20 | end 21 | 22 | action_item :only => [:index] do 23 | link_to "New Dish", new_admin_dish_path 24 | end 25 | 26 | action_item :only => [:show] do 27 | html = '' 28 | html += post_action_link(resource) 29 | html += dish_links(resource) 30 | html.html_safe 31 | end 32 | 33 | index do 34 | #selectable_column 35 | 36 | column :name do |c| 37 | auto_link c, c.name 38 | end 39 | column :weight 40 | column :proteins 41 | column :fats 42 | column :carbs 43 | column :kcal 44 | 45 | column "" do |resource| 46 | dish_links(resource) 47 | end 48 | 49 | end 50 | 51 | show do |d| 52 | attributes_table do 53 | row :name 54 | row :description 55 | row :weight 56 | row :proteins 57 | row :fats 58 | row :carbs 59 | row :prep_time 60 | row :cook_time 61 | row :portions 62 | end 63 | 64 | panel "Ingredients" do 65 | table_for dish.dish_compositions do 66 | column "name" do |appointment| 67 | auto_link(appointment.ingredient, appointment.ingredient.name) 68 | end 69 | column "quantity" do |c| 70 | if c.portion_unit == "item" 71 | "#{c.portions} #{c.portion_unit.pluralize} (#{c.weight} g)" 72 | else 73 | "#{c.weight} g" 74 | end 75 | end 76 | end 77 | end 78 | 79 | active_admin_comments 80 | end 81 | 82 | form do |f| 83 | f.semantic_errors *f.object.errors.keys 84 | 85 | f.inputs "Details" do 86 | f.input :name 87 | f.input :description, :as => :ckeditor 88 | f.input :prep_time, :as => :select, :collection => durations_options(f.object.prep_time) 89 | f.input :cook_time, :as => :select, :collection => durations_options(f.object.cook_time) 90 | f.input :portions, :as => :select, :collection => (1..20) 91 | end 92 | 93 | f.has_many :dish_compositions, :allow_destroy => true, :heading => "Ingredients" do |i| 94 | i.form_buffers.last << Arbre::Context.new({}, f.template) do 95 | li link_to("Create new ingredient", "#", :id => "new_ingredient_#{i.index}", :class => "new_ingredient") 96 | end 97 | 98 | i.input :ingredient_id, :as => :select, :collection => ingredients_options_with_portion_unit(i.object.ingredient_id), :input_html => {:class => "dish_ingredient_select"} 99 | 100 | i.input :portions, :wrapper_html => ({:style => "display: none;"} if i.object.portion_unit == "gramm" or i.object.new_record?) 101 | i.input :weight, :wrapper_html => ({:style => "display: none;"} if i.object.portion_unit == "item" or i.object.new_record?) 102 | end 103 | 104 | f.actions 105 | 106 | f.form_buffers.last << Arbre::Context.new({}, f.template) do 107 | script :type => "text/javascript" do 108 | "switch_dish_ingredients();" 109 | end 110 | end 111 | end 112 | 113 | controller do 114 | def index 115 | index! do |format| 116 | @dishes = current_user.all_dishes.page(params[:page]) 117 | end 118 | end 119 | 120 | def show 121 | @dish = Dish.find(params[:id]) 122 | end 123 | 124 | def new 125 | if session[:new_dish] 126 | @dish = Dish.new session[:new_dish] 127 | session[:new_dish] = nil 128 | end 129 | super { 130 | @dish.dish_compositions << DishComposition.new if @dish.dish_compositions.empty? 131 | } 132 | end 133 | 134 | def edit 135 | super { 136 | if session[:new_dish] 137 | @dish.attributes = session[:new_dish] 138 | session[:new_dish] = nil 139 | end 140 | } 141 | end 142 | end 143 | 144 | end 145 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | "> 8 | "/> 9 | 10 | 11 | <%= yield_with_default(:page_title, "Diet Recipe") %> 12 | 13 | <%= stylesheet_link_tag "client", media: "all", "data-turbolinks-track" => true %> 14 | <%= javascript_include_tag "client", "data-turbolinks-track" => true %> 15 | 16 | <%= csrf_meta_tags %> 17 | 18 | 19 | 20 | 21 | 48 | 49 |
50 | 51 |

<%= notice %>

52 |

<%= alert %>

53 | 54 |
55 |
56 | <%= yield %> 57 |
58 | 59 |
60 |
61 | 62 | 66 | 69 |
70 | 71 | 74 |
75 | <%= render :partial => "layouts/side_popular" %> 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |
84 |
85 |

Copyright © Mealness 2014

86 |
87 |
88 |
89 | 90 |
91 | 92 | 93 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /config/locales/devise.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | devise: 3 | confirmations: 4 | confirmed: "Ваша учётная запись подтверждена. Теперь вы вошли в систему." 5 | send_instructions: "В течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи." 6 | send_paranoid_instructions: "Если ваш адрес email есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи." 7 | failure: 8 | already_authenticated: "Вы уже вошли в систему." 9 | inactive: "Ваша учётная запись ещё не активирована." 10 | invalid: "Неверный номер или пароль." 11 | invalid_token: "Неверный ключ аутентификации." 12 | locked: "Ваша учётная запись заблокирована." 13 | not_found_in_database: "Неверный номер или пароль." 14 | timeout: "Ваш сеанс закончился. Пожалуйста, войдите в систему снова." 15 | unauthenticated: "Вам необходимо войти в систему или зарегистрироваться." 16 | unconfirmed: "Вы должны подтвердить вашу учётную запись." 17 | mailer: 18 | confirmation_instructions: 19 | subject: "Инструкции по подтверждению учётной записи" 20 | reset_password_instructions: 21 | subject: "Инструкции по восстановлению пароля" 22 | unlock_instructions: 23 | subject: "Инструкции по разблокировке учётной записи" 24 | omniauth_callbacks: 25 | failure: "Вы не можете войти в систему с учётной записью из %{kind}б так как \"%{reason}\"." 26 | success: "Вход в систему выполнен с учётной записью из %{kind}." 27 | passwords: 28 | format: "Hеверный формат - должен содержать минимум 8 символов, включая одну строчную букву, заглавную букву и цифру." 29 | no_token: "Эта страница доступна только при переходе с email для сброса пароля. Если вы перешли по ссылке из письма, пожалуйста, убедитесь, что вы использовали полный URL." 30 | send_instructions: "В течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля." 31 | send_paranoid_instructions: "Если ваш адрес email есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля." 32 | updated: "Ваш пароль изменён. Теперь вы вошли в систему." 33 | updated_not_active: "Пароль успешно изменён." 34 | registrations: 35 | destroyed: "До свидания! Ваша учётная запись удалена. Надеемся снова увидеть вас." 36 | signed_up: "Добро пожаловать! Вы успешно зарегистрировались." 37 | signed_up_but_inactive: "Вы успешно зарегистрировались. Тем не менее, вы не можете войти, потому что ваша учетная запись не активирована." 38 | signed_up_but_locked: "Вы успешно зарегистрировались. Тем не менее, вы не можете войти, потому что ваша учетная запись заблокирована." 39 | signed_up_but_unconfirmed: "В течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи." 40 | updated: "Ваша учётная запись изменена." 41 | update_needs_confirmation: "Ваш аккаунт успешно обновлен, нонеобходимо подтвердить ваш новый адрес email. Пожалуйста, проверьте свою электронную почту и нажмите на ссылку \"Подтвердить\", чтобы завершить обновления email." 42 | sessions: 43 | signed_in: "Вход в систему выполнен." 44 | signed_out: "Выход из системы выполнен." 45 | unlocks: 46 | send_instructions: "В течение нескольких минут вы получите письмо с инструкциями по разблокировке вашей учётной записи." 47 | send_paranoid_instructions: "Если ваша учётная запись существует, то в течение нескольких минут вы получите письмо с инструкциями по её разблокировке." 48 | unlocked: "Ваша учётная запись разблокирована. Теперь вы вошли в систему." 49 | 50 | errors: 51 | messages: 52 | already_confirmed: "уже подтверждена. Пожалуйста, попробуйте войти в систему" 53 | confirmation_period_expired: "должен быть подтвержден в течении %{period}, пожалуйста, запросите подтверждение аккаунта завтра" 54 | expired: "устарела. Пожалуйста, запросите новую" 55 | not_found: "не найдена" 56 | not_locked: "не заблокирована" 57 | not_saved: 58 | one: "%{resource}: сохранение не удалось из-за %{count} ошибки" 59 | few: "%{resource}: сохранение не удалось из-за %{count} ошибок" 60 | many: "%{resource}: сохранение не удалось из-за %{count} ошибок" 61 | other: "%{resource}: сохранение не удалось из-за %{count} ошибки" 62 | -------------------------------------------------------------------------------- /spec/models/plan_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Plan do 4 | describe "Associations" do 5 | it { should belong_to(:user) } 6 | it { should have_many(:plan_items) } 7 | end 8 | 9 | describe "Auto weights" do 10 | let(:user) { create(:user) } 11 | 12 | before(:each) do 13 | user.settings << create(:setting, :var => "meals", :value => 3) 14 | user.settings << create(:setting, :var => "proteins", :value => 140) 15 | end 16 | 17 | it "should calculate one dish, all ingredients with protein" do 18 | 19 | dish = create(:flakes) 20 | 21 | ing_1 = create(:nestle_fitness) 22 | ing_2 = create(:milk) 23 | dish_com_1 = create(:dish_composition, :weight => 80, :dish => dish, :ingredient => ing_1) 24 | dish_com_2 = create(:dish_composition, :weight => 15, :dish => dish, :ingredient => ing_2) 25 | 26 | plan = create(:plan_second, :user => user, :meals_num => 3) 27 | plan_item_1 = create(:plan_item, :meal_id => 1, :plan => plan, :eatable => dish, :weight => 0) 28 | piing_1 = create(:plan_item_ingredient, :plan_item => plan_item_1, :ingredient => ing_1, :weight => 0) 29 | piing_2 = create(:plan_item_ingredient, :plan_item => plan_item_1, :ingredient => ing_2, :weight => 0) 30 | 31 | plan.auto_weights! 32 | 33 | piing_1.reload; piing_2.reload 34 | piing_1.weight.round(2).should == 426.14 35 | piing_2.weight.round(2).should == 236.79 36 | end 37 | 38 | context "ingredients with zero protein" do 39 | before(:each) do 40 | @dish = create(:omelet) 41 | # this is because there is one ingredient by default and weight changed after save 42 | @dish.ingredients.delete_all 43 | @dish.update_column(:weight, 158) 44 | 45 | @ing_1 = create(:glair) 46 | @ing_2 = create(:salt) 47 | @ing_3 = create(:cheese) 48 | @ing_4 = create(:sugar) 49 | @dish_com_1 = create(:dish_composition, :weight => 91, :dish => @dish, :ingredient => @ing_1) 50 | @dish_com_2 = create(:dish_composition, :weight => 5, :dish => @dish, :ingredient => @ing_2) 51 | @dish_com_3 = create(:dish_composition, :weight => 50, :dish => @dish, :ingredient => @ing_3) 52 | @dish_com_4 = create(:dish_composition, :weight => 12, :dish => @dish, :ingredient => @ing_4) 53 | 54 | @plan = create(:plan_second, :user => user, :meals_num => 3) 55 | @plan_item_1 = create(:plan_item, :meal_id => 1, :plan => @plan, :eatable => @dish, :weight => 0) 56 | @piing_1 = create(:plan_item_ingredient, :plan_item => @plan_item_1, :ingredient => @ing_1, :weight => 0) 57 | @piing_2 = create(:plan_item_ingredient, :plan_item => @plan_item_1, :ingredient => @ing_2, :weight => 0) 58 | @piing_3 = create(:plan_item_ingredient, :plan_item => @plan_item_1, :ingredient => @ing_3, :weight => 0) 59 | @piing_4 = create(:plan_item_ingredient, :plan_item => @plan_item_1, :ingredient => @ing_4, :weight => 0) 60 | end 61 | 62 | it "select ingredients with protein" do 63 | @plan_item_1.pi_ingredients_with_protein.should == [@piing_1, @piing_3] 64 | end 65 | 66 | it "select ingredients without protein" do 67 | @plan_item_1.pi_ingredients_without_protein.should include(@piing_2, @piing_4) 68 | @plan_item_1.pi_ingredients_without_protein.should_not include(@piing_1, @piing_3) 69 | end 70 | 71 | it "all ingredients percentage" do 72 | a = @plan_item_1.ingredients_percentage 73 | a[@piing_1.id].should == 57.59 74 | a[@piing_2.id].should == 3.16 75 | a[@piing_3.id].should == 31.65 76 | a[@piing_4.id].should == 7.59 77 | end 78 | 79 | it "ingredients with protein percentage" do 80 | a = @plan_item_1.ingredients_with_protein_percentage 81 | a.count.should == 2 82 | a[@piing_1.id].should == 64.54 83 | a[@piing_3.id].should == 35.46 84 | end 85 | 86 | it "weights auto calculating" do 87 | @plan.auto_weights! 88 | 89 | @piing_1.reload; @piing_2.reload; @piing_3.reload; @piing_4.reload 90 | @piing_1.weight.round(2).should == 213.46 91 | @piing_2.weight.round(2).should == 9.84 92 | @piing_3.weight.round(2).should == 64.18 93 | @piing_4.weight.round(2).should == 23.64 94 | 95 | end 96 | 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /spec/requests/admin/ingredient_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Ingredients" do 4 | include IngredientHelper 5 | 6 | let(:admin) { create(:user) } 7 | 8 | before(:each) do 9 | admin.add_rations 10 | login_as admin 11 | end 12 | 13 | describe "Index" do 14 | context "create new" do 15 | before(:each) do 16 | @ingredient = build(:ingredient) 17 | end 18 | 19 | it "should create for own ration" do 20 | visit admin_ingredients_path 21 | click_link('New Ingredient') 22 | 23 | page.should have_selector('h2', :text => "New Ingredient") 24 | 25 | fill_in "ingredient_name", :with => @ingredient.name 26 | fill_in "ingredient_portion", :with => @ingredient.portion 27 | click_button("Create Ingredient") 28 | 29 | current_path.should == admin_ingredients_path 30 | page.should have_selector('table tbody tr td.col-name', :text => @ingredient.name) 31 | end 32 | 33 | it "should create from ration" do 34 | default_ration = Ration.get_default 35 | default_ingredient = create(:ingredient, :user => default_ration.user, :ration => default_ration) 36 | 37 | visit admin_ingredients_path 38 | click_link('New Ingredient') 39 | 40 | within("span.action_item") do 41 | click_link "Rations" 42 | end 43 | 44 | click_link default_ration.name 45 | click_link default_ingredient.name 46 | 47 | click_button "Update Ingredient" 48 | 49 | current_path.should == admin_ingredients_path 50 | page.should have_selector('table tbody tr td.col-name', :text => default_ingredient.name) 51 | end 52 | 53 | it "should create without referer" do 54 | visit new_admin_ingredient_path 55 | 56 | fill_in "ingredient_name", :with => @ingredient.name 57 | fill_in "ingredient_portion", :with => @ingredient.portion 58 | click_button("Create Ingredient") 59 | 60 | page.should have_selector('h2', :text => @ingredient.name) 61 | end 62 | end 63 | 64 | context "edit" do 65 | before(:each) do 66 | @ingredient = create_ingredient_user_ration(:ingredient, admin) 67 | end 68 | 69 | it "should edit and return to index" do 70 | visit admin_ingredients_path 71 | 72 | within("tr#ingredient_#{@ingredient.id}") do 73 | click_link "Edit" 74 | end 75 | 76 | fill_in "ingredient_name", :with => "New one" 77 | click_button("Update Ingredient") 78 | 79 | page.should have_selector('h2', :text => "Ingredients") 80 | page.should have_selector('table tbody tr td.col-name', :text => "New one") 81 | end 82 | 83 | it "should edit and return to show" do 84 | visit admin_ingredient_path(@ingredient) 85 | 86 | click_link "Edit" 87 | fill_in "ingredient_name", :with => "New second" 88 | click_button "Update Ingredient" 89 | 90 | page.should have_selector('h2', :text => "New second") 91 | end 92 | 93 | end 94 | 95 | it "should eat ingredient" do 96 | ingredient = create_ingredient_user_ration(:ingredient_sample, admin) 97 | 98 | visit admin_ingredients_path 99 | 100 | page.should have_selector('h2', :text => "Ingredients") 101 | page.should have_selector('table tbody tr td.col-name', :text => ingredient.name) 102 | page.should have_selector('table tbody tr td.col-portion', :text => "#{ingredient.portion} g") 103 | page.should have_selector('table tbody tr td.col-proteins', :text => ingredient.proteins) 104 | page.should have_selector('table tbody tr td.col-fats', :text => ingredient.fats) 105 | page.should have_selector('table tbody tr td.col-carbs', :text => ingredient.carbs) 106 | 107 | click_link "Eat" 108 | 109 | page.should have_selector('h2', :text => "New Eaten") 110 | page.should have_selector('span', :text => "Ingredient '#{ingredient.name}'") 111 | 112 | fill_in "Weight", :with => "50" 113 | 114 | click_button "Create Eaten" 115 | 116 | page.should have_selector('h3', :text => "Eaten Details") 117 | page.should have_selector('.flash_notice', :text => "Eaten was successfully created.") 118 | 119 | visit admin_eatens_path 120 | 121 | page.should have_selector('h2', :text => "Eatens") 122 | page.should have_selector('table tbody tr td.col-eatable', :text => ingredient.name) 123 | page.should have_selector('table tbody tr td.col-weight', :text => "50") 124 | page.should have_selector('table tbody tr td.col-proteins', :text => "19.25") 125 | page.should have_selector('table tbody tr td.col-fats', :text => "30.25") 126 | page.should have_selector('table tbody tr td.col-carbs', :text => "41.25") 127 | 128 | end 129 | 130 | end 131 | end 132 | 133 | 134 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'spork' 3 | #uncomment the following line to use spork with the debugger 4 | #require 'spork/ext/ruby-debug' 5 | 6 | Spork.trap_method(Rails::Application::RoutesReloader, :reload!) if ENV['DRB'] 7 | 8 | Spork.prefork do 9 | # Loading more in this block will cause your tests to run faster. However, 10 | # if you change any configuration or code from libraries loaded here, you'll 11 | # need to restart spork for it take effect. 12 | 13 | # This file is copied to spec/ when you run 'rails generate rspec:install' 14 | ENV["RAILS_ENV"] ||= 'test' 15 | 16 | require 'rails/application' 17 | 18 | # Use of https://github.com/sporkrb/spork/wiki/Spork.trap_method-Jujutsu 19 | #Spork.trap_method(Rails::Application, :reload_routes!) 20 | #Spork.trap_method(Rails::Application::RoutesReloader, :reload!) 21 | 22 | # Prevent main application to eager_load in the prefork block (do not load files in autoload_paths) 23 | Spork.trap_method(Rails::Application, :eager_load!) 24 | 25 | require File.expand_path("../../config/environment", __FILE__) 26 | require 'rspec/rails' 27 | require 'rspec/autorun' 28 | 29 | # Requires supporting ruby files with custom matchers and macros, etc, 30 | # in spec/support/ and its subdirectories. 31 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 32 | 33 | # Checks for pending migrations before tests are run. 34 | # If you are not using ActiveRecord, you can remove this line. 35 | ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration) 36 | 37 | RSpec.configure do |config| 38 | # ## Mock Framework 39 | # 40 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 41 | # 42 | # config.mock_with :mocha 43 | # config.mock_with :flexmock 44 | # config.mock_with :rr 45 | 46 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 47 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 48 | 49 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 50 | # examples within a transaction, remove the following line or assign false 51 | # instead of true. 52 | config.use_transactional_fixtures = true 53 | 54 | # If true, the base class of anonymous controllers will be inferred 55 | # automatically. This will be the default behavior in future versions of 56 | # rspec-rails. 57 | config.infer_base_class_for_anonymous_controllers = false 58 | 59 | # Run specs in random order to surface order dependencies. If you find an 60 | # order dependency and want to debug it, you can fix the order by providing 61 | # the seed, which is printed after each run. 62 | # --seed 1234 63 | config.order = "random" 64 | 65 | config.include Capybara::DSL 66 | config.include Warden::Test::Helpers 67 | Warden.test_mode! 68 | end 69 | 70 | end 71 | 72 | Spork.each_run do 73 | if /spork/i =~ $0 || ENV['DRB'] == 'true' 74 | ActiveSupport::Dependencies.clear 75 | end 76 | 77 | require 'factory_girl_rails' 78 | 79 | # We can't use it because state_machine is loading twice :( 80 | # reload all the models 81 | #Dir["#{Rails.root}/app/models/**/*.rb"].each do |model| 82 | #load model 83 | #end 84 | 85 | # reload routes 86 | Rails.application.reload_routes! 87 | 88 | RSpec.configure do |config| 89 | config.include FactoryGirl::Syntax::Methods 90 | end 91 | 92 | end 93 | 94 | # --- Instructions --- 95 | # Sort the contents of this file into a Spork.prefork and a Spork.each_run 96 | # block. 97 | # 98 | # The Spork.prefork block is run only once when the spork server is started. 99 | # You typically want to place most of your (slow) initializer code in here, in 100 | # particular, require'ing any 3rd-party gems that you don't normally modify 101 | # during development. 102 | # 103 | # The Spork.each_run block is run each time you run your specs. In case you 104 | # need to load files that tend to change during development, require them here. 105 | # With Rails, your application modules are loaded automatically, so sometimes 106 | # this block can remain empty. 107 | # 108 | # Note: You can modify files loaded *from* the Spork.each_run block without 109 | # restarting the spork server. However, this file itself will not be reloaded, 110 | # so if you change any of the code inside the each_run block, you still need to 111 | # restart the server. In general, if you have non-trivial code in this file, 112 | # it's advisable to move it into a separate file so you can easily edit it 113 | # without restarting spork. (For example, with RSpec, you could move 114 | # non-trivial code into a file spec/support/my_helper.rb, making sure that the 115 | # spec/support/* files are require'd from inside the each_run block.) 116 | # 117 | # Any code that is left outside the two blocks will be run during preforking 118 | # *and* during each_run -- that's probably not what you want. 119 | # 120 | # These instructions should self-destruct in 10 seconds. If they don't, feel 121 | # free to delete them. 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/admin/ingredients.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register Ingredient do 2 | menu :priority => 5, :parent => I18n.t("menu.food") 3 | config.batch_actions = false 4 | config.clear_action_items! #unless can? :create, Ingredient 5 | 6 | breadcrumb do 7 | crumbs = [ 8 | link_to("admin", admin_root_path) 9 | ] 10 | 11 | if params[:ration_id] 12 | ration = Ration.find(params[:ration_id]) 13 | 14 | crumbs += [link_to("rations", admin_rations_path)] 15 | crumbs += [link_to(ration.name, admin_ration_path(ration))] 16 | end 17 | crumbs 18 | end 19 | 20 | collection_action :eaten_autocomplete_list, :method => :get do 21 | items = Ingredient.autocomplete_list(current_user, params[:term]) 22 | res = items.collect do |item| 23 | hash = {"id" => item.id.to_s, "label" => item.send(:name), "value" => item.send(:name)} 24 | #extra_data.each do |datum| 25 | #hash[datum] = item.send(datum) 26 | #end if extra_data 27 | # TODO: Come back to remove this if clause when test suite is better 28 | #hash 29 | end 30 | render :json => res 31 | end 32 | 33 | collection_action :rations_list, :method => :get, :title => "Rations" do 34 | render :template => "admin/ingredients/rations", :locals => {:rations => current_user.all_rations} 35 | end 36 | 37 | member_action :copy_to_my, :method => :post do 38 | ingredient = Ingredient.find params[:id] 39 | new_ingredient = ingredient.dup 40 | new_ingredient.user = current_user 41 | new_ingredient.ration_id = current_user.setting(:ration) 42 | 43 | if new_ingredient.save 44 | flash[:notice] = "Ingredient copied" 45 | 46 | case params[:redirect] 47 | when "edit_selected" 48 | redirect_to edit_admin_ingredient_path(new_ingredient) 49 | else 50 | redirect_to request.referer 51 | end 52 | else 53 | flash[:error] = "Ingredient NOT copied" 54 | redirect_to request.referer 55 | end 56 | 57 | end 58 | 59 | action_item :only => [:index] do 60 | link_to "New Ingredient", new_admin_ingredient_path 61 | end 62 | 63 | action_item :only => [:show] do 64 | ingredient_links(resource) 65 | end 66 | 67 | action_item :only => [:new] do 68 | link_to("Rations", rations_list_admin_ingredients_path, :title => "Copy from rations") 69 | end 70 | 71 | filter :name 72 | filter :group, :as => :select, :collection => IngredientGroup.all 73 | filter :proteins 74 | filter :fats 75 | filter :carbs 76 | 77 | index do 78 | #selectable_column 79 | #column :id 80 | column :name do |c| 81 | auto_link c, c.name 82 | end 83 | column :group 84 | column :portion do |p| 85 | portion_caption(p) 86 | end 87 | column :proteins 88 | column :fats 89 | column :carbs 90 | column :kcal 91 | 92 | column "" do |resource| 93 | ingredient_links(resource) 94 | end 95 | end 96 | 97 | form do |f| 98 | f.form_buffers.last << Arbre::Context.new({}, f.template) do 99 | div link_to("Return to start", session[:ingredient_referer]) 100 | end 101 | 102 | f.inputs do 103 | f.input :name 104 | f.input :group 105 | f.input :portion 106 | f.input :portion_unit, :collection => Ingredient::PORTION_UNITS.invert, :default => :gramm 107 | f.input :proteins 108 | f.input :fats 109 | f.input :carbs 110 | end 111 | f.actions 112 | end 113 | 114 | #collection_action :autocomplete_ingredient_name, :method => :get 115 | 116 | controller do 117 | #autocomplete :ingredient, :name 118 | #layout 'active_admin' 119 | 120 | def scoped_collection 121 | if params[:ration_id] 122 | Ingredient.by_ration params[:ration_id] 123 | else 124 | current_user.all_ingredients 125 | end 126 | end 127 | 128 | def new 129 | new! { 130 | session[:ingredient_referer] = request.referer 131 | } 132 | end 133 | 134 | def edit 135 | super { 136 | session[:ingredient_referer] ||= request.referer 137 | } 138 | end 139 | 140 | def show 141 | @ingredient = Ingredient.find(params[:id]) 142 | end 143 | 144 | def create 145 | super do |success, failure| 146 | success.html { 147 | @ingredient.update_column(:user_id, current_user.id) 148 | @ingredient.update_column(:ration_id, current_user.setting(:ration)) 149 | 150 | redirect_to redirect_referer(@ingredient) 151 | } 152 | end 153 | end 154 | 155 | def update 156 | super do |success, failure| 157 | success.html { 158 | redirect_to redirect_referer(@ingredient) 159 | } 160 | end 161 | end 162 | 163 | private 164 | def redirect_referer(ingredient) 165 | if session[:ingredient_referer].blank? 166 | redirect_path = admin_ingredient_path(ingredient) 167 | else 168 | redirect_path = session[:ingredient_referer] 169 | session[:ingredient_referer] = nil 170 | end 171 | redirect_path 172 | end 173 | 174 | end 175 | end 176 | --------------------------------------------------------------------------------