├── app
├── mailers
│ └── .keep
├── models
│ ├── .keep
│ ├── concerns
│ │ └── .keep
│ ├── product.rb
│ ├── invoice.rb
│ ├── line_item.rb
│ └── download.rb
├── assets
│ ├── images
│ │ └── .keep
│ ├── stylesheets
│ │ ├── base
│ │ │ ├── _base.scss
│ │ │ ├── _grid-settings.scss
│ │ │ ├── _tables.scss
│ │ │ ├── _lists.scss
│ │ │ ├── _buttons.scss
│ │ │ ├── _typography.scss
│ │ │ ├── _variables.scss
│ │ │ └── _forms.scss
│ │ ├── application.scss
│ │ ├── refills
│ │ │ └── _flashes.scss
│ │ └── invoice_pdf.scss
│ └── javascripts
│ │ └── application.js
├── views
│ ├── pages
│ │ └── .keep
│ ├── application
│ │ ├── _flashes.html.erb
│ │ ├── _javascript.html.erb
│ │ └── _analytics.html.erb
│ ├── invoices
│ │ ├── index.html.erb
│ │ ├── show.html.erb
│ │ └── pdf.html.erb
│ └── layouts
│ │ ├── invoice_pdf.html.erb
│ │ └── application.html.erb
├── controllers
│ ├── concerns
│ │ └── .keep
│ ├── invoices_controller.rb
│ ├── application_controller.rb
│ └── downloads_controller.rb
└── helpers
│ ├── application_helper.rb
│ └── flashes_helper.rb
├── lib
├── assets
│ └── .keep
├── tasks
│ ├── .keep
│ ├── bundler_audit.rake
│ └── dev.rake
└── templates
│ └── erb
│ └── scaffold
│ └── _form.html.erb
├── public
├── favicon.ico
├── robots.txt
├── 500.html
├── 422.html
└── 404.html
├── spec
├── helpers
│ └── .keep
├── lib
│ └── .keep
├── controllers
│ └── .keep
├── features
│ ├── .keep
│ └── user_downloads_invoice_pdf_spec.rb
├── support
│ ├── features
│ │ └── .keep
│ ├── matchers
│ │ └── .keep
│ ├── mixins
│ │ └── .keep
│ ├── shared_examples
│ │ └── .keep
│ ├── i18n.rb
│ ├── factory_girl.rb
│ ├── action_mailer.rb
│ ├── capybara_webkit.rb
│ ├── shoulda_matchers.rb
│ └── database_cleaner.rb
├── models
│ ├── invoice_spec.rb
│ ├── product_spec.rb
│ └── line_item_spec.rb
├── i18n_spec.rb
├── factories.rb
├── spec_helper.rb
└── rails_helper.rb
├── .ruby-version
├── vendor
└── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
├── .rspec
├── browserslist
├── config
├── initializers
│ ├── json_encoding.rb
│ ├── disable_xml_params.rb
│ ├── cookies_serializer.rb
│ ├── session_store.rb
│ ├── mime_types.rb
│ ├── filter_parameter_logging.rb
│ ├── backtrace_silencers.rb
│ ├── assets.rb
│ ├── wrap_parameters.rb
│ ├── inflections.rb
│ ├── errors.rb
│ └── simple_form.rb
├── environment.rb
├── boot.rb
├── routes.rb
├── environments
│ ├── staging.rb
│ ├── test.rb
│ ├── development.rb
│ └── production.rb
├── secrets.yml
├── i18n-tasks.yml
├── smtp.rb
├── locales
│ ├── en.yml
│ └── simple_form.en.yml
├── database.yml
├── newrelic.yml
└── application.rb
├── Procfile
├── bin
├── bundle
├── delayed_job
├── rspec
├── rake
├── rails
├── spring
└── setup
├── circle.yml
├── config.ru
├── .gitignore
├── db
├── migrate
│ ├── 20151222025546_create_products.rb
│ ├── 20151222031031_create_invoices.rb
│ ├── 20151222034730_create_line_items.rb
│ └── 20151222024559_create_delayed_jobs.rb
├── seeds.rb
└── schema.rb
├── .sample.env
├── .hound.yml
├── Rakefile
├── Gemfile
├── README.md
└── Gemfile.lock
/app/mailers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/helpers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/lib/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.2.3
2 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/pages/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/controllers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/features/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/support/features/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/support/matchers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/support/mixins/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/support/shared_examples/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/app/models/product.rb:
--------------------------------------------------------------------------------
1 | class Product < ActiveRecord::Base
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/browserslist:
--------------------------------------------------------------------------------
1 | Last 2 versions
2 | Explorer >= 9
3 | iOS >= 7.1
4 | Android >= 4.4
5 |
--------------------------------------------------------------------------------
/config/initializers/json_encoding.rb:
--------------------------------------------------------------------------------
1 | ActiveSupport::JSON::Encoding.time_precision = 0
2 |
--------------------------------------------------------------------------------
/app/models/invoice.rb:
--------------------------------------------------------------------------------
1 | class Invoice < ActiveRecord::Base
2 | has_many :line_items
3 | end
4 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec puma -p $PORT -C ./config/puma.rb
2 | worker: bundle exec rake jobs:work
3 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../application', __FILE__)
2 | Rails.application.initialize!
3 |
--------------------------------------------------------------------------------
/config/initializers/disable_xml_params.rb:
--------------------------------------------------------------------------------
1 | ActionDispatch::ParamsParser::DEFAULT_PARSERS.delete(Mime::XML)
2 |
--------------------------------------------------------------------------------
/spec/support/i18n.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include AbstractController::Translation
3 | end
4 |
--------------------------------------------------------------------------------
/spec/support/factory_girl.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include FactoryGirl::Syntax::Methods
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/line_item.rb:
--------------------------------------------------------------------------------
1 | class LineItem < ActiveRecord::Base
2 | belongs_to :invoice
3 | belongs_to :product
4 | end
5 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/spec/support/action_mailer.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.before(:each) do
3 | ActionMailer::Base.deliveries.clear
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/spec/support/capybara_webkit.rb:
--------------------------------------------------------------------------------
1 | Capybara.javascript_driver = :webkit
2 |
3 | Capybara::Webkit.configure do |config|
4 | config.block_unknown_urls
5 | end
6 |
--------------------------------------------------------------------------------
/app/helpers/flashes_helper.rb:
--------------------------------------------------------------------------------
1 | module FlashesHelper
2 | def user_facing_flashes
3 | flash.to_hash.slice("alert", "error", "notice", "success")
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | checkout:
2 | post:
3 | - cp .sample.env .env
4 | database:
5 | override:
6 | - bin/setup
7 | test:
8 | override:
9 | - bin/rake
10 |
--------------------------------------------------------------------------------
/spec/models/invoice_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Invoice, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/product_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Product, type: :model 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 |
--------------------------------------------------------------------------------
/spec/models/line_item_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe LineItem, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_invoicer_session'
4 |
--------------------------------------------------------------------------------
/spec/support/shoulda_matchers.rb:
--------------------------------------------------------------------------------
1 | Shoulda::Matchers.configure do |config|
2 | config.integrate do |with|
3 | with.test_framework :rspec
4 | with.library :rails
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | !.keep
2 | *.DS_Store
3 | *.swo
4 | *.swp
5 | /.bundle
6 | /.env
7 | /coverage/*
8 | /db/*.sqlite3
9 | /log/*
10 | /public/system
11 | /public/assets
12 | /tags
13 | /tmp/*
14 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root to: "invoices#index"
3 |
4 | resources :invoices, only: [:index, :show] do
5 | resource :download, only: [:show]
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/bin/delayed_job:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
4 | require 'delayed/command'
5 | Delayed::Command.new(ARGV).daemonize
6 |
--------------------------------------------------------------------------------
/config/environments/staging.rb:
--------------------------------------------------------------------------------
1 | require_relative "production"
2 |
3 | Mail.register_interceptor(
4 | RecipientInterceptor.new(ENV.fetch("EMAIL_RECIPIENTS"))
5 | )
6 |
7 | Rails.application.configure do
8 | # ...
9 | end
10 |
--------------------------------------------------------------------------------
/app/controllers/invoices_controller.rb:
--------------------------------------------------------------------------------
1 | class InvoicesController < ApplicationController
2 | def index
3 | @invoices = Invoice.all
4 | end
5 |
6 | def show
7 | @invoice = Invoice.find(params[:id])
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.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/views/application/_flashes.html.erb:
--------------------------------------------------------------------------------
1 | <% if flash.any? %>
2 |
3 | <% user_facing_flashes.each do |key, value| -%>
4 |
<%= value %>
5 | <% end -%>
6 |
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/bin/rspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require 'bundler/setup'
8 | load Gem.bin_path('rspec-core', 'rspec')
9 |
--------------------------------------------------------------------------------
/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/secrets.yml:
--------------------------------------------------------------------------------
1 | default: &default
2 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
3 |
4 | development:
5 | <<: *default
6 |
7 | test:
8 | <<: *default
9 |
10 | staging:
11 | <<: *default
12 |
13 | production:
14 | <<: *default
15 |
--------------------------------------------------------------------------------
/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 | end
6 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/config/i18n-tasks.yml:
--------------------------------------------------------------------------------
1 | search:
2 | paths:
3 | - "app/controllers"
4 | - "app/helpers"
5 | - "app/presenters"
6 | - "app/views"
7 |
8 | ignore_unused:
9 | - activerecord.*
10 | - date.*
11 | - simple_form.*
12 | - time.*
13 | - titles.*
14 |
--------------------------------------------------------------------------------
/app/views/invoices/index.html.erb:
--------------------------------------------------------------------------------
1 | Invoices
2 |
3 | <% @invoices.each do |invoice| %>
4 |
5 | -
6 | <%= link_to invoice.number, invoice %> - <%= invoice.line_items.count %> lines -- <%= invoice.date %>
7 |
8 |
9 | <% end %>
10 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../../config/application', __FILE__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/db/migrate/20151222025546_create_products.rb:
--------------------------------------------------------------------------------
1 | class CreateProducts < ActiveRecord::Migration
2 | def change
3 | create_table :products do |t|
4 | t.string :description
5 | t.string :item_number
6 | t.money :price
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/.sample.env:
--------------------------------------------------------------------------------
1 | # https://github.com/ddollar/forego
2 | ASSET_HOST=localhost:3000
3 | APPLICATION_HOST=localhost:3000
4 | RACK_ENV=development
5 | SECRET_KEY_BASE=development_secret
6 | EXECJS_RUNTIME=Node
7 | SMTP_ADDRESS=smtp.example.com
8 | SMTP_DOMAIN=example.com
9 | SMTP_PASSWORD=password
10 | SMTP_USERNAME=username
11 |
--------------------------------------------------------------------------------
/app/views/application/_javascript.html.erb:
--------------------------------------------------------------------------------
1 | <%= javascript_include_tag :application %>
2 |
3 | <%= yield :javascript %>
4 |
5 | <%= render "analytics" %>
6 |
7 | <% if Rails.env.test? %>
8 | <%= javascript_tag do %>
9 | $.fx.off = true;
10 | $.ajaxSetup({ async: false });
11 | <% end %>
12 | <% end %>
13 |
--------------------------------------------------------------------------------
/db/migrate/20151222031031_create_invoices.rb:
--------------------------------------------------------------------------------
1 | class CreateInvoices < ActiveRecord::Migration
2 | def change
3 | create_table :invoices do |t|
4 | t.string :account
5 | t.string :number
6 | t.date :date
7 | t.text :notes
8 |
9 | t.timestamps null: false
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/config/smtp.rb:
--------------------------------------------------------------------------------
1 | SMTP_SETTINGS = {
2 | address: ENV.fetch("SMTP_ADDRESS"), # example: "smtp.sendgrid.net"
3 | authentication: :plain,
4 | domain: ENV.fetch("SMTP_DOMAIN"), # example: "heroku.com"
5 | enable_starttls_auto: true,
6 | password: ENV.fetch("SMTP_PASSWORD"),
7 | port: "587",
8 | user_name: ENV.fetch("SMTP_USERNAME")
9 | }
10 |
--------------------------------------------------------------------------------
/db/migrate/20151222034730_create_line_items.rb:
--------------------------------------------------------------------------------
1 | class CreateLineItems < ActiveRecord::Migration
2 | def change
3 | create_table :line_items do |t|
4 | t.belongs_to :invoice, index: true, foreign_key: true
5 | t.integer :quantity
6 | t.references :product
7 |
8 | t.timestamps null: false
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/tasks/bundler_audit.rake:
--------------------------------------------------------------------------------
1 | if Rails.env.development? || Rails.env.test?
2 | require "bundler/audit/cli"
3 |
4 | namespace :bundler do
5 | desc "Updates the ruby-advisory-db and runs audit"
6 | task :audit do
7 | %w(update check).each do |command|
8 | Bundler::Audit::CLI.start [command]
9 | end
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | date:
3 | formats:
4 | default:
5 | "%m/%d/%Y"
6 | with_weekday:
7 | "%a %m/%d/%y"
8 |
9 | time:
10 | formats:
11 | default:
12 | "%a, %b %-d, %Y at %r"
13 | date:
14 | "%b %-d, %Y"
15 | short:
16 | "%B %d"
17 |
18 | titles:
19 | application: Invoicer
20 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_base.scss:
--------------------------------------------------------------------------------
1 | // Bitters 1.1.0
2 | // http://bitters.bourbon.io
3 | // Copyright 2013-2015 thoughtbot, inc.
4 | // MIT License
5 |
6 | @import "variables";
7 |
8 | // Neat Settings -- uncomment if using Neat -- must be imported before Neat
9 | // @import "grid-settings";
10 |
11 | @import "buttons";
12 | @import "forms";
13 | @import "lists";
14 | @import "tables";
15 | @import "typography";
16 |
--------------------------------------------------------------------------------
/lib/templates/erb/scaffold/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
2 | <%%= f.error_notification %>
3 |
4 |
5 | <%- attributes.each do |attribute| -%>
6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %>
7 | <%- end -%>
8 |
9 |
10 |
11 | <%%= f.button :submit %>
12 |
13 | <%% end %>
14 |
--------------------------------------------------------------------------------
/app/views/layouts/invoice_pdf.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 | <%= yield %>
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/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/assets/stylesheets/base/_grid-settings.scss:
--------------------------------------------------------------------------------
1 | @import "neat-helpers"; // or "../neat/neat-helpers" when not in Rails
2 |
3 | // Neat Overrides
4 | // $column: 90px;
5 | // $gutter: 30px;
6 | // $grid-columns: 12;
7 | // $max-width: 1200px;
8 |
9 | // Neat Breakpoints
10 | $medium-screen: 600px;
11 | $large-screen: 900px;
12 |
13 | $medium-screen-up: new-breakpoint(min-width $medium-screen 4);
14 | $large-screen-up: new-breakpoint(min-width $large-screen 8);
15 |
--------------------------------------------------------------------------------
/.hound.yml:
--------------------------------------------------------------------------------
1 | # See https://houndci.com/configuration for help.
2 | coffeescript:
3 | # config_file: .coffeescript-style.json
4 | enabled: true
5 | haml:
6 | # config_file: .haml-style.yml
7 | enabled: true
8 | javascript:
9 | # config_file: .javascript-style.json
10 | enabled: true
11 | # ignore_file: .javascript_ignore
12 | ruby:
13 | # config_file: .ruby-style.yml
14 | enabled: true
15 | scss:
16 | # config_file: .scss-style.yml
17 | enabled: true
18 |
--------------------------------------------------------------------------------
/spec/support/database_cleaner.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.before(:suite) do
3 | DatabaseCleaner.clean_with(:deletion)
4 | end
5 |
6 | config.before(:each) do
7 | DatabaseCleaner.strategy = :transaction
8 | end
9 |
10 | config.before(:each, js: true) do
11 | DatabaseCleaner.strategy = :deletion
12 | end
13 |
14 | config.before(:each) do
15 | DatabaseCleaner.start
16 | end
17 |
18 | config.after(:each) do
19 | DatabaseCleaner.clean
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/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 | Rails.application.load_tasks
7 | task(:default).clear
8 | task default: [:spec]
9 |
10 | if defined? RSpec
11 | task(:spec).clear
12 | RSpec::Core::RakeTask.new(:spec) do |t|
13 | t.verbose = false
14 | end
15 | end
16 |
17 | task default: "bundler:audit"
18 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq }
12 | gem 'spring', match[1]
13 | require 'spring/binstub'
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_tables.scss:
--------------------------------------------------------------------------------
1 | table {
2 | border-collapse: collapse;
3 | font-feature-settings: "kern", "liga", "tnum";
4 | margin: $small-spacing 0;
5 | table-layout: fixed;
6 | width: 100%;
7 | }
8 |
9 | th {
10 | border-bottom: 1px solid shade($base-border-color, 25%);
11 | font-weight: 600;
12 | padding: $small-spacing 0;
13 | text-align: left;
14 | }
15 |
16 | td {
17 | border-bottom: $base-border;
18 | padding: $small-spacing 0;
19 | }
20 |
21 | tr,
22 | td,
23 | th {
24 | vertical-align: middle;
25 | }
26 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/i18n_spec.rb:
--------------------------------------------------------------------------------
1 | require 'i18n/tasks'
2 |
3 | RSpec.describe 'I18n' do
4 | let(:i18n) { I18n::Tasks::BaseTask.new }
5 | let(:missing_keys) { i18n.missing_keys }
6 | let(:unused_keys) { i18n.unused_keys }
7 |
8 | it 'does not have missing keys' do
9 | expect(missing_keys).to be_empty,
10 | "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
11 | end
12 |
13 | it 'does not have unused keys' do
14 | expect(unused_keys).to be_empty,
15 | "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_lists.scss:
--------------------------------------------------------------------------------
1 | ul,
2 | ol {
3 | list-style-type: none;
4 | margin: 0;
5 | padding: 0;
6 |
7 | &%default-ul {
8 | list-style-type: disc;
9 | margin-bottom: $small-spacing;
10 | padding-left: $base-spacing;
11 | }
12 |
13 | &%default-ol {
14 | list-style-type: decimal;
15 | margin-bottom: $small-spacing;
16 | padding-left: $base-spacing;
17 | }
18 | }
19 |
20 | dl {
21 | margin-bottom: $small-spacing;
22 |
23 | dt {
24 | font-weight: bold;
25 | margin-top: $small-spacing;
26 | }
27 |
28 | dd {
29 | margin: 0;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | @import "normalize-rails";
4 | @import "bourbon";
5 | @import "base/grid-settings";
6 | @import "neat";
7 | @import "base/base";
8 | @import "refills/flashes";
9 |
10 | .container {
11 | margin: 30px auto;
12 | max-width: 980px;
13 | }
14 |
15 |
16 | .line-items {
17 | .quantity {
18 | width: 15%;
19 | }
20 |
21 | .item-number {
22 | width: 15%;
23 | }
24 |
25 | .description {
26 | width: 50%;
27 | }
28 |
29 | .unit-price, .total {
30 | width: 10%;
31 | }
32 | }
33 |
34 | .download {
35 | @include button(simple)
36 | }
37 |
--------------------------------------------------------------------------------
/spec/factories.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :invoice do
3 | account { "#{Random.rand(10..99)}-#{Random.rand(10000..99999)}" }
4 | number { "#{Random.rand(1..9)}-#{Random.rand(10..99)}-#{Random.rand(10000..99999)}" }
5 | date { Random.rand(1..25).days.ago }
6 | notes "Make sure to deliver between 3:15 and 3:28, otherwise Mike is likely to be on break."
7 | end
8 |
9 | factory :product do
10 | description "A multi-purpose tool"
11 | item_number "tool-124-ab2"
12 | price 29.95
13 | end
14 |
15 | factory :line_item do
16 | invoice
17 | quantity { Random.rand(1..9) }
18 | product
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/models/download.rb:
--------------------------------------------------------------------------------
1 | require "render_anywhere"
2 |
3 | class Download
4 | include RenderAnywhere
5 |
6 | def initialize(invoice)
7 | @invoice = invoice
8 | end
9 |
10 | def to_pdf
11 | kit = PDFKit.new(as_html)
12 | kit.to_file("tmp/invoice.pdf")
13 | end
14 |
15 | def filename
16 | "Invoice #{invoice.number}.pdf"
17 | end
18 |
19 | def render_attributes
20 | {
21 | template: "invoices/pdf",
22 | layout: "invoice_pdf",
23 | locals: { invoice: invoice }
24 | }
25 | end
26 |
27 | private
28 |
29 | attr_reader :invoice
30 |
31 | def as_html
32 | render render_attributes
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | development: &default
2 | adapter: postgresql
3 | database: invoicer_development
4 | encoding: utf8
5 | host: localhost
6 | min_messages: warning
7 | pool: <%= Integer(ENV.fetch("DB_POOL", 5)) %>
8 | reaping_frequency: <%= Integer(ENV.fetch("DB_REAPING_FREQUENCY", 10)) %>
9 | timeout: 5000
10 |
11 | test:
12 | <<: *default
13 | database: invoicer_test
14 |
15 | production: &deploy
16 | encoding: utf8
17 | min_messages: warning
18 | pool: <%= [Integer(ENV.fetch("MAX_THREADS", 5)), Integer(ENV.fetch("DB_POOL", 5))].max %>
19 | timeout: 5000
20 | url: <%= ENV.fetch("DATABASE_URL", "") %>
21 |
22 | staging: *deploy
23 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | if ENV.fetch("COVERAGE", false)
2 | require "simplecov"
3 | SimpleCov.start "rails"
4 | end
5 |
6 | require "webmock/rspec"
7 |
8 | # http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9 | RSpec.configure do |config|
10 | config.expect_with :rspec do |expectations|
11 | expectations.syntax = :expect
12 | end
13 |
14 | config.mock_with :rspec do |mocks|
15 | mocks.syntax = :expect
16 | mocks.verify_partial_doubles = true
17 | end
18 |
19 | config.example_status_persistence_file_path = "tmp/rspec_examples.txt"
20 | config.order = :random
21 | end
22 |
23 | WebMock.disable_net_connect!(allow_localhost: true)
24 |
--------------------------------------------------------------------------------
/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 any plugin's vendor/assets/javascripts directory 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/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%#
8 | Configure default and controller-, and view-specific titles in
9 | config/locales/en.yml. For more see:
10 | https://github.com/calebthompson/title#usage
11 | %>
12 | <%= title %>
13 | <%= stylesheet_link_tag :application, media: "all" %>
14 | <%= csrf_meta_tags %>
15 |
16 |
17 |
18 | <%= render "flashes" -%>
19 | <%= yield %>
20 | <%= render "javascript" %>
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # Set up Rails app. Run this script immediately after cloning the codebase.
4 | # https://github.com/thoughtbot/guides/tree/master/protocol
5 |
6 | # Exit if any subcommand fails
7 | set -e
8 |
9 | # Set up Ruby dependencies via Bundler
10 | gem install bundler --conservative
11 | bundle check || bundle install
12 |
13 | # Set up configurable environment variables
14 | if [ ! -f .env ]; then
15 | cp .sample.env .env
16 | fi
17 |
18 | # Set up database and add any development seed data
19 | bin/rake dev:prime
20 |
21 | # Add binstubs to PATH via export PATH=".git/safe/../../bin:$PATH" in ~/.zshenv
22 | mkdir -p .git/safe
23 |
24 | # Only if this isn't CI
25 | # if [ -z "$CI" ]; then
26 | # fi
27 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] = "test"
2 |
3 | require File.expand_path("../../config/environment", __FILE__)
4 | abort("DATABASE_URL environment variable is set") if ENV["DATABASE_URL"]
5 |
6 | require "rspec/rails"
7 |
8 | Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |file| require file }
9 |
10 | module Features
11 | # Extend this module in spec/support/features/*.rb
12 | include Formulaic::Dsl
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.include Features, type: :feature
17 | config.infer_base_class_for_anonymous_controllers = false
18 | config.infer_spec_type_from_file_location!
19 | config.use_transactional_fixtures = false
20 | end
21 |
22 | ActiveRecord::Migration.maintain_test_schema!
23 |
--------------------------------------------------------------------------------
/config/initializers/errors.rb:
--------------------------------------------------------------------------------
1 | require "net/http"
2 | require "net/smtp"
3 |
4 | # Example:
5 | # begin
6 | # some http call
7 | # rescue *HTTP_ERRORS => error
8 | # notify_hoptoad error
9 | # end
10 |
11 | HTTP_ERRORS = [
12 | EOFError,
13 | Errno::ECONNRESET,
14 | Errno::EINVAL,
15 | Net::HTTPBadResponse,
16 | Net::HTTPHeaderSyntaxError,
17 | Net::ProtocolError,
18 | Timeout::Error
19 | ]
20 |
21 | SMTP_SERVER_ERRORS = [
22 | IOError,
23 | Net::SMTPAuthenticationError,
24 | Net::SMTPServerBusy,
25 | Net::SMTPUnknownError,
26 | TimeoutError
27 | ]
28 |
29 | SMTP_CLIENT_ERRORS = [
30 | Net::SMTPFatalError,
31 | Net::SMTPSyntaxError
32 | ]
33 |
34 | SMTP_ERRORS = SMTP_SERVER_ERRORS + SMTP_CLIENT_ERRORS
35 |
--------------------------------------------------------------------------------
/app/controllers/downloads_controller.rb:
--------------------------------------------------------------------------------
1 | class DownloadsController < ApplicationController
2 | def show
3 | respond_to do |format|
4 | format.pdf { send_invoice_pdf }
5 |
6 | if Rails.env.development?
7 | format.html { render_sample_html }
8 | end
9 | end
10 | end
11 |
12 | private
13 |
14 | def invoice
15 | Invoice.find(params[:invoice_id])
16 | end
17 |
18 | def download
19 | Download.new(invoice)
20 | end
21 |
22 | def send_invoice_pdf
23 | send_file download.to_pdf, download_attributes
24 | end
25 |
26 | def render_sample_html
27 | render download.render_attributes
28 | end
29 |
30 | def download_attributes
31 | {
32 | filename: download.filename,
33 | type: "application/pdf",
34 | disposition: "inline"
35 | }
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | config.assets.raise_runtime_errors = true
3 | config.cache_classes = true
4 | config.eager_load = false
5 | config.serve_static_files = true
6 | config.static_cache_control = 'public, max-age=3600'
7 | config.consider_all_requests_local = true
8 | config.action_controller.perform_caching = false
9 | config.action_dispatch.show_exceptions = false
10 | config.action_controller.allow_forgery_protection = false
11 | config.action_mailer.delivery_method = :test
12 | config.active_support.test_order = :random
13 | config.active_support.deprecation = :stderr
14 | config.action_view.raise_on_missing_translations = true
15 | config.action_mailer.default_url_options = { host: "www.example.com" }
16 | config.active_job.queue_adapter = :inline
17 | end
18 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | config.cache_classes = false
3 | config.eager_load = false
4 | config.consider_all_requests_local = true
5 | config.action_controller.perform_caching = false
6 | config.action_mailer.raise_delivery_errors = true
7 | config.after_initialize do
8 | Bullet.enable = true
9 | Bullet.bullet_logger = true
10 | Bullet.rails_logger = true
11 | end
12 | config.action_mailer.delivery_method = :test
13 | config.active_support.deprecation = :log
14 | config.active_record.migration_error = :page_load
15 | config.assets.debug = true
16 | config.assets.digest = true
17 | config.assets.raise_runtime_errors = true
18 | config.action_view.raise_on_missing_translations = true
19 | config.action_mailer.default_url_options = { host: "localhost:3000" }
20 | end
21 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/refills/_flashes.scss:
--------------------------------------------------------------------------------
1 | $base-spacing: 1.5em !default;
2 | $alert-color: #fff6bf !default;
3 | $error-color: #fbe3e4 !default;
4 | $notice-color: #e5edf8 !default;
5 | $success-color: #e6efc2 !default;
6 |
7 | @mixin flash($color) {
8 | background-color: $color;
9 | color: darken($color, 60%);
10 | display: block;
11 | font-weight: 600;
12 | margin-bottom: $base-spacing / 2;
13 | padding: $base-spacing / 2;
14 | text-align: center;
15 |
16 | a {
17 | color: darken($color, 70%);
18 |
19 | &:focus,
20 | &:hover {
21 | color: darken($color, 90%);
22 | }
23 | }
24 | }
25 |
26 | .flash-alert {
27 | @include flash($alert-color);
28 | }
29 |
30 | .flash-error {
31 | @include flash($error-color);
32 | }
33 |
34 | .flash-notice {
35 | @include flash($notice-color);
36 | }
37 |
38 | .flash-success {
39 | @include flash($success-color);
40 | }
41 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_buttons.scss:
--------------------------------------------------------------------------------
1 | #{$all-buttons} {
2 | appearance: none;
3 | background-color: $action-color;
4 | border: 0;
5 | border-radius: $base-border-radius;
6 | color: #fff;
7 | cursor: pointer;
8 | display: inline-block;
9 | font-family: $base-font-family;
10 | font-size: $base-font-size;
11 | -webkit-font-smoothing: antialiased;
12 | font-weight: 600;
13 | line-height: 1;
14 | padding: $small-spacing $base-spacing;
15 | text-decoration: none;
16 | transition: background-color $base-duration $base-timing;
17 | user-select: none;
18 | vertical-align: middle;
19 | white-space: nowrap;
20 |
21 | &:hover,
22 | &:focus {
23 | background-color: shade($action-color, 20%);
24 | color: #fff;
25 | }
26 |
27 | &:disabled {
28 | cursor: not-allowed;
29 | opacity: 0.5;
30 |
31 | &:hover {
32 | background-color: $action-color;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/config/newrelic.yml:
--------------------------------------------------------------------------------
1 | common: &default_settings
2 | app_name: "invoicer"
3 | audit_log:
4 | enabled: false
5 | browser_monitoring:
6 | auto_instrument: true
7 | capture_params: false
8 | developer_mode: false
9 | error_collector:
10 | capture_source: true
11 | enabled: true
12 | ignore_errors: "ActionController::RoutingError,Sinatra::NotFound"
13 | license_key: "<%= ENV["NEW_RELIC_LICENSE_KEY"] %>"
14 | log_level: info
15 | monitor_mode: true
16 | transaction_tracer:
17 | enabled: true
18 | record_sql: obfuscated
19 | stack_trace_threshold: 0.500
20 | transaction_threshold: apdex_f
21 | development:
22 | <<: *default_settings
23 | monitor_mode: false
24 | developer_mode: true
25 | test:
26 | <<: *default_settings
27 | monitor_mode: false
28 | production:
29 | <<: *default_settings
30 | monitor_mode: true
31 | staging:
32 | <<: *default_settings
33 | app_name: "invoicer (Staging)"
34 | monitor_mode: true
35 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_typography.scss:
--------------------------------------------------------------------------------
1 | body {
2 | color: $base-font-color;
3 | font-family: $base-font-family;
4 | font-feature-settings: "kern", "liga", "pnum";
5 | font-size: $base-font-size;
6 | line-height: $base-line-height;
7 | }
8 |
9 | h1,
10 | h2,
11 | h3,
12 | h4,
13 | h5,
14 | h6 {
15 | font-family: $heading-font-family;
16 | font-size: $base-font-size;
17 | line-height: $heading-line-height;
18 | margin: 0 0 $small-spacing;
19 | }
20 |
21 | p {
22 | margin: 0 0 $small-spacing;
23 | }
24 |
25 | a {
26 | color: $action-color;
27 | text-decoration: none;
28 | transition: color $base-duration $base-timing;
29 |
30 | &:active,
31 | &:focus,
32 | &:hover {
33 | color: shade($action-color, 25%);
34 | }
35 | }
36 |
37 | hr {
38 | border-bottom: $base-border;
39 | border-left: 0;
40 | border-right: 0;
41 | border-top: 0;
42 | margin: $base-spacing 0;
43 | }
44 |
45 | img,
46 | picture {
47 | margin: 0;
48 | max-width: 100%;
49 | }
50 |
--------------------------------------------------------------------------------
/config/locales/simple_form.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | simple_form:
3 | "yes": 'Yes'
4 | "no": 'No'
5 | required:
6 | text: 'required'
7 | mark: '*'
8 | # You can uncomment the line below if you need to overwrite the whole required html.
9 | # When using html, text and mark won't be used.
10 | # html: '*'
11 | error_notification:
12 | default_message: "Please review the problems below:"
13 | # Examples
14 | # labels:
15 | # defaults:
16 | # password: 'Password'
17 | # user:
18 | # new:
19 | # email: 'E-mail to sign in.'
20 | # edit:
21 | # email: 'E-mail.'
22 | # hints:
23 | # defaults:
24 | # username: 'User name to sign in.'
25 | # password: 'No special characters, please.'
26 | # include_blanks:
27 | # defaults:
28 | # age: 'Rather not say'
29 | # prompts:
30 | # defaults:
31 | # age: 'Select your age'
32 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/invoice_pdf.scss:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | @import "normalize-rails";
4 | @import "bourbon";
5 | @import "base/grid-settings";
6 | @import "neat";
7 | @import "base/base";
8 | @import "refills/flashes";
9 |
10 | $row-stripe: #d2d2d2;
11 |
12 | .container {
13 | margin: 30px auto;
14 | max-width: 980px;
15 | }
16 |
17 |
18 | .line-items {
19 | margin-bottom: 20px;
20 |
21 | .quantity {
22 | width: 5%;
23 | }
24 |
25 | .item-number {
26 | width: 20%;
27 | }
28 |
29 | .description {
30 | width: 55%;
31 | }
32 |
33 | .unit-price, .total {
34 | width: 10%;
35 | }
36 |
37 | tbody tr:nth-child(2n) {
38 | background: $row-stripe;
39 | }
40 |
41 | tbody td:first-child {
42 | padding-left: 10px;
43 | }
44 | }
45 |
46 | header {
47 | margin-bottom: 40px;
48 |
49 | .contact {
50 | float: right;
51 | p {
52 | margin-bottom: 0;
53 | }
54 | }
55 |
56 | .logo {
57 | max-height: 70px;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/views/invoices/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= link_to "Download PDF",
2 | invoice_download_path(@invoice, format: "pdf"),
3 | target: "_blank",
4 | class: "download" %>
5 |
6 |
7 |
8 |
9 | | Qty |
10 | Item # |
11 | Description |
12 | Unit Price |
13 | Total |
14 |
15 |
16 |
17 | <% @invoice.line_items.each do |line_item| %>
18 |
19 | | <%= line_item.quantity %> |
20 | <%= line_item.product.item_number %> |
21 | <%= line_item.product.description %> |
22 | <%= number_to_currency(line_item.product.price) %> |
23 | <%= number_to_currency(line_item.product.price * line_item.quantity) %> |
24 |
25 | <% end %>
26 |
27 |
28 |
29 |
30 |
Notes
31 |
<%= @invoice.notes %>
32 |
33 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 | require "rails"
3 | require "active_model/railtie"
4 | require "active_job/railtie"
5 | require "active_record/railtie"
6 | require "action_controller/railtie"
7 | require "action_mailer/railtie"
8 | require "action_view/railtie"
9 | require "sprockets/railtie"
10 | Bundler.require(*Rails.groups)
11 | module Invoicer
12 | class Application < Rails::Application
13 | config.i18n.enforce_available_locales = true
14 | config.quiet_assets = true
15 | config.generators do |generate|
16 | generate.helper false
17 | generate.javascript_engine false
18 | generate.request_specs false
19 | generate.routing_specs false
20 | generate.stylesheets false
21 | generate.test_framework :rspec
22 | generate.view_specs false
23 | end
24 | config.action_controller.action_on_unpermitted_parameters = :raise
25 | config.active_record.raise_in_transactional_callbacks = true
26 | config.active_job.queue_adapter = :delayed_job
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_variables.scss:
--------------------------------------------------------------------------------
1 | // Typography
2 | $base-font-family: $helvetica;
3 | $heading-font-family: $base-font-family;
4 |
5 | // Font Sizes
6 | $base-font-size: 1em;
7 |
8 | // Line height
9 | $base-line-height: 1.5;
10 | $heading-line-height: 1.2;
11 |
12 | // Other Sizes
13 | $base-border-radius: 3px;
14 | $base-spacing: $base-line-height * 1em;
15 | $small-spacing: $base-spacing / 2;
16 | $base-z-index: 0;
17 |
18 | // Colors
19 | $blue: #477dca;
20 | $dark-gray: #333;
21 | $medium-gray: #999;
22 | $light-gray: #ddd;
23 |
24 | // Font Colors
25 | $base-font-color: $dark-gray;
26 | $action-color: $blue;
27 |
28 | // Border
29 | $base-border-color: $light-gray;
30 | $base-border: 1px solid $base-border-color;
31 |
32 | // Background Colors
33 | $base-background-color: #fff;
34 | $secondary-background-color: tint($base-border-color, 75%);
35 |
36 | // Forms
37 | $form-box-shadow: inset 0 1px 3px rgba(#000, 0.06);
38 | $form-box-shadow-focus: $form-box-shadow, 0 0 5px adjust-color($action-color, $lightness: -5%, $alpha: -0.3);
39 |
40 | // Animations
41 | $base-duration: 150ms;
42 | $base-timing: ease;
43 |
--------------------------------------------------------------------------------
/app/views/application/_analytics.html.erb:
--------------------------------------------------------------------------------
1 | <% if ENV["SEGMENT_KEY"] %>
2 |
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/spec/features/user_downloads_invoice_pdf_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe "User downalods PDF" do
4 | scenario "for an invoice with normal data" do
5 | product = create(:product, item_number: 'abc-123')
6 | invoice = create(:invoice)
7 | line_item = create(:line_item, product: product, invoice: invoice)
8 |
9 | visit invoice_path(invoice)
10 | click_link "Download PDF"
11 |
12 | expect(content_type).to eq("application/pdf")
13 | expect(content_disposition).to include("inline")
14 | expect(download_filename).to include(invoice.number)
15 | expect(pdf_body).to have_content(product.description)
16 | end
17 |
18 | def content_type
19 | response_headers["Content-Type"]
20 | end
21 |
22 | def content_disposition
23 | response_headers["Content-Disposition"]
24 | end
25 |
26 | def download_filename
27 | content_disposition.scan(/filename="(.*)"/).last.first
28 | end
29 |
30 | def pdf_body
31 | temp_pdf = Tempfile.new('pdf')
32 | temp_pdf << page.source.force_encoding('UTF-8')
33 | reader = PDF::Reader.new(temp_pdf)
34 | reader.pages.first.text
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | require Rails.root.join("config/smtp")
2 | Rails.application.configure do
3 | config.cache_classes = true
4 | config.eager_load = true
5 | config.consider_all_requests_local = false
6 | config.action_controller.perform_caching = true
7 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
8 | config.middleware.use Rack::Deflater
9 | config.middleware.use Rack::CanonicalHost, ENV.fetch("APPLICATION_HOST")
10 | config.assets.js_compressor = :uglifier
11 | config.assets.compile = false
12 | config.assets.digest = true
13 | config.log_level = :debug
14 | config.action_controller.asset_host = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST"))
15 | config.action_mailer.delivery_method = :smtp
16 | config.action_mailer.smtp_settings = SMTP_SETTINGS
17 | config.i18n.fallbacks = true
18 | config.active_support.deprecation = :notify
19 | config.log_formatter = ::Logger::Formatter.new
20 | config.active_record.dump_schema_after_migration = false
21 | config.action_mailer.default_url_options = { host: ENV.fetch("APPLICATION_HOST") }
22 | end
23 | Rack::Timeout.timeout = (ENV["RACK_TIMEOUT"] || 10).to_i
24 |
--------------------------------------------------------------------------------
/app/views/invoices/pdf.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
7 | <%= image_tag "https://thoughtbot.com/logo-large.png", class: "logo" %>
8 |
9 |
10 | Invoice
11 |
12 |
13 |
14 |
15 | | Qty |
16 | Item # |
17 | Description |
18 | Unit Price |
19 | Total |
20 |
21 |
22 |
23 | <% invoice.line_items.each do |line_item| %>
24 |
25 | | <%= line_item.quantity %> |
26 | <%= line_item.product.item_number %> |
27 | <%= line_item.product.description %> |
28 | <%= number_to_currency(line_item.product.price) %> |
29 | <%= number_to_currency(line_item.product.price * line_item.quantity) %> |
30 |
31 | <% end %>
32 |
33 |
34 |
35 |
36 |
Notes
37 |
<%= invoice.notes %>
38 |
39 |
40 |
--------------------------------------------------------------------------------
/db/migrate/20151222024559_create_delayed_jobs.rb:
--------------------------------------------------------------------------------
1 | class CreateDelayedJobs < ActiveRecord::Migration
2 | def self.up
3 | create_table :delayed_jobs, force: true do |table|
4 | table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
5 | table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
6 | table.text :handler, null: false # YAML-encoded string of the object that will do work
7 | table.text :last_error # reason for last failure (See Note below)
8 | table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
9 | table.datetime :locked_at # Set when a client is working on this object
10 | table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
11 | table.string :locked_by # Who is working on this object (if locked)
12 | table.string :queue # The name of the queue this job is in
13 | table.timestamps null: true
14 | end
15 |
16 | add_index :delayed_jobs, [:priority, :run_at], name: "delayed_jobs_priority"
17 | end
18 |
19 | def self.down
20 | drop_table :delayed_jobs
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | ruby "2.2.3"
4 |
5 | gem "autoprefixer-rails"
6 | gem "bourbon", "~> 4.2.0"
7 | gem "coffee-rails", "~> 4.1.0"
8 | gem "delayed_job_active_record"
9 | gem "flutie"
10 | gem "high_voltage"
11 | gem "jquery-rails"
12 | gem "neat", "~> 1.7.0"
13 | gem "newrelic_rpm", ">= 3.9.8"
14 | gem "normalize-rails", "~> 3.0.0"
15 | gem "pdfkit"
16 | gem "pg"
17 | gem "rack-canonical-host"
18 | gem "rails", "~> 4.2.0"
19 | gem "recipient_interceptor"
20 | gem "render_anywhere", require: false
21 | gem "sass-rails", "~> 5.0"
22 | gem "simple_form"
23 | gem "title"
24 | gem "uglifier"
25 |
26 | group :development do
27 | gem "quiet_assets"
28 | gem "refills"
29 | gem "spring"
30 | gem "spring-commands-rspec"
31 | gem "web-console"
32 | end
33 |
34 | group :development, :test do
35 | gem "awesome_print"
36 | gem "bullet"
37 | gem "bundler-audit", require: false
38 | gem "byebug"
39 | gem "dotenv-rails"
40 | gem "factory_girl_rails"
41 | gem "i18n-tasks"
42 | gem "pry-rails"
43 | gem "rspec-rails", "~> 3.3.0"
44 | end
45 |
46 | group :test do
47 | gem "capybara-webkit"
48 | gem "database_cleaner"
49 | gem "formulaic"
50 | gem "launchy"
51 | gem "pdf-reader"
52 | gem "shoulda-matchers"
53 | gem "simplecov", require: false
54 | gem "timecop"
55 | gem "webmock"
56 | end
57 |
58 | group :staging, :production do
59 | gem "rack-timeout"
60 | gem "wkhtmltopdf-heroku"
61 | end
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Invoicer
2 |
3 | This is the companion codebase to [The Weekly Iteration, Episode 105:
4 | Generating PDFs with Rails][].
5 |
6 | In this episode, we walk through everything we need to work with PDFs in our
7 | Rails apps: the easiest way to generate them, how to properly serve them as
8 | responses in our controllers, and even how to test them.
9 |
10 | Invoicer is a simple application that will generate PDF receipts.
11 |
12 | [The Weekly Iteration, Episode 105: Generating PDFs with Rails]: https://upcase.com/videos/generating-pdfs-with-rails?utm_source=github&utm_medium=companion-code&utm_campaign=upcase-generating-pdfs-with-rails
13 |
14 | ## Getting Started
15 |
16 | After you have cloned this repo, run this setup script to set up your machine
17 | with the necessary dependencies to run and test this app:
18 |
19 | % ./bin/setup
20 |
21 | It assumes you have a machine equipped with Ruby, Postgres, etc. If not, set up
22 | your machine with [this script].
23 |
24 | [this script]: https://github.com/thoughtbot/laptop
25 |
26 | After setting up, you can run the application locally with:
27 |
28 | % rails server
29 |
30 | ## Guidelines
31 |
32 | Use the following guides for getting things done, programming well, and
33 | programming in style.
34 |
35 | * [Protocol](http://github.com/thoughtbot/guides/blob/master/protocol)
36 | * [Best Practices](http://github.com/thoughtbot/guides/blob/master/best-practices)
37 | * [Style](http://github.com/thoughtbot/guides/blob/master/style)
38 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | We're sorry, but something went wrong (500)
8 |
9 |
58 |
59 |
60 |
61 |
62 |
63 |
We're sorry, but something went wrong.
64 |
65 |
If you are the application owner check the logs for more information.
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | The change you wanted was rejected (422)
8 |
9 |
58 |
59 |
60 |
61 |
62 |
63 |
The change you wanted was rejected.
64 |
Maybe you tried to change something you didn't have access to.
65 |
66 |
If you are the application owner check the logs for more information.
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | The page you were looking for doesn't exist (404)
8 |
9 |
58 |
59 |
60 |
61 |
62 |
63 |
The page you were looking for doesn't exist.
64 |
You may have mistyped the address or the page may have moved.
65 |
66 |
If you are the application owner check the logs for more information.
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_forms.scss:
--------------------------------------------------------------------------------
1 | fieldset {
2 | background-color: $secondary-background-color;
3 | border: $base-border;
4 | margin: 0 0 $small-spacing;
5 | padding: $base-spacing;
6 | }
7 |
8 | input,
9 | label,
10 | select {
11 | display: block;
12 | font-family: $base-font-family;
13 | font-size: $base-font-size;
14 | }
15 |
16 | label {
17 | font-weight: 600;
18 | margin-bottom: $small-spacing / 2;
19 |
20 | &.required::after {
21 | content: "*";
22 | }
23 |
24 | abbr {
25 | display: none;
26 | }
27 | }
28 |
29 | #{$all-text-inputs},
30 | select[multiple=multiple] {
31 | background-color: $base-background-color;
32 | border: $base-border;
33 | border-radius: $base-border-radius;
34 | box-shadow: $form-box-shadow;
35 | box-sizing: border-box;
36 | font-family: $base-font-family;
37 | font-size: $base-font-size;
38 | margin-bottom: $small-spacing;
39 | padding: $base-spacing / 3;
40 | transition: border-color $base-duration $base-timing;
41 | width: 100%;
42 |
43 | &:hover {
44 | border-color: shade($base-border-color, 20%);
45 | }
46 |
47 | &:focus {
48 | border-color: $action-color;
49 | box-shadow: $form-box-shadow-focus;
50 | outline: none;
51 | }
52 |
53 | &:disabled {
54 | background-color: shade($base-background-color, 5%);
55 | cursor: not-allowed;
56 |
57 | &:hover {
58 | border: $base-border;
59 | }
60 | }
61 | }
62 |
63 | textarea {
64 | resize: vertical;
65 | }
66 |
67 | input[type="search"] {
68 | appearance: none;
69 | }
70 |
71 | input[type="checkbox"],
72 | input[type="radio"] {
73 | display: inline;
74 | margin-right: $small-spacing / 2;
75 |
76 | + label {
77 | display: inline-block;
78 | }
79 | }
80 |
81 | input[type="file"] {
82 | margin-bottom: $small-spacing;
83 | width: 100%;
84 | }
85 |
86 | select {
87 | margin-bottom: $base-spacing;
88 | max-width: 100%;
89 | width: auto;
90 | }
91 |
--------------------------------------------------------------------------------
/lib/tasks/dev.rake:
--------------------------------------------------------------------------------
1 | if Rails.env.development? || Rails.env.test?
2 | require "factory_girl"
3 |
4 | namespace :dev do
5 | desc "Sample data for local development environment"
6 | task prime: "db:setup" do
7 | include FactoryGirl::Syntax::Methods
8 |
9 | LineItem.destroy_all
10 | Product.destroy_all
11 | Invoice.destroy_all
12 |
13 | tool = create :product, price: 29.95, item_number: "tool-123-ab4",
14 | description: "A mutli-purpose tool"
15 | level = create :product, price: 49.50, item_number: "tool-389-b5d",
16 | description: "Thermonuclear level w/ kick stand"
17 | tacks = create :product, price: 9.15, item_number: "tool-887-bd4",
18 | description: "Thumb tacks... really good ones"
19 | saw = create :product, price: 25.00, item_number: "tool-387-saw",
20 | description: "A very sharp saw"
21 | nails = create :product, price: 1.57, item_number: "tool-845-bb2",
22 | description: "A collection of nails, about the same size"
23 |
24 | invoice = create :invoice
25 | create :line_item, invoice: invoice, product: tacks
26 | create :line_item, invoice: invoice, product: tool
27 | create :line_item, invoice: invoice, product: level
28 |
29 | other_invoice = create :invoice
30 | create :line_item, invoice: other_invoice, product: tacks
31 | create :line_item, invoice: other_invoice, product: level
32 | create :line_item, invoice: other_invoice, product: nails
33 | create :line_item, invoice: other_invoice, product: tool
34 | create :line_item, invoice: other_invoice, product: saw, quantity: 5
35 |
36 | last_invoice = create :invoice
37 | create :line_item, invoice: last_invoice, product: level
38 | create :line_item, invoice: last_invoice, product: tacks
39 | create :line_item, invoice: last_invoice, product: nails
40 | create :line_item, invoice: last_invoice, product: saw
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended that you check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(version: 20151222034730) do
15 |
16 | # These are extensions that must be enabled in order to support this database
17 | enable_extension "plpgsql"
18 |
19 | create_table "delayed_jobs", force: :cascade do |t|
20 | t.integer "priority", default: 0, null: false
21 | t.integer "attempts", default: 0, null: false
22 | t.text "handler", null: false
23 | t.text "last_error"
24 | t.datetime "run_at"
25 | t.datetime "locked_at"
26 | t.datetime "failed_at"
27 | t.string "locked_by"
28 | t.string "queue"
29 | t.datetime "created_at"
30 | t.datetime "updated_at"
31 | end
32 |
33 | add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
34 |
35 | create_table "invoices", force: :cascade do |t|
36 | t.string "account"
37 | t.string "number"
38 | t.date "date"
39 | t.text "notes"
40 | t.datetime "created_at", null: false
41 | t.datetime "updated_at", null: false
42 | end
43 |
44 | create_table "line_items", force: :cascade do |t|
45 | t.integer "invoice_id"
46 | t.integer "quantity"
47 | t.integer "product_id"
48 | t.datetime "created_at", null: false
49 | t.datetime "updated_at", null: false
50 | end
51 |
52 | add_index "line_items", ["invoice_id"], name: "index_line_items_on_invoice_id", using: :btree
53 |
54 | create_table "products", force: :cascade do |t|
55 | t.string "description"
56 | t.string "item_number"
57 | t.money "price", scale: 2
58 | t.datetime "created_at", null: false
59 | t.datetime "updated_at", null: false
60 | end
61 |
62 | add_foreign_key "line_items", "invoices"
63 | end
64 |
--------------------------------------------------------------------------------
/config/initializers/simple_form.rb:
--------------------------------------------------------------------------------
1 | # Use this setup block to configure all options available in SimpleForm.
2 | SimpleForm.setup do |config|
3 | # Wrappers are used by the form builder to generate a
4 | # complete input. You can remove any component from the
5 | # wrapper, change the order or even add your own to the
6 | # stack. The options given below are used to wrap the
7 | # whole input.
8 | config.wrappers :default, class: :input,
9 | hint_class: :field_with_hint, error_class: :field_with_errors do |b|
10 | ## Extensions enabled by default
11 | # Any of these extensions can be disabled for a
12 | # given input by passing: `f.input EXTENSION_NAME => false`.
13 | # You can make any of these extensions optional by
14 | # renaming `b.use` to `b.optional`.
15 |
16 | # Determines whether to use HTML5 (:email, :url, ...)
17 | # and required attributes
18 | b.use :html5
19 |
20 | # Calculates placeholders automatically from I18n
21 | # You can also pass a string as f.input placeholder: "Placeholder"
22 | b.use :placeholder
23 |
24 | ## Optional extensions
25 | # They are disabled unless you pass `f.input EXTENSION_NAME => true`
26 | # to the input. If so, they will retrieve the values from the model
27 | # if any exists. If you want to enable any of those
28 | # extensions by default, you can change `b.optional` to `b.use`.
29 |
30 | # Calculates maxlength from length validations for string inputs
31 | b.optional :maxlength
32 |
33 | # Calculates pattern from format validations for string inputs
34 | b.optional :pattern
35 |
36 | # Calculates min and max from length validations for numeric inputs
37 | b.optional :min_max
38 |
39 | # Calculates readonly automatically from readonly attributes
40 | b.optional :readonly
41 |
42 | ## Inputs
43 | b.use :label_input
44 | b.use :hint, wrap_with: { tag: :span, class: :hint }
45 | b.use :error, wrap_with: { tag: :span, class: :error }
46 |
47 | ## full_messages_for
48 | # If you want to display the full error message for the attribute, you can
49 | # use the component :full_error, like:
50 | #
51 | # b.use :full_error, wrap_with: { tag: :span, class: :error }
52 | end
53 |
54 | # The default wrapper to be used by the FormBuilder.
55 | config.default_wrapper = :default
56 |
57 | # Define the way to render check boxes / radio buttons with labels.
58 | # Defaults to :nested for bootstrap config.
59 | # inline: input + label
60 | # nested: label > input
61 | config.boolean_style = :nested
62 |
63 | # Default class for buttons
64 | config.button_class = 'btn'
65 |
66 | # Method used to tidy up errors. Specify any Rails Array method.
67 | # :first lists the first message for each field.
68 | # Use :to_sentence to list all errors for each field.
69 | # config.error_method = :first
70 |
71 | # Default tag used for error notification helper.
72 | config.error_notification_tag = :div
73 |
74 | # CSS class to add for error notification helper.
75 | config.error_notification_class = 'error_notification'
76 |
77 | # ID to add for error notification helper.
78 | # config.error_notification_id = nil
79 |
80 | # Series of attempts to detect a default label method for collection.
81 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
82 |
83 | # Series of attempts to detect a default value method for collection.
84 | # config.collection_value_methods = [ :id, :to_s ]
85 |
86 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
87 | # config.collection_wrapper_tag = nil
88 |
89 | # You can define the class to use on all collection wrappers. Defaulting to none.
90 | # config.collection_wrapper_class = nil
91 |
92 | # You can wrap each item in a collection of radio/check boxes with a tag,
93 | # defaulting to :span.
94 | # config.item_wrapper_tag = :span
95 |
96 | # You can define a class to use in all item wrappers. Defaulting to none.
97 | # config.item_wrapper_class = nil
98 |
99 | # How the label text should be generated altogether with the required text.
100 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
101 |
102 | # You can define the class to use on all labels. Default is nil.
103 | # config.label_class = nil
104 |
105 | # You can define the default class to be used on forms. Can be overriden
106 | # with `html: { :class }`. Defaulting to none.
107 | # config.default_form_class = nil
108 |
109 | # You can define which elements should obtain additional classes
110 | # config.generate_additional_classes_for = [:wrapper, :label, :input]
111 |
112 | # Whether attributes are required by default (or not). Default is true.
113 | # config.required_by_default = true
114 |
115 | # Tell browsers whether to use the native HTML5 validations (novalidate form option).
116 | # These validations are enabled in SimpleForm's internal config but disabled by default
117 | # in this configuration, which is recommended due to some quirks from different browsers.
118 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
119 | # change this configuration to true.
120 | config.browser_validations = false
121 |
122 | # Collection of methods to detect if a file type was given.
123 | # config.file_methods = [ :mounted_as, :file?, :public_filename ]
124 |
125 | # Custom mappings for input types. This should be a hash containing a regexp
126 | # to match as key, and the input type that will be used when the field name
127 | # matches the regexp as value.
128 | # config.input_mappings = { /count/ => :integer }
129 |
130 | # Custom wrappers for input types. This should be a hash containing an input
131 | # type as key and the wrapper that will be used for all inputs with specified type.
132 | # config.wrapper_mappings = { string: :prepend }
133 |
134 | # Namespaces where SimpleForm should look for custom input classes that
135 | # override default inputs.
136 | # config.custom_inputs_namespaces << "CustomInputs"
137 |
138 | # Default priority for time_zone inputs.
139 | # config.time_zone_priority = nil
140 |
141 | # Default priority for country inputs.
142 | # config.country_priority = nil
143 |
144 | # When false, do not use translations for labels.
145 | # config.translate_labels = true
146 |
147 | # Automatically discover new inputs in Rails' autoload path.
148 | # config.inputs_discovery = true
149 |
150 | # Cache SimpleForm inputs discovery
151 | # config.cache_discovery = !Rails.env.development?
152 |
153 | # Default class for inputs
154 | # config.input_class = nil
155 |
156 | # Define the default class of the input wrapper of the boolean input.
157 | config.boolean_label_class = 'checkbox'
158 |
159 | # Defines if the default input wrapper class should be included in radio
160 | # collection wrappers.
161 | # config.include_default_input_wrapper_class = true
162 |
163 | # Defines which i18n scope will be used in Simple Form.
164 | # config.i18n_scope = 'simple_form'
165 | end
166 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | Ascii85 (1.0.2)
5 | actionmailer (4.2.5)
6 | actionpack (= 4.2.5)
7 | actionview (= 4.2.5)
8 | activejob (= 4.2.5)
9 | mail (~> 2.5, >= 2.5.4)
10 | rails-dom-testing (~> 1.0, >= 1.0.5)
11 | actionpack (4.2.5)
12 | actionview (= 4.2.5)
13 | activesupport (= 4.2.5)
14 | rack (~> 1.6)
15 | rack-test (~> 0.6.2)
16 | rails-dom-testing (~> 1.0, >= 1.0.5)
17 | rails-html-sanitizer (~> 1.0, >= 1.0.2)
18 | actionview (4.2.5)
19 | activesupport (= 4.2.5)
20 | builder (~> 3.1)
21 | erubis (~> 2.7.0)
22 | rails-dom-testing (~> 1.0, >= 1.0.5)
23 | rails-html-sanitizer (~> 1.0, >= 1.0.2)
24 | activejob (4.2.5)
25 | activesupport (= 4.2.5)
26 | globalid (>= 0.3.0)
27 | activemodel (4.2.5)
28 | activesupport (= 4.2.5)
29 | builder (~> 3.1)
30 | activerecord (4.2.5)
31 | activemodel (= 4.2.5)
32 | activesupport (= 4.2.5)
33 | arel (~> 6.0)
34 | activesupport (4.2.5)
35 | i18n (~> 0.7)
36 | json (~> 1.7, >= 1.7.7)
37 | minitest (~> 5.1)
38 | thread_safe (~> 0.3, >= 0.3.4)
39 | tzinfo (~> 1.1)
40 | addressable (2.4.0)
41 | afm (0.2.2)
42 | arel (6.0.3)
43 | ast (2.2.0)
44 | autoprefixer-rails (6.2.1)
45 | execjs
46 | json
47 | awesome_print (1.6.1)
48 | bourbon (4.2.6)
49 | sass (~> 3.4)
50 | thor (~> 0.19)
51 | builder (3.2.2)
52 | bullet (4.14.10)
53 | activesupport (>= 3.0.0)
54 | uniform_notifier (~> 1.9.0)
55 | bundler-audit (0.4.0)
56 | bundler (~> 1.2)
57 | thor (~> 0.18)
58 | byebug (8.2.1)
59 | capybara (2.5.0)
60 | mime-types (>= 1.16)
61 | nokogiri (>= 1.3.3)
62 | rack (>= 1.0.0)
63 | rack-test (>= 0.5.4)
64 | xpath (~> 2.0)
65 | capybara-webkit (1.7.1)
66 | capybara (>= 2.3.0, < 2.6.0)
67 | json
68 | coderay (1.1.0)
69 | coffee-rails (4.1.1)
70 | coffee-script (>= 2.2.0)
71 | railties (>= 4.0.0, < 5.1.x)
72 | coffee-script (2.4.1)
73 | coffee-script-source
74 | execjs
75 | coffee-script-source (1.10.0)
76 | concurrent-ruby (1.0.0)
77 | crack (0.4.3)
78 | safe_yaml (~> 1.0.0)
79 | database_cleaner (1.5.1)
80 | debug_inspector (0.0.2)
81 | delayed_job (4.1.1)
82 | activesupport (>= 3.0, < 5.0)
83 | delayed_job_active_record (4.1.0)
84 | activerecord (>= 3.0, < 5)
85 | delayed_job (>= 3.0, < 5)
86 | diff-lcs (1.2.5)
87 | docile (1.1.5)
88 | dotenv (2.0.2)
89 | dotenv-rails (2.0.2)
90 | dotenv (= 2.0.2)
91 | railties (~> 4.0)
92 | easy_translate (0.5.0)
93 | json
94 | thread
95 | thread_safe
96 | erubis (2.7.0)
97 | execjs (2.6.0)
98 | factory_girl (4.5.0)
99 | activesupport (>= 3.0.0)
100 | factory_girl_rails (4.5.0)
101 | factory_girl (~> 4.5.0)
102 | railties (>= 3.0.0)
103 | flutie (2.0.0)
104 | formulaic (0.3.0)
105 | activesupport
106 | capybara
107 | i18n
108 | globalid (0.3.6)
109 | activesupport (>= 4.1.0)
110 | hashdiff (0.2.3)
111 | hashery (2.1.1)
112 | high_voltage (2.4.0)
113 | highline (1.7.8)
114 | i18n (0.7.0)
115 | i18n-tasks (0.9.2)
116 | activesupport (>= 4.0.2)
117 | ast (>= 2.1.0)
118 | easy_translate (>= 0.5.0)
119 | erubis
120 | highline (>= 1.7.3)
121 | i18n
122 | parser (>= 2.2.3.0)
123 | term-ansicolor (>= 1.3.2)
124 | terminal-table (>= 1.5.1)
125 | jquery-rails (4.0.5)
126 | rails-dom-testing (~> 1.0)
127 | railties (>= 4.2.0)
128 | thor (>= 0.14, < 2.0)
129 | json (1.8.3)
130 | launchy (2.4.3)
131 | addressable (~> 2.3)
132 | loofah (2.0.3)
133 | nokogiri (>= 1.5.9)
134 | mail (2.6.3)
135 | mime-types (>= 1.16, < 3)
136 | method_source (0.8.2)
137 | mime-types (2.99)
138 | mini_portile2 (2.0.0)
139 | minitest (5.8.3)
140 | neat (1.7.2)
141 | bourbon (>= 4.0)
142 | sass (>= 3.3)
143 | newrelic_rpm (3.14.1.311)
144 | nokogiri (1.6.7.1)
145 | mini_portile2 (~> 2.0.0.rc2)
146 | normalize-rails (3.0.3)
147 | parser (2.2.3.0)
148 | ast (>= 1.1, < 3.0)
149 | pdf-reader (1.3.3)
150 | Ascii85 (~> 1.0.0)
151 | afm (~> 0.2.0)
152 | hashery (~> 2.0)
153 | ruby-rc4
154 | ttfunk
155 | pdfkit (0.8.2)
156 | pg (0.18.4)
157 | pry (0.10.3)
158 | coderay (~> 1.1.0)
159 | method_source (~> 0.8.1)
160 | slop (~> 3.4)
161 | pry-rails (0.3.4)
162 | pry (>= 0.9.10)
163 | quiet_assets (1.1.0)
164 | railties (>= 3.1, < 5.0)
165 | rack (1.6.4)
166 | rack-canonical-host (0.1.0)
167 | addressable
168 | rack (~> 1.0)
169 | rack-test (0.6.3)
170 | rack (>= 1.0)
171 | rack-timeout (0.3.2)
172 | rails (4.2.5)
173 | actionmailer (= 4.2.5)
174 | actionpack (= 4.2.5)
175 | actionview (= 4.2.5)
176 | activejob (= 4.2.5)
177 | activemodel (= 4.2.5)
178 | activerecord (= 4.2.5)
179 | activesupport (= 4.2.5)
180 | bundler (>= 1.3.0, < 2.0)
181 | railties (= 4.2.5)
182 | sprockets-rails
183 | rails-deprecated_sanitizer (1.0.3)
184 | activesupport (>= 4.2.0.alpha)
185 | rails-dom-testing (1.0.7)
186 | activesupport (>= 4.2.0.beta, < 5.0)
187 | nokogiri (~> 1.6.0)
188 | rails-deprecated_sanitizer (>= 1.0.1)
189 | rails-html-sanitizer (1.0.2)
190 | loofah (~> 2.0)
191 | railties (4.2.5)
192 | actionpack (= 4.2.5)
193 | activesupport (= 4.2.5)
194 | rake (>= 0.8.7)
195 | thor (>= 0.18.1, < 2.0)
196 | rake (10.4.2)
197 | recipient_interceptor (0.1.2)
198 | mail
199 | refills (0.1.0)
200 | render_anywhere (0.0.12)
201 | rails (>= 3.0.7)
202 | rspec-core (3.3.2)
203 | rspec-support (~> 3.3.0)
204 | rspec-expectations (3.3.1)
205 | diff-lcs (>= 1.2.0, < 2.0)
206 | rspec-support (~> 3.3.0)
207 | rspec-mocks (3.3.2)
208 | diff-lcs (>= 1.2.0, < 2.0)
209 | rspec-support (~> 3.3.0)
210 | rspec-rails (3.3.3)
211 | actionpack (>= 3.0, < 4.3)
212 | activesupport (>= 3.0, < 4.3)
213 | railties (>= 3.0, < 4.3)
214 | rspec-core (~> 3.3.0)
215 | rspec-expectations (~> 3.3.0)
216 | rspec-mocks (~> 3.3.0)
217 | rspec-support (~> 3.3.0)
218 | rspec-support (3.3.0)
219 | ruby-rc4 (0.1.5)
220 | safe_yaml (1.0.4)
221 | sass (3.4.20)
222 | sass-rails (5.0.4)
223 | railties (>= 4.0.0, < 5.0)
224 | sass (~> 3.1)
225 | sprockets (>= 2.8, < 4.0)
226 | sprockets-rails (>= 2.0, < 4.0)
227 | tilt (>= 1.1, < 3)
228 | shoulda-matchers (3.0.1)
229 | activesupport (>= 4.0.0)
230 | simple_form (3.2.1)
231 | actionpack (> 4, < 5.1)
232 | activemodel (> 4, < 5.1)
233 | simplecov (0.11.1)
234 | docile (~> 1.1.0)
235 | json (~> 1.8)
236 | simplecov-html (~> 0.10.0)
237 | simplecov-html (0.10.0)
238 | slop (3.6.0)
239 | spring (1.6.0)
240 | spring-commands-rspec (1.0.4)
241 | spring (>= 0.9.1)
242 | sprockets (3.5.2)
243 | concurrent-ruby (~> 1.0)
244 | rack (> 1, < 3)
245 | sprockets-rails (3.0.0)
246 | actionpack (>= 4.0)
247 | activesupport (>= 4.0)
248 | sprockets (>= 3.0.0)
249 | term-ansicolor (1.3.2)
250 | tins (~> 1.0)
251 | terminal-table (1.5.2)
252 | thor (0.19.1)
253 | thread (0.2.2)
254 | thread_safe (0.3.5)
255 | tilt (2.0.1)
256 | timecop (0.8.0)
257 | tins (1.8.1)
258 | title (0.0.5)
259 | i18n
260 | rails (>= 3.1)
261 | ttfunk (1.4.0)
262 | tzinfo (1.2.2)
263 | thread_safe (~> 0.1)
264 | uglifier (2.7.2)
265 | execjs (>= 0.3.0)
266 | json (>= 1.8.0)
267 | uniform_notifier (1.9.0)
268 | web-console (3.0.0)
269 | activemodel (>= 4.2)
270 | debug_inspector
271 | railties (>= 4.2)
272 | webmock (1.22.3)
273 | addressable (>= 2.3.6)
274 | crack (>= 0.3.2)
275 | hashdiff
276 | wkhtmltopdf-heroku (2.12.2.4)
277 | xpath (2.0.0)
278 | nokogiri (~> 1.3)
279 |
280 | PLATFORMS
281 | ruby
282 |
283 | DEPENDENCIES
284 | autoprefixer-rails
285 | awesome_print
286 | bourbon (~> 4.2.0)
287 | bullet
288 | bundler-audit
289 | byebug
290 | capybara-webkit
291 | coffee-rails (~> 4.1.0)
292 | database_cleaner
293 | delayed_job_active_record
294 | dotenv-rails
295 | factory_girl_rails
296 | flutie
297 | formulaic
298 | high_voltage
299 | i18n-tasks
300 | jquery-rails
301 | launchy
302 | neat (~> 1.7.0)
303 | newrelic_rpm (>= 3.9.8)
304 | normalize-rails (~> 3.0.0)
305 | pdf-reader
306 | pdfkit
307 | pg
308 | pry-rails
309 | quiet_assets
310 | rack-canonical-host
311 | rack-timeout
312 | rails (~> 4.2.0)
313 | recipient_interceptor
314 | refills
315 | render_anywhere
316 | rspec-rails (~> 3.3.0)
317 | sass-rails (~> 5.0)
318 | shoulda-matchers
319 | simple_form
320 | simplecov
321 | spring
322 | spring-commands-rspec
323 | timecop
324 | title
325 | uglifier
326 | web-console
327 | webmock
328 | wkhtmltopdf-heroku
329 |
330 | BUNDLED WITH
331 | 1.10.6
332 |
--------------------------------------------------------------------------------