├── log └── .gitkeep ├── .rspec ├── lib ├── tasks │ ├── .gitkeep │ └── db.rake ├── assets │ └── .gitkeep ├── simplecov │ └── rails_api_profile.rb ├── api_tasters │ ├── users.rb │ ├── sessions.rb │ ├── locations.rb │ └── units.rb ├── examples.rb └── extensions │ └── active_model_serializer │ └── include_only_declared_associations.rb ├── public ├── favicon.ico ├── robots.txt ├── 500.html ├── 422.html └── 404.html ├── app ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── location.rb │ ├── user.rb │ └── unit.rb ├── serializers │ ├── base_serializer.rb │ ├── location_serializer.rb │ ├── unit_serializer.rb │ └── user_serializer.rb ├── controllers │ ├── user │ │ └── base_controller.rb │ ├── users_controller.rb │ ├── sessions_controller.rb │ ├── application_controller.rb │ ├── units_controller.rb │ └── locations_controller.rb ├── responders │ └── api_responder.rb ├── services │ └── authentication_service.rb └── interactors │ ├── unit_saver.rb │ └── unit_fetcher.rb ├── .ruby-version ├── db ├── seeds │ ├── development │ │ └── all.seeds.rb │ └── staging │ │ └── all.seeds.rb ├── migrate │ ├── 20130614112947_create_locations.rb │ ├── 20130614115836_create_units.rb │ └── 20130319140714_devise_create_users.rb ├── seeds.rb └── schema.rb ├── script ├── server ├── ci ├── quality ├── rails ├── ci_deploy └── bootstrap ├── Procfile ├── doc ├── schema.png └── README_FOR_APP ├── config ├── initializers │ ├── mailer.rb │ ├── api_taster.rb │ ├── active_model_serializer.rb │ ├── mail_safe.rb │ ├── bullet.rb │ ├── generators.rb │ ├── mime_types.rb │ ├── time_formats.rb │ ├── 01_config.rb │ ├── requires.rb │ ├── strong_parameters.rb │ ├── wrap_parameters.rb │ ├── secret_token.rb │ ├── rollbar.rb │ └── devise.rb ├── environment.rb ├── boot.rb ├── locales │ ├── en.yml │ └── devise.en.yml ├── database.yml.example ├── routes.rb ├── environments │ ├── development.rb │ ├── test.rb │ └── production.rb ├── rails_best_practices.yml └── application.rb ├── .env.example ├── spec ├── factories │ ├── location.rb │ ├── sequences.rb │ ├── users.rb │ └── unit.rb ├── support │ ├── extensions │ │ ├── active_record │ │ │ └── sliced.rb │ │ └── rspec-rails │ │ │ └── mock_model.rb │ ├── matchers │ │ ├── be_a_full_user_representation.rb │ │ ├── include_attributes.rb │ │ ├── be_a_location_representation.rb │ │ ├── be_a_user_representation.rb │ │ └── be_a_unit_representation.rb │ ├── shared_examples │ │ ├── success_response.rb │ │ └── authentication.rb │ └── helpers.rb ├── serializers │ ├── unit_serializer_spec.rb │ ├── location_serializer_spec.rb │ └── user_serializer_spec.rb ├── models │ ├── user_spec.rb │ ├── location_spec.rb │ └── unit_spec.rb ├── controllers │ ├── sessions_controller_spec.rb │ ├── users_controller_spec.rb │ ├── locations_controller_spec.rb │ └── units_controller_spec.rb ├── api │ ├── sessions_spec.rb │ ├── users_spec.rb │ ├── locations_spec.rb │ └── units_spec.rb ├── interactors │ ├── unit_saver_spec.rb │ └── unit_fetcher_spec.rb └── spec_helper.rb ├── config.ru ├── Rakefile ├── .gitignore ├── Guardfile ├── Gemfile ├── README.md └── Gemfile.lock /log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.0.0-p247 2 | -------------------------------------------------------------------------------- /db/seeds/development/all.seeds.rb: -------------------------------------------------------------------------------- 1 | Examples.setup! 2 | -------------------------------------------------------------------------------- /db/seeds/staging/all.seeds.rb: -------------------------------------------------------------------------------- 1 | Examples.setup! 2 | -------------------------------------------------------------------------------- /script/server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | exec bin/foreman start 4 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec rails server thin -p $PORT -e $RACK_ENV 2 | -------------------------------------------------------------------------------- /doc/schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fs/inventory-reborn/master/doc/schema.png -------------------------------------------------------------------------------- /app/serializers/base_serializer.rb: -------------------------------------------------------------------------------- 1 | class BaseSerializer < ActiveModel::Serializer 2 | end 3 | -------------------------------------------------------------------------------- /config/initializers/mailer.rb: -------------------------------------------------------------------------------- 1 | ActionMailer::Base.default_url_options[:host] = app_config.host 2 | -------------------------------------------------------------------------------- /script/ci: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | bundle exec rspec spec 6 | 7 | script/quality 8 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Add your API tokens here 2 | RACK_ENV=development 3 | # ROLLBAR_KEY=your_key_here 4 | 5 | -------------------------------------------------------------------------------- /app/serializers/location_serializer.rb: -------------------------------------------------------------------------------- 1 | class LocationSerializer < BaseSerializer 2 | attributes :id, :name 3 | end 4 | -------------------------------------------------------------------------------- /config/initializers/api_taster.rb: -------------------------------------------------------------------------------- 1 | ApiTaster.route_path = Rails.root.join('lib', 'api_tasters') if defined? ApiTaster 2 | -------------------------------------------------------------------------------- /spec/factories/location.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :location do 3 | name { Faker::Name.title } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/user/base_controller.rb: -------------------------------------------------------------------------------- 1 | class User::BaseController < ApplicationController 2 | before_filter :authenticate_user! 3 | end 4 | -------------------------------------------------------------------------------- /spec/factories/sequences.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | sequence(:email) { |n| "user#{n}@example.com" } 3 | sequence(:password) { '123456' } 4 | end 5 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :user do 3 | email 4 | password 5 | full_name { Faker::Name.name } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/extensions/active_record/sliced.rb: -------------------------------------------------------------------------------- 1 | ActiveRecord::Base.class_eval do 2 | def sliced_attributes(keys) 3 | attributes.slice(*keys) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/location.rb: -------------------------------------------------------------------------------- 1 | class Location < ActiveRecord::Base 2 | has_many :units, include: :user, order: :id 3 | 4 | validates :name, presence: true, uniqueness: true 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/active_model_serializer.rb: -------------------------------------------------------------------------------- 1 | ActiveSupport.on_load(:active_model_serializers) do 2 | self.root = false 3 | ActiveModel::ArraySerializer.root = false 4 | end 5 | -------------------------------------------------------------------------------- /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 InventoryReborn::Application 5 | -------------------------------------------------------------------------------- /config/initializers/mail_safe.rb: -------------------------------------------------------------------------------- 1 | # allow send emails to the @example.com 2 | # 3 | if defined?(MailSafe::Config) 4 | MailSafe::Config.internal_address_definition = /^.*@example\.com$/i 5 | end -------------------------------------------------------------------------------- /script/quality: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | bin/brakeman --quiet --skip-libs --except ForgerySetting 6 | bin/rails_best_practices --silent --spec --features -x lib/templates 7 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | InventoryReborn::Application.initialize! 6 | -------------------------------------------------------------------------------- /app/serializers/unit_serializer.rb: -------------------------------------------------------------------------------- 1 | class UnitSerializer < BaseSerializer 2 | attributes :unit_type, :inv_id, :name, :description, :on_depot, :out_of_order 3 | 4 | has_one :user, :location 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | expose(:users) 5 | 6 | def index 7 | respond_with users 8 | end 9 | end -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /lib/simplecov/rails_api_profile.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov' 2 | 3 | SimpleCov.adapters.define 'rails-api' do 4 | load_adapter 'rails' 5 | add_filter 'api_taster' 6 | add_filter 'examples' 7 | add_filter 'serializers/' 8 | end 9 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /spec/support/matchers/be_a_full_user_representation.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :be_a_full_user_representation do |user| 2 | match do |json| 3 | json.should be_a_user_representation(user, 'authentication_token') 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/matchers/include_attributes.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :include_attributes do |expected| 2 | match_for_should do |actual| 3 | actual.should RSpec::Matchers::BuiltIn::Include.new(expected.as_json) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/serializers/user_serializer.rb: -------------------------------------------------------------------------------- 1 | class UserSerializer < BaseSerializer 2 | attributes :id, :authentication_token, :email, :full_name 3 | 4 | def include_authentication_token? 5 | options[:full_representation] 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/support/shared_examples/success_response.rb: -------------------------------------------------------------------------------- 1 | shared_examples 'a request with valid params' do |code| 2 | it 'returns http success' do 3 | expect(response).to be_success 4 | expect(response.code).to eq code 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20130614112947_create_locations.rb: -------------------------------------------------------------------------------- 1 | class CreateLocations < ActiveRecord::Migration 2 | def change 3 | create_table :locations do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/api_tasters/users.rb: -------------------------------------------------------------------------------- 1 | ApiTaster.routes do 2 | desc <<-markdown.strip_heredoc 3 | ## List all users 4 | markdown 5 | 6 | get '/users', 7 | authentication_token: Examples.user.authentication_token 8 | end if defined? ApiTaster -------------------------------------------------------------------------------- /config/initializers/bullet.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.after_initialize do 2 | Bullet.enable = true 3 | Bullet.alert = true 4 | Bullet.rails_logger = true 5 | Bullet.console = true 6 | Bullet.airbrake = true 7 | end if defined?(Bullet) 8 | -------------------------------------------------------------------------------- /config/initializers/generators.rb: -------------------------------------------------------------------------------- 1 | InventoryReborn::Application.configure do 2 | config.generators do |g| 3 | g.fixture_replacement :factory_girl, dir: 'spec/factories' 4 | g.stylesheets false 5 | g.javascripts false 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 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /config/initializers/time_formats.rb: -------------------------------------------------------------------------------- 1 | { 2 | short_date: '%x', 3 | long_date: '%a, %b %d, %Y', 4 | us: '%m/%d/%Y %I:%M %p', 5 | us_date: '%m/%d/%Y', 6 | us_time: '%I:%M %p' 7 | }.each do |k, v| 8 | Time::DATE_FORMATS.update(k => v) 9 | end 10 | -------------------------------------------------------------------------------- /lib/tasks/db.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | desc 'Generates model schema diagram' 3 | task generate_schema_diagram: :environment do 4 | %x(bundle exec erd --filetype=png --notation=uml --inheritance --polymorphism --filename=doc/schema) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/support/shared_examples/authentication.rb: -------------------------------------------------------------------------------- 1 | shared_examples 'a method that requires an authentication' do 2 | it 'responds unauthorized with an HTTP 401 status code' do 3 | send method, url 4 | expect(response.code).to eq '401' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/01_config.rb: -------------------------------------------------------------------------------- 1 | # The shortcut for getting application config 2 | # Application config should be stored in the config/application.rb, config/environments/*.rb 3 | module Kernel 4 | def app_config 5 | Rails.application.config 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/helpers.rb: -------------------------------------------------------------------------------- 1 | module Helpers 2 | def set_devise_mapping(mapping_name = :user) 3 | @request.env['devise.mapping'] = Devise.mappings[mapping_name] 4 | end 5 | 6 | def json_response_body 7 | JSON.parse(response.body) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /config/initializers/requires.rb: -------------------------------------------------------------------------------- 1 | # Require recursively all files in the lib/extensions 2 | Dir[Rails.root.join('lib/extensions/**/*.rb')].each {|f| require f} 3 | 4 | # Require only files placed in the lib folder 5 | Dir[Rails.root.join('lib/*.rb')].each {|f| require f} 6 | -------------------------------------------------------------------------------- /lib/api_tasters/sessions.rb: -------------------------------------------------------------------------------- 1 | ApiTaster.routes do 2 | desc <<-markdown.strip_heredoc 3 | ## Visitor signs in 4 | markdown 5 | 6 | post '/users/sign_in', user: { 7 | email: Examples.user.email, 8 | password: Examples.password 9 | } 10 | end if defined? ApiTaster 11 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < Devise::SessionsController 2 | wrap_parameters :user 3 | 4 | def create 5 | user = AuthenticationService.new(warden).authenticate! 6 | 7 | respond_with user, 8 | full_representation: true 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/serializers/unit_serializer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UnitSerializer do 4 | let(:unit) { build :unit } 5 | let(:json) { UnitSerializer.new(unit).to_json } 6 | 7 | subject { JSON.parse(json) } 8 | 9 | it { should be_a_unit_representation(unit) } 10 | end 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | InventoryReborn::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | devise :database_authenticatable, :registerable, 3 | :recoverable, :validatable, 4 | :token_authenticatable 5 | 6 | has_many :units, include: :location, order: :id 7 | 8 | before_save :ensure_authentication_token 9 | end 10 | -------------------------------------------------------------------------------- /config/initializers/strong_parameters.rb: -------------------------------------------------------------------------------- 1 | ActiveSupport.on_load(:active_record) do 2 | ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection) 3 | end 4 | 5 | ActiveSupport.on_load(:action_controller) do 6 | ActionController::API.send :include, ActionController::StrongParameters 7 | end 8 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | describe 'validations' do 5 | context 'uniqueness' do 6 | it { should validate_uniqueness_of :email } 7 | end 8 | end 9 | 10 | describe 'associations' do 11 | it { should have_many :units } 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::API 2 | include ActionController::MimeResponds 3 | 4 | self.responder = ApiResponder 5 | 6 | decent_configuration do 7 | strategy DecentExposure::StrongParametersStrategy 8 | end 9 | 10 | respond_to :json 11 | end 12 | -------------------------------------------------------------------------------- /spec/models/location_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Location do 4 | describe 'associations' do 5 | it { should have_many :units } 6 | end 7 | 8 | describe 'validations' do 9 | it { should validate_presence_of :name } 10 | it { should validate_uniqueness_of :name } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/serializers/location_serializer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe LocationSerializer do 4 | let(:location) { build :location, id: 1 } 5 | let(:json) { LocationSerializer.new(location).to_json } 6 | 7 | subject { JSON.parse(json) } 8 | 9 | it { should be_a_location_representation(location) } 10 | end 11 | -------------------------------------------------------------------------------- /app/models/unit.rb: -------------------------------------------------------------------------------- 1 | class Unit < ActiveRecord::Base 2 | belongs_to :user 3 | belongs_to :location 4 | 5 | validates :inv_id, presence: true, uniqueness: true, numericality: true 6 | validates :name, :unit_type, :location, :user, presence: true 7 | validates :out_of_order_note, presence: true, if: proc { |u| u.out_of_order? } 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/unit.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :unit do 3 | unit_type 'Awesome Type' 4 | sequence :inv_id 5 | name { Faker::Name.title } 6 | description 'Awesome Description' 7 | on_depot false 8 | out_of_order true 9 | out_of_order_note 'Awesome Text' 10 | user 11 | location 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/matchers/be_a_location_representation.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :be_a_location_representation do |location| 2 | match do |json| 3 | response_attributes = location.sliced_attributes %w[ 4 | id 5 | name 6 | ] 7 | 8 | expect(json).to be 9 | expect(json).to include_attributes(response_attributes) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /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/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | ActiveSupport.on_load(:action_controller) do 2 | # Make sure ParamsWrapper module included 3 | ActionController::API.send(:include, ActionController::ParamsWrapper) 4 | 5 | # Enable parameter wrapping for JSON 6 | wrap_parameters( 7 | format: [:json, :url_encoded_form], 8 | exclude: [Devise.token_authentication_key] 9 | ) 10 | end 11 | -------------------------------------------------------------------------------- /app/responders/api_responder.rb: -------------------------------------------------------------------------------- 1 | class ApiResponder < ActionController::Responder 2 | def api_behavior(error) 3 | raise error unless resourceful? 4 | 5 | if get? 6 | display resource 7 | elsif post? 8 | display resource, status: :created, location: nil 9 | elsif put? 10 | display resource, status: :ok 11 | else 12 | head :no_content 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/matchers/be_a_user_representation.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :be_a_user_representation do |user, *keys| 2 | match do |json| 3 | default_keys = %w[ 4 | id 5 | email 6 | full_name 7 | ] 8 | keys.concat(default_keys) 9 | response_attributes = user.sliced_attributes keys 10 | 11 | json.should be 12 | json.should include_attributes(response_attributes) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/matchers/be_a_unit_representation.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :be_a_unit_representation do |unit| 2 | match do |json| 3 | response_attributes = unit.sliced_attributes %w[ 4 | unit_type 5 | inv_id 6 | name 7 | description 8 | on_depot 9 | out_of_order 10 | ] 11 | 12 | expect(json).to be 13 | expect(json).to include_attributes(response_attributes) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/services/authentication_service.rb: -------------------------------------------------------------------------------- 1 | class AuthenticationService 2 | SCOPE = :user 3 | 4 | def initialize(warden) 5 | @warden = warden 6 | end 7 | 8 | def authenticate! 9 | @warden.authenticate!(authentication_options).tap do |user| 10 | user.ensure_authentication_token! 11 | end 12 | end 13 | 14 | private 15 | 16 | def authentication_options 17 | { store: false, scope: SCOPE } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Rails.application.config.secret_token = '2bcc1492fb9e2f8158a1bb5e951022317eba080b195d676d77d65f2f8a2ee751d816683e05a8ea21673219' 8 | -------------------------------------------------------------------------------- /spec/controllers/sessions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SessionsController do 4 | before do 5 | set_devise_mapping(:user) 6 | end 7 | 8 | describe 'POST #create' do 9 | before do 10 | AuthenticationService. 11 | any_instance. 12 | should_receive(:authenticate!) { build :user } 13 | 14 | post :create, 15 | format: :json 16 | end 17 | 18 | it_behaves_like 'a request with valid params', '201' 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/support/extensions/rspec-rails/mock_model.rb: -------------------------------------------------------------------------------- 1 | module RSpec 2 | module Rails 3 | module Mocks 4 | def mock_model_with_read_attribute_for_serialization(string_or_model_class, stubs = {}) 5 | stubs = stubs.update(read_attribute_for_serialization: 'attribute') 6 | mock_model_without_read_attribute_for_serialization(string_or_model_class, stubs) 7 | end 8 | 9 | alias_method_chain :mock_model, :read_attribute_for_serialization 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | /.bundle 8 | /db/*.sqlite3 9 | /log/*.log 10 | /tmp 11 | coverage/* 12 | rerun.txt 13 | config/database.yml 14 | doc/**/* 15 | vendor/bundle 16 | vendor/cache 17 | vendor/ruby 18 | bin 19 | .sass-cache 20 | ._* 21 | .env 22 | -------------------------------------------------------------------------------- /config/database.yml.example: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: postgresql 3 | encoding: unicode 4 | database: rails3_base_api_dev 5 | pool: 5 6 | username: postgres 7 | password: postgres 8 | 9 | # Warning: The database defined as "test" will be erased and 10 | # re-generated from your development database when you run "rake". 11 | # Do not set this db to the same as development or production. 12 | test: 13 | adapter: postgresql 14 | encoding: unicode 15 | database: rails3_base_api_test 16 | pool: 5 17 | username: postgres 18 | password: postgres 19 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard 'rspec', notification: true, zeus: true, binstubs: true do 2 | watch(%r{^spec/.+_spec\.rb$}) 3 | watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } 4 | watch('spec/spec_helper.rb') { "spec" } 5 | 6 | # Rails example 7 | watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 8 | watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb"] } 9 | watch(%r{^spec/support/(.+)\.rb$}) { "spec" } 10 | watch('app/controllers/application_controller.rb') { "spec/controllers" } 11 | end 12 | 13 | -------------------------------------------------------------------------------- /spec/controllers/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UsersController do 4 | let(:user) { create :user } 5 | let(:users) { [user] } 6 | 7 | before do 8 | sign_in user 9 | end 10 | 11 | describe "GET #index" do 12 | before do 13 | User.stub(:scoped) { users } 14 | users.stub(:where) { users } 15 | 16 | get 'index', format: 'json' 17 | end 18 | 19 | it_behaves_like 'a request with valid params', '200' 20 | 21 | it 'assigns users' do 22 | expect(controller.users).to eq users 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20130614115836_create_units.rb: -------------------------------------------------------------------------------- 1 | class CreateUnits < ActiveRecord::Migration 2 | def change 3 | create_table :units do |t| 4 | t.string :unit_type 5 | t.integer :inv_id 6 | t.string :name 7 | t.text :description 8 | t.integer :user_id 9 | t.integer :location_id 10 | t.boolean :on_depot, default: false 11 | t.boolean :out_of_order, default: false 12 | t.text :out_of_order_note 13 | 14 | t.timestamps 15 | end 16 | 17 | add_index :units, :inv_id 18 | add_index :units, :location_id 19 | add_index :units, :user_id 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/serializers/user_serializer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UserSerializer do 4 | let(:user) { build :user, id: 1, authentication_token: 'token' } 5 | subject { JSON.parse(json) } 6 | 7 | context 'full representation' do 8 | let(:json) { UserSerializer.new(user, full_representation: true).to_json } 9 | 10 | it { should be_a_full_user_representation(user) } 11 | end 12 | 13 | context 'base representation' do 14 | let(:json) { UserSerializer.new(user).to_json } 15 | 16 | it { should be_a_user_representation(user) } 17 | it { should_not be_a_full_user_representation(user) } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/examples.rb: -------------------------------------------------------------------------------- 1 | module Examples 2 | extend self 3 | 4 | def user 5 | @user ||= User.first 6 | end 7 | 8 | def password 9 | '123456' 10 | end 11 | 12 | def location 13 | @location ||= Location.first_or_create FactoryGirl.attributes_for(:location) 14 | end 15 | 16 | def unit 17 | @unit ||= Unit.first_or_create FactoryGirl.attributes_for(:unit, user: user, location: location) 18 | end 19 | 20 | def setup! 21 | ActiveRecord::Base.transaction do 22 | FactoryGirl.create :user 23 | 24 | FactoryGirl.create :location 25 | 26 | FactoryGirl.create_list :unit, 3, user: user, location: location 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | InventoryReborn::Application.routes.draw do 2 | scope defaults: { format: :json } do 3 | devise_for :users, only: [] 4 | devise_scope :user do 5 | post 'users/sign_in', to: 'sessions#create' 6 | end 7 | 8 | resources :users, only: :index do 9 | resources :units, only: :index 10 | end 11 | 12 | resources :locations, only: [:index, :show, :create, :update] do 13 | resources :units, only: :index 14 | end 15 | 16 | resources :units, only: [:index, :show, :create, :update] 17 | end 18 | 19 | if defined? ApiTaster::Engine 20 | mount ApiTaster::Engine => '/api_taster' 21 | root to: ApiTaster::Engine 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/interactors/unit_saver.rb: -------------------------------------------------------------------------------- 1 | class UnitSaver 2 | include Interactor 3 | 4 | def setup 5 | @unit = context[:unit] 6 | @params = context[:unit_params] 7 | end 8 | 9 | def perform 10 | @unit.assign_attributes(unit_params) 11 | @unit.user = user 12 | @unit.location = location 13 | 14 | @unit.save! 15 | end 16 | 17 | private 18 | 19 | def location 20 | @location ||= Location.find(@params[:location_id]) 21 | end 22 | 23 | def user 24 | @user ||= User.find(@params[:user_id]) 25 | end 26 | 27 | def unit_params 28 | @unit_params ||= @params.except(:location_id, :user_id).permit(:unit_type, :inv_id, :name, 29 | :description, :on_depot, :out_of_order, :out_of_order_note) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/api/sessions_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe '/users/sign_in' do 4 | subject { json_response_body } 5 | 6 | describe 'sign in' do 7 | let(:url) { '/users/sign_in' } 8 | 9 | context 'with valid credentials' do 10 | let(:user) { create :user, password: '123456' } 11 | let(:params) do 12 | { 13 | email: user.email, 14 | password: '123456' 15 | } 16 | end 17 | 18 | before { post url, params } 19 | 20 | it { should be_a_full_user_representation(user) } 21 | end 22 | 23 | context 'with invalid credentials' do 24 | let(:method) { :post } 25 | 26 | it_behaves_like 'a method that requires an authentication' 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /app/interactors/unit_fetcher.rb: -------------------------------------------------------------------------------- 1 | class UnitFetcher 2 | include Interactor 3 | 4 | def perform 5 | get_units 6 | get_ancestors 7 | end 8 | 9 | private 10 | 11 | def get_units 12 | context[:units] = user.units.presence || location.units.presence || Unit.includes(:user, :location) 13 | end 14 | 15 | def get_ancestors 16 | context[:ancestors] = if user.persisted? 17 | [:location] 18 | elsif location.persisted? 19 | [:user] 20 | else 21 | [:user, :location] 22 | end 23 | end 24 | 25 | def user 26 | @user ||= context['user_id'] ? User.find(context['user_id']) : User.new 27 | end 28 | 29 | def location 30 | @location ||= context['location_id'] ? Location.find(context['location_id']) : Location.new 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /app/controllers/units_controller.rb: -------------------------------------------------------------------------------- 1 | class UnitsController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | expose(:unit_fetcher) { UnitFetcher.perform(params) } 5 | expose(:units) { unit_fetcher.units } 6 | expose(:unit) 7 | 8 | def index 9 | respond_with units, 10 | serializer_includes: { 11 | unit: unit_fetcher.ancestors 12 | } 13 | end 14 | 15 | def show 16 | respond_with unit, 17 | serializer_includes: { 18 | unit: [:user, :location] 19 | } 20 | end 21 | 22 | def create 23 | UnitSaver.perform(unit: unit, unit_params: params[:unit]) 24 | 25 | respond_with unit 26 | end 27 | 28 | def update 29 | UnitSaver.perform(unit: unit, unit_params: params[:unit]) 30 | 31 | respond_with unit 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/api/users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'resource users' do 4 | describe 'list' do 5 | let!(:users) { create_list :user, 2 } 6 | let!(:user) { users.first } 7 | let(:params) { { authentication_token: user.authentication_token } } 8 | subject { json_response_body } 9 | 10 | context 'GET /users' do 11 | let(:method) { :get } 12 | let(:url) { '/users' } 13 | 14 | it_behaves_like 'a method that requires an authentication' 15 | 16 | context 'with authentication token' do 17 | before { get url, params } 18 | 19 | it { should be_a_kind_of Array } 20 | its(:first) { should be_a_user_representation(user) } 21 | its(:count) { should eq(2) } 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

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

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /app/controllers/locations_controller.rb: -------------------------------------------------------------------------------- 1 | class LocationsController < ApplicationController 2 | before_filter :authenticate_user! 3 | 4 | # We can't use loaction method b/c 5 | # it defined in the ActionController already 6 | expose(:unit_locations) { Location.scoped } 7 | expose(:unit_location, model: :location, attributes: :location_params) 8 | 9 | def index 10 | respond_with unit_locations 11 | end 12 | 13 | def show 14 | respond_with unit_location 15 | end 16 | 17 | def create 18 | unit_location.save 19 | 20 | respond_with unit_location 21 | end 22 | 23 | def update 24 | unit_location.save 25 | 26 | respond_with unit_location 27 | end 28 | 29 | private 30 | 31 | def location_params 32 | params.require(:location).permit(:name) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

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

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/api_tasters/locations.rb: -------------------------------------------------------------------------------- 1 | ApiTaster.routes do 2 | desc <<-markdown.strip_heredoc 3 | ## List all locations 4 | markdown 5 | 6 | get '/locations', 7 | authentication_token: Examples.user.authentication_token 8 | 9 | desc <<-markdown.strip_heredoc 10 | ## List Single location 11 | markdown 12 | 13 | get '/locations/:id', 14 | id: Examples.location.id, 15 | authentication_token: Examples.user.authentication_token 16 | 17 | desc <<-markdown.strip_heredoc 18 | ## Create location 19 | markdown 20 | 21 | post '/locations', 22 | location: FactoryGirl.attributes_for(:location), 23 | authentication_token: Examples.user.authentication_token 24 | 25 | desc <<-markdown.strip_heredoc 26 | ## Update location 27 | markdown 28 | 29 | put '/locations/:id', 30 | id: Examples.location.id, 31 | location: FactoryGirl.attributes_for(:location), 32 | authentication_token: Examples.user.authentication_token 33 | end if defined? ApiTaster 34 | -------------------------------------------------------------------------------- /db/migrate/20130319140714_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table(:users) do |t| 4 | ## Database authenticatable 5 | t.string :email, null: false, default: '' 6 | t.string :encrypted_password, null: false, default: '' 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, default: 0 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.string :current_sign_in_ip 20 | t.string :last_sign_in_ip 21 | 22 | ## Token authenticatable 23 | t.string :authentication_token 24 | 25 | t.string :full_name 26 | 27 | t.timestamps 28 | end 29 | 30 | add_index :users, :email, unique: true 31 | add_index :users, :reset_password_token, unique: true 32 | add_index :users, :authentication_token, unique: true 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/extensions/active_model_serializer/include_only_declared_associations.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/concern' 2 | 3 | module ActiveModel::Serializer::IncludeOnlyDeclaredAssociations 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | alias_method_chain :include_associations!, :only_declared_associations 8 | end 9 | 10 | private 11 | 12 | def include_associations_with_only_declared_associations! 13 | include_only_declared_associations! 14 | end 15 | 16 | def include_only_declared_associations! 17 | associations_inclusion_options.each do |association| 18 | include!(association) 19 | end if has_associations_inclusion_options? 20 | end 21 | 22 | def has_associations_inclusion_options? 23 | options.include?(:serializer_includes) && 24 | associations_inclusion_options.present? 25 | end 26 | 27 | def associations_inclusion_options 28 | options[:serializer_includes][current_serializer] 29 | end 30 | 31 | def current_serializer 32 | self.class.name.demodulize.underscore.sub(/_serializer$/, '').to_sym 33 | end 34 | end 35 | 36 | ActiveModel::Serializer.send(:include, ActiveModel::Serializer::IncludeOnlyDeclaredAssociations) 37 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | ruby '2.0.0' 4 | 5 | gem 'rails', '3.2.13' 6 | 7 | gem 'rails-api' 8 | 9 | gem 'pg' 10 | gem 'thin' 11 | gem 'decent_exposure' 12 | gem 'active_model_serializers' 13 | gem 'seedbank', github: 'james2m/seedbank' 14 | gem 'dotenv' 15 | gem 'strong_parameters' 16 | gem 'devise' 17 | gem 'rollbar' 18 | gem 'interactor-rails' 19 | 20 | group :development do 21 | gem 'letter_opener' 22 | gem 'foreman' 23 | gem 'bullet' 24 | 25 | gem 'guard-rspec' 26 | gem 'rb-fsevent', require: false 27 | gem 'zeus' 28 | gem 'rails-erd' 29 | gem 'pry-remote' 30 | gem 'pry-stack_explorer' 31 | end 32 | 33 | group :development, :test do 34 | gem 'rspec-rails' 35 | gem 'mail_safe' 36 | gem 'rails_best_practices' 37 | gem 'brakeman' 38 | gem 'pry-rails' 39 | gem 'pry-debugger' 40 | end 41 | 42 | group :test do 43 | gem 'simplecov', require: false 44 | gem 'webmock', require: false 45 | 46 | gem 'capybara' 47 | gem 'database_cleaner' 48 | gem 'email_spec' 49 | gem 'shoulda-matchers' 50 | end 51 | 52 | group :development, :staging do 53 | gem 'api_taster' 54 | end 55 | 56 | group :development, :test, :staging do 57 | gem 'faker' 58 | gem 'factory_girl_rails' 59 | end 60 | -------------------------------------------------------------------------------- /spec/models/unit_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Unit do 4 | let(:unit) { build :unit } 5 | 6 | describe 'associations' do 7 | it { should belong_to :user } 8 | it { should belong_to :location } 9 | end 10 | 11 | describe 'validations' do 12 | context 'presence' do 13 | it { should validate_presence_of :name } 14 | it { should validate_presence_of :unit_type } 15 | it { should validate_presence_of :location } 16 | it { should validate_presence_of :user } 17 | it { should validate_presence_of :inv_id } 18 | 19 | context 'out_of_order_note' do 20 | it 'skip validation with out_of_order is not true' do 21 | unit.out_of_order = false 22 | unit.out_of_order_note = nil 23 | unit.should be_valid 24 | end 25 | 26 | it 'validates presence if out_of_order is true' do 27 | unit.out_of_order_note = nil 28 | unit.should_not be_valid 29 | end 30 | end 31 | end 32 | 33 | context 'uniqueness' do 34 | it { should validate_uniqueness_of :inv_id } 35 | end 36 | 37 | context 'numericality' do 38 | it { should validate_numericality_of :inv_id } 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/interactors/unit_saver_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UnitSaver do 4 | let(:user) { build :user } 5 | let(:unit) { build :unit } 6 | let(:location) { build :location } 7 | let(:unit_params) { attributes_for :unit } 8 | 9 | before do 10 | unit.stub(:save!) { true } 11 | Location.stub(:find) { location } 12 | User.stub(:find) { user } 13 | unit_params.stub(:except) { unit_params } 14 | unit_params.stub(:permit) { unit_params } 15 | end 16 | 17 | describe '#perform' do 18 | it 'receive assing_attributes' do 19 | unit.should_receive(:assign_attributes) { unit } 20 | UnitSaver.perform(unit: unit, unit_params: unit_params) 21 | end 22 | 23 | it 'receive save' do 24 | unit.should_receive(:save!) { true } 25 | UnitSaver.perform(unit: unit, unit_params: unit_params) 26 | end 27 | 28 | context 'assign user and location to unit' do 29 | before do 30 | UnitSaver.perform(unit: unit, unit_params: unit_params) 31 | end 32 | 33 | it 'assign user to unit' do 34 | unit.user.should eq user 35 | end 36 | 37 | it 'assign location to unit' do 38 | unit.location.should eq location 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'simplecov/rails_api_profile' 2 | SimpleCov.start 'rails-api' 3 | 4 | ENV["RAILS_ENV"] ||= 'test' 5 | 6 | require File.expand_path("../../config/environment", __FILE__) 7 | require 'rspec/rails' 8 | # require 'rspec/autorun' should be diabled with guard 9 | 10 | paths = Dir[Rails.root.join('spec/**/{support,extensions}/**/*.rb')] 11 | paths.each { |file| require file } 12 | 13 | RSpec.configure do |config| 14 | config.use_transactional_fixtures = true 15 | 16 | config.include Rails.application.routes.url_helpers 17 | config.include EmailSpec::Helpers 18 | config.include EmailSpec::Matchers 19 | config.include Devise::TestHelpers, type: :controller 20 | config.include FactoryGirl::Syntax::Methods 21 | config.include Helpers 22 | 23 | config.infer_base_class_for_anonymous_controllers = false 24 | 25 | config.order = "random" 26 | 27 | config.before :suite do 28 | DatabaseCleaner.strategy = :transaction 29 | DatabaseCleaner.clean_with :truncation 30 | end 31 | 32 | config.before do 33 | ActionMailer::Base.deliveries.clear 34 | end 35 | 36 | # Make sure we will send all requests with correct content type 37 | # 38 | config.before(type: :controller) do 39 | request.env['CONTENT_TYPE'] = 'application/json' 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | InventoryReborn::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 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 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 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Raise exception on mass assignment protection for Active Record models 26 | config.active_record.mass_assignment_sanitizer = :strict 27 | 28 | # Log the query plan for queries taking more than this (works 29 | # with SQLite, MySQL, and PostgreSQL) 30 | config.active_record.auto_explain_threshold_in_seconds = 0.5 31 | 32 | # Do not compress assets 33 | config.assets.compress = false 34 | 35 | # Expands the lines which load the assets 36 | config.assets.debug = true 37 | end 38 | -------------------------------------------------------------------------------- /lib/api_tasters/units.rb: -------------------------------------------------------------------------------- 1 | ApiTaster.routes do 2 | desc <<-markdown.strip_heredoc 3 | ## List all units 4 | markdown 5 | 6 | get '/units', 7 | authentication_token: Examples.user.authentication_token 8 | 9 | 10 | desc <<-markdown.strip_heredoc 11 | ## List units for user 12 | markdown 13 | 14 | get '/users/:user_id/units', 15 | user_id: Examples.user.id, 16 | authentication_token: Examples.user.authentication_token 17 | 18 | 19 | desc <<-markdown.strip_heredoc 20 | ## List units for location 21 | markdown 22 | 23 | get '/locations/:location_id/units', 24 | location_id: Examples.location.id, 25 | authentication_token: Examples.user.authentication_token 26 | 27 | desc <<-markdown.strip_heredoc 28 | ## Single unit 29 | markdown 30 | 31 | get '/units/:id', 32 | id: Examples.unit.id, 33 | authentication_token: Examples.user.authentication_token 34 | 35 | desc <<-markdown.strip_heredoc 36 | ## Create unit 37 | markdown 38 | 39 | post '/units', 40 | { 41 | unit: FactoryGirl.attributes_for(:unit). 42 | merge({ location_id: Examples.location.id, user_id: Examples.user.id }) 43 | }.merge({ authentication_token: Examples.user.authentication_token }) 44 | 45 | desc <<-markdown.strip_heredoc 46 | ## Update unit 47 | markdown 48 | 49 | put '/units/:id', 50 | { 51 | id: Examples.unit.id, 52 | unit: FactoryGirl.attributes_for(:unit). 53 | merge({ location_id: Examples.location.id, user_id: Examples.user.id }) 54 | }.merge({ authentication_token: Examples.user.authentication_token }) 55 | end if defined? ApiTaster 56 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | InventoryReborn::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 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | end 38 | -------------------------------------------------------------------------------- /config/rails_best_practices.yml: -------------------------------------------------------------------------------- 1 | AddModelVirtualAttributeCheck: { } 2 | AlwaysAddDbIndexCheck: { } 3 | #CheckSaveReturnValueCheck: { } 4 | DryBundlerInCapistranoCheck: { } 5 | HashSyntaxCheck: { } 6 | IsolateSeedDataCheck: { } 7 | KeepFindersOnTheirOwnModelCheck: { } 8 | LawOfDemeterCheck: { } 9 | #LongLineCheck: { max_line_length: 80 } 10 | MoveCodeIntoControllerCheck: { } 11 | MoveCodeIntoHelperCheck: { array_count: 3 } 12 | MoveCodeIntoModelCheck: { use_count: 2 } 13 | MoveFinderToNamedScopeCheck: { } 14 | MoveModelLogicIntoModelCheck: { use_count: 4 } 15 | NeedlessDeepNestingCheck: { nested_count: 2 } 16 | NotRescueExceptionCheck: { } 17 | NotUseDefaultRouteCheck: { } 18 | NotUseTimeAgoInWordsCheck: { } 19 | OveruseRouteCustomizationsCheck: { customize_count: 3 } 20 | ProtectMassAssignmentCheck: { } 21 | RemoveEmptyHelpersCheck: { } 22 | RemoveTabCheck: { } 23 | RemoveTrailingWhitespaceCheck: { } 24 | RemoveUnusedMethodsInControllersCheck: 25 | except_methods: 26 | - UnitsController#unit_params 27 | - LocationsController#location_params 28 | RemoveUnusedMethodsInHelpersCheck: { except_methods: [] } 29 | RemoveUnusedMethodsInModelsCheck: { except_methods: [] } 30 | ReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 } 31 | ReplaceInstanceVariableWithLocalVariableCheck: { } 32 | RestrictAutoGeneratedRoutesCheck: { } 33 | SimplifyRenderInControllersCheck: { } 34 | SimplifyRenderInViewsCheck: { } 35 | #UseBeforeFilterCheck: { customize_count: 2 } 36 | UseModelAssociationCheck: { } 37 | UseMultipartAlternativeAsContentTypeOfEmailCheck: { } 38 | #UseParenthesesInMethodDefCheck: { } 39 | UseObserverCheck: { } 40 | UseQueryAttributeCheck: { } 41 | UseSayWithTimeInMigrationsCheck: { } 42 | UseScopeAccessCheck: { } 43 | UseTurboSprocketsRails3Check: { } 44 | -------------------------------------------------------------------------------- /spec/controllers/locations_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe LocationsController do 4 | let(:locations) { build_list :location, 2 } 5 | let(:location) { stub_model Location } 6 | let(:location_attributes) { attributes_for :location } 7 | 8 | before do 9 | sign_in create(:user) 10 | end 11 | 12 | describe 'GET #index' do 13 | before do 14 | Location.stub(:scoped) { locations } 15 | get 'index', format: 'json' 16 | end 17 | 18 | it_behaves_like 'a request with valid params', '200' 19 | 20 | it 'assigns unit_locations' do 21 | expect(controller.unit_locations).to eq locations 22 | end 23 | end 24 | 25 | describe 'GET #show' do 26 | before do 27 | Location.stub(:scoped) { locations } 28 | locations.stub(:find) { location } 29 | 30 | get 'show', 31 | id: location.id, 32 | format: 'json' 33 | end 34 | 35 | it_behaves_like 'a request with valid params', '200' 36 | 37 | it 'assigns unit_location' do 38 | expect(controller.unit_location).to eq location 39 | end 40 | end 41 | 42 | describe 'POST #create' do 43 | before do 44 | Location.any_instance.stub(:save) { true } 45 | 46 | post 'create', 47 | location: location_attributes, 48 | format: 'json' 49 | end 50 | 51 | it_behaves_like 'a request with valid params', '201' 52 | end 53 | 54 | describe 'PUT #update' do 55 | let!(:location) { stub_model Location } 56 | 57 | before do 58 | Location.stub(:find) { location } 59 | location.stub(:save) { true } 60 | 61 | put 'update', 62 | id: location.id, 63 | location: location_attributes, 64 | format: 'json' 65 | end 66 | 67 | it_behaves_like 'a request with valid params', '200' 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /spec/interactors/unit_fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UnitFetcher do 4 | let(:units) { build_list :unit, 2 } 5 | let(:user) { build :user } 6 | let(:location) { build :location } 7 | let(:unit_fetcher) { UnitFetcher.perform } 8 | 9 | before do 10 | UnitFetcher.any_instance.stub(:user) { user } 11 | UnitFetcher.any_instance.stub(:location) { location } 12 | user.stub(:persisted?) { false } 13 | location.stub(:persisted?) { false } 14 | end 15 | 16 | describe '#units' do 17 | it 'should receive units for user' do 18 | user.should_receive(:units) { units } 19 | UnitFetcher.perform 20 | end 21 | 22 | it 'should not receive units for location' do 23 | user.stub(:units) { units } 24 | 25 | location.should_not_receive(:units) 26 | UnitFetcher.perform 27 | end 28 | 29 | it 'should receive units for location' do 30 | user.stub(:units) { [] } 31 | 32 | location.should_receive(:units) { units } 33 | UnitFetcher.perform 34 | end 35 | 36 | it 'should not receive includes for User' do 37 | user.stub(:units) { [] } 38 | location.stub(:units) { units } 39 | 40 | User.should_not_receive(:includes) 41 | UnitFetcher.perform 42 | end 43 | 44 | it 'should receive includes for User' do 45 | user.stub(:units) { [] } 46 | location.stub(:units) { [] } 47 | 48 | Unit.should_receive(:includes) { units } 49 | UnitFetcher.perform 50 | end 51 | end 52 | 53 | describe '#ancestors' do 54 | it 'should return user and location' do 55 | unit_fetcher.ancestors.should eq([:user, :location]) 56 | end 57 | 58 | it 'should return user' do 59 | location.stub(:persisted?) { true } 60 | unit_fetcher.ancestors.should eq([:user]) 61 | end 62 | 63 | it 'should return location' do 64 | user.stub(:persisted?) { true } 65 | unit_fetcher.ancestors.should eq([:location]) 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /script/ci_deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Deploy app to heroku with semaphoreapp 4 | # http://fs.github.com/dev/ci-semaphoreapp 5 | # 6 | # Usage: 7 | # script/ci_deploy branch heroku-app-name heroku-colloborator-private-key-encoded-with-base64 heroku-colloborator-api-key 8 | # Options: 9 | # * branch - will trigger deploy only for this brunch 10 | # * heroku-app-name - name of your heroku application 11 | # * code will be pushed to git from user with this private key. Key should be encoded with base64: base64 /path/to/private_key 12 | # * heroku-colloborator-api-key - user's API key requred for run heroku run rake db:migrate 13 | 14 | require 'fileutils' 15 | require 'base64' 16 | 17 | BRANCH = ARGV.shift 18 | HEROKU_APP = ARGV.shift 19 | KEY_BASE64 = ARGV.shift 20 | API_KEY = ARGV.shift 21 | CURRENT_BRANCH = ENV['BRANCH_NAME'] 22 | 23 | def prepare_ssh 24 | ssh_dir = File.expand_path('~/.ssh') 25 | 26 | FileUtils.mkdir(ssh_dir) unless File.exists?(ssh_dir) 27 | 28 | File.open("#{ssh_dir}/id_rsa", 'w') do |file| 29 | file.write(Base64.decode64(KEY_BASE64)) 30 | end 31 | 32 | File.open("#{ssh_dir}/config", 'a') do |file| 33 | file << <<-HOST 34 | Host *heroku.com* 35 | StrictHostKeyChecking no 36 | UserKnownHostsFile=/dev/null 37 | HOST 38 | end 39 | 40 | File.chmod(0600, "#{ssh_dir}/id_rsa") 41 | end 42 | 43 | def prepare_git 44 | system('git remote rm heroku 2>/dev/null') 45 | system("git remote add heroku git@heroku.com:#{HEROKU_APP}.git") || exit(1) 46 | end 47 | 48 | def deploy 49 | system("git push --force heroku #{BRANCH}:master") || exit(1) 50 | end 51 | 52 | def run_migrations 53 | system("env HEROKU_API_KEY=#{API_KEY} bundle exec heroku run rake db:migrate") || exit(1) 54 | end 55 | 56 | if CURRENT_BRANCH == BRANCH 57 | puts "Going to deploy #{BRANCH}..." 58 | 59 | prepare_ssh 60 | prepare_git 61 | deploy 62 | run_migrations 63 | 64 | puts "Deployed!" 65 | else 66 | puts "Only #{BRANCH} allowed for depoy." 67 | end -------------------------------------------------------------------------------- /config/initializers/rollbar.rb: -------------------------------------------------------------------------------- 1 | require 'rollbar/rails' 2 | 3 | Rollbar.configure do |config| 4 | config.access_token = ENV['ROLLBAR_KEY'] 5 | 6 | # Without configuration, Rollbar is enabled by in all environments. 7 | # To disable in specific environments, set config.enabled=false. 8 | # Here we'll disable in 'test': 9 | if Rails.env.test? || Rails.env.development? 10 | config.enabled = false 11 | end 12 | 13 | # By default, Rollbar will try to call the `current_user` controller method 14 | # to fetch the logged-in user object, and then call that object's `id`, 15 | # `username`, and `email` methods to fetch those properties. To customize: 16 | # config.person_method = "my_current_user" 17 | # config.person_id_method = "my_id" 18 | # config.person_username_method = "my_username" 19 | # config.person_email_method = "my_email" 20 | 21 | # If you want to attach custom data to all exception and message reports, 22 | # provide a lambda like the following. It should return a hash. 23 | # config.custom_data_method = lambda { {:some_key => "some_value" } } 24 | 25 | # Add exception class names to the exception_level_filters hash to 26 | # change the level that exception is reported at. Note that if an exception 27 | # has already been reported and logged the level will need to be changed 28 | # via the rollbar interface. 29 | # Valid levels: 'critical', 'error', 'warning', 'info', 'debug', 'ignore' 30 | # 'ignore' will cause the exception to not be reported at all. 31 | # config.exception_level_filters.merge!('MyCriticalException' => 'critical') 32 | 33 | # Enable asynchronous reporting (uses girl_friday or Threading if girl_friday 34 | # is not installed) 35 | # config.use_async = true 36 | # Supply your own async handler: 37 | # config.async_handler = Proc.new { |payload| 38 | # Thread.new { Rollbar.process_payload(payload) } 39 | # } 40 | 41 | # Enable delayed reporting (using Sidekiq) 42 | # config.use_sidekiq = true 43 | # You can supply custom Sidekiq options: 44 | # config.use_sidekiq = { 'queue' => 'my_queue' } 45 | end 46 | -------------------------------------------------------------------------------- /spec/controllers/units_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UnitsController do 4 | let(:units) { build_list :unit, 2 } 5 | let(:unit) { build :unit, id: 1 } 6 | let(:location) { build :location, id: 1 } 7 | let(:user) { build :user, id: 1 } 8 | let(:unit_attributes) do 9 | attributes_for(:unit).merge(location_id: location.id, user_id: user.id) 10 | end 11 | 12 | before do 13 | sign_in create(:user) 14 | end 15 | 16 | describe 'GET #index' do 17 | before do 18 | controller.unit_fetcher.stub(:units) { units } 19 | get 'index', format: 'json' 20 | end 21 | 22 | it_behaves_like 'a request with valid params', '200' 23 | 24 | it 'assigns units' do 25 | expect(controller.units).to eq units 26 | end 27 | end 28 | 29 | describe 'GET #show' do 30 | before do 31 | Unit.stub(:scoped) { units } 32 | units.stub(:includes) { units } 33 | units.stub(:find) { unit } 34 | 35 | get 'show', 36 | id: unit.id, 37 | format: 'json' 38 | end 39 | 40 | it_behaves_like 'a request with valid params', '200' 41 | 42 | it 'assigns unit' do 43 | expect(controller.unit).to eq unit 44 | end 45 | end 46 | 47 | context 'update and create' do 48 | before do 49 | Location.stub(:find) { location } 50 | User.stub(:find) { user } 51 | location.stub(:persisted?) { true } 52 | end 53 | 54 | describe 'POST #create' do 55 | before do 56 | post 'create', 57 | unit: unit_attributes, 58 | format: 'json' 59 | end 60 | 61 | it_behaves_like 'a request with valid params', '201' 62 | end 63 | 64 | describe 'PUT #update' do 65 | before do 66 | Unit.stub(:scoped) { units } 67 | units.stub(:includes) { units } 68 | units.stub(:find) { unit } 69 | 70 | put 'update', 71 | id: unit.id, 72 | unit: unit_attributes, 73 | format: 'json' 74 | end 75 | 76 | it_behaves_like 'a request with valid params', '200' 77 | 78 | it 'assign attributes to unit' do 79 | expect(controller.unit).to eq unit 80 | end 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /spec/api/locations_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'resource location' do 4 | let!(:user) { create :user } 5 | let(:params) { { authentication_token: user.authentication_token } } 6 | let(:location_attributes) { attributes_for(:location) } 7 | let(:params_with_location_attributes) { params.merge(location: location_attributes) } 8 | subject { json_response_body } 9 | 10 | describe 'list' do 11 | let!(:locations) { create_list :location, 2 } 12 | let(:method) { :get } 13 | let(:url) { '/locations' } 14 | 15 | it_behaves_like 'a method that requires an authentication' 16 | 17 | context 'with authentication token' do 18 | before { get url, params } 19 | 20 | its(:first) { should be_a_location_representation(locations.first) } 21 | its(:count) { should eq(2) } 22 | end 23 | end 24 | 25 | describe 'single' do 26 | let!(:location) { create :location } 27 | let(:method) { :get } 28 | let(:url) { "/locations/#{location.id}" } 29 | 30 | it_behaves_like 'a method that requires an authentication' 31 | 32 | context 'with authentication token' do 33 | before { get url, params } 34 | 35 | it { should be_a_location_representation(location) } 36 | end 37 | end 38 | 39 | describe 'POST /locations' do 40 | let(:method) { :post } 41 | let(:url) { "/locations" } 42 | 43 | it_behaves_like 'a method that requires an authentication' 44 | 45 | context 'with authentication token' do 46 | before { post url, params_with_location_attributes } 47 | 48 | it { should be_a_location_representation(Location.last) } 49 | end 50 | end 51 | 52 | describe 'PUT /locations/:id' do 53 | let!(:location) { create :location } 54 | let(:method) { :put } 55 | let(:url) { "/locations/#{location.id}" } 56 | 57 | it_behaves_like 'a method that requires an authentication' 58 | 59 | context 'with authentication token' do 60 | before do 61 | put url, params_with_location_attributes 62 | 63 | location.assign_attributes(location_attributes) 64 | end 65 | 66 | it { should be_a_location_representation(location) } 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'fileutils' 4 | 5 | def rails_root 6 | @rails_root ||= File.expand_path('../../', __FILE__) 7 | end 8 | 9 | def check(key) 10 | FileUtils.mkdir('tmp') unless File.exists?('tmp') 11 | cache_file = "tmp/.#{key}" 12 | 13 | if File.exists?(cache_file) 14 | old_version = File.read(cache_file) 15 | else 16 | old_version = nil 17 | end 18 | 19 | version = yield(old_version) 20 | File.open(cache_file, 'w') { |f| f.puts(version || 'cached') } 21 | end 22 | 23 | def setup_database_yml 24 | unless File.exists?(File.join(rails_root, 'config/database.yml')) 25 | puts 'Database configuration file is missing, installing...' 26 | FileUtils.cp(File.join(rails_root, 'config/database.yml.example'), File.join(rails_root, 'config/database.yml')) 27 | end 28 | end 29 | 30 | def setup_dotenv 31 | unless File.exists?(File.join(rails_root, '.env')) 32 | puts 'DotEnv configuration file is missing, installing...' 33 | FileUtils.cp(File.join(rails_root, '.env.example'), File.join(rails_root, '.env')) 34 | end 35 | end 36 | 37 | def install_bundler 38 | check(:bundler) do |old_version| 39 | break if old_version 40 | 41 | unless system('which bundle > /dev/null') 42 | puts 'Bundler missing, installing...' 43 | system('gem install bundler --no-ri --no-rdoc') || exit(1) 44 | end 45 | end 46 | end 47 | 48 | def install_gems(without = 'production staging') 49 | check(:gemfile) do |old_version| 50 | # check both Gemfile and Gemfile.lock as there might be local changes that hasn't been bundled yet 51 | version = File.read('Gemfile') + File.read('Gemfile.lock') 52 | 53 | if version != old_version 54 | puts 'Gemfile changed, bundling...' 55 | system("bundle install --path vendor/bundle --binstubs --without production staging #{without}") || exit(1) 56 | end 57 | 58 | version 59 | end 60 | end 61 | 62 | def migrate_db 63 | check(:schema) do |old_version| 64 | version = File.readlines('db/schema.rb').find { |line| line.include?('define(:version') } 65 | 66 | if version != old_version 67 | puts 'Schema changed, updating databases...' 68 | system('bundle exec rake db:create db:migrate db:test:prepare') || exit(1) 69 | end 70 | 71 | version 72 | end 73 | end 74 | 75 | is_ci = ARGV.shift == 'ci' 76 | 77 | setup_database_yml 78 | setup_dotenv 79 | install_bundler 80 | install_gems(is_ci ? 'development' : '') 81 | migrate_db 82 | 83 | puts 'Everything is up to date.' 84 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | InventoryReborn::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 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | # Log the query plan for queries taking more than this (works 65 | # with SQLite, MySQL, and PostgreSQL) 66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 67 | end 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example of Rails app with API 2 | 3 | ## API 4 | 5 | Status of the API could be checked at http://localhost:5000/api_taster 6 | 7 | ### Unauthenticated user: 8 | 9 | * POST `/users/sign_in.json`: Authenticate user with given email and password 10 | * GET `/posts.json`: list posts 11 | * GET `/posts/:id.json`: get a single post 12 | 13 | ### Authenticated as user: 14 | 15 | * GET `/user/comments.json`: list comments for currently authenticated user 16 | * POST `/user/comments.json`: create comment 17 | 18 | ## What's included 19 | 20 | Application currently based on Rails 3.2 stable branch and Ruby 1.9 21 | 22 | ### Application gems: 23 | 24 | * [Decent Exposure](https://github.com/voxdolo/decent_exposure) for DRY controllers 25 | * [Thin](https://github.com/macournoyer/thin) as rails web server 26 | 27 | ### Development gems 28 | 29 | * [Foreman](https://github.com/ddollar/foreman) for managing development stack with Procfile 30 | * [Letter Opener](https://github.com/ryanb/letter_opener) for preview mail in the browser instead of sending 31 | * [Mail Safe](https://github.com/myronmarston/mail_safe) keep ActionMailer emails from escaping into the wild during development 32 | * [Bullet](https://github.com/flyerhzm/bullet) gem to kill N+1 queries and unused eager loading 33 | * [Rails Best Practices](https://github.com/railsbp/rails_best_practices) code metric tool 34 | * [Brakeman](https://github.com/presidentbeef/brakeman) static analysis security vulnerability scanner 35 | 36 | ### Testing gems 37 | 38 | * [Factory Girl](https://github.com/thoughtbot/factory_girl) for easier creation of test data 39 | * [RSpec](https://github.com/rspec/rspec) for awesome, readable isolation testing 40 | * [Shoulda Matchers](http://github.com/thoughtbot/shoulda-matchers) for frequently needed Rails and RSpec matchers 41 | * [Email Spec](https://github.com/bmabey/email-spec) Collection of rspec matchers and cucumber steps for testing emails 42 | * [ApiTaster](https://github.com/fredwu/api_taster) A quick and easy way to visually test your Rails application's API. 43 | 44 | ### Initializes 45 | 46 | * `01_config.rb` - shortcut for getting application config with `app_config` 47 | * `mailer.rb` - setup default hosts for mailer from configuration 48 | * `time_formats.rb` - setup default time formats, so you can use them like object.create_at.to_s(:us_time) 49 | * `requires.rb` - automatically requires everything in lib/ & lib/extensions 50 | 51 | ### Scripts 52 | 53 | * `script/bootstrap` - setup required gems and migrate db if needed 54 | * `script/quality` - runs brakeman and rails_best_practices for the app 55 | * `script/ci` - should be used in the CI, checkout .travis.yml for example 56 | * `script/ci_deploy` - should be used in [Semaphoreapp CI to deploy code to Heroku](http://tatsoft.ru/ci-semaphoreapp) 57 | -------------------------------------------------------------------------------- /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 to check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(:version => 20130614115836) do 15 | 16 | create_table "locations", :force => true do |t| 17 | t.string "name" 18 | t.datetime "created_at", :null => false 19 | t.datetime "updated_at", :null => false 20 | end 21 | 22 | create_table "units", :force => true do |t| 23 | t.string "unit_type" 24 | t.integer "inv_id" 25 | t.string "name" 26 | t.text "description" 27 | t.integer "user_id" 28 | t.integer "location_id" 29 | t.boolean "on_depot", :default => false 30 | t.boolean "out_of_order", :default => false 31 | t.text "out_of_order_note" 32 | t.datetime "created_at", :null => false 33 | t.datetime "updated_at", :null => false 34 | end 35 | 36 | add_index "units", ["inv_id"], :name => "index_units_on_inv_id" 37 | add_index "units", ["location_id"], :name => "index_units_on_location_id" 38 | add_index "units", ["user_id"], :name => "index_units_on_user_id" 39 | 40 | create_table "users", :force => true do |t| 41 | t.string "email", :default => "", :null => false 42 | t.string "encrypted_password", :default => "", :null => false 43 | t.string "reset_password_token" 44 | t.datetime "reset_password_sent_at" 45 | t.datetime "remember_created_at" 46 | t.integer "sign_in_count", :default => 0 47 | t.datetime "current_sign_in_at" 48 | t.datetime "last_sign_in_at" 49 | t.string "current_sign_in_ip" 50 | t.string "last_sign_in_ip" 51 | t.string "authentication_token" 52 | t.string "full_name" 53 | t.datetime "created_at", :null => false 54 | t.datetime "updated_at", :null => false 55 | end 56 | 57 | add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true 58 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true 59 | add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true 60 | 61 | end 62 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | require 'active_record/railtie' 5 | require 'action_controller/railtie' 6 | require 'action_mailer/railtie' 7 | require 'active_resource/railtie' 8 | require 'sprockets/railtie' 9 | # require "rails/test_unit/railtie" 10 | 11 | if defined?(Bundler) 12 | # If you precompile assets before deploying to production, use this line 13 | Bundler.require(*Rails.groups(assets: %w(development test))) 14 | # If you want your assets lazily compiled in production, use this line 15 | # Bundler.require(:default, :assets, Rails.env) 16 | end 17 | 18 | module InventoryReborn 19 | class Application < Rails::Application 20 | # Settings in config/environments/* take precedence over those specified here. 21 | # Application configuration should go into files in config/initializers 22 | # -- all .rb files in that directory are automatically loaded. 23 | 24 | # Custom directories with classes and modules you want to be autoloadable. 25 | # config.autoload_paths += %W(#{config.root}/extras) 26 | 27 | # Only load the plugins named here, in the order given (default is alphabetical). 28 | # :all can be used as a placeholder for all plugins not explicitly named. 29 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 30 | 31 | # Activate observers that should always be running. 32 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 33 | 34 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 35 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 36 | # config.time_zone = 'Central Time (US & Canada)' 37 | 38 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 39 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 40 | # config.i18n.default_locale = :de 41 | 42 | # Configure the default encoding used in templates for Ruby 1.9. 43 | config.encoding = 'utf-8' 44 | 45 | # Configure sensitive parameters which will be filtered from the log file. 46 | config.filter_parameters += [:password] 47 | 48 | # Enable escaping HTML in JSON. 49 | config.active_support.escape_html_entities_in_json = true 50 | 51 | # Use SQL instead of Active Record's schema dumper when creating the database. 52 | # This is necessary if your schema can't be completely dumped by the schema dumper, 53 | # like if you have constraints or database-specific column types 54 | # config.active_record.schema_format = :sql 55 | 56 | # We use ActiveModel::ForbiddenAttributesProtection instead 57 | config.active_record.whitelist_attributes = false 58 | 59 | # Enable the asset pipeline 60 | config.assets.enabled = true 61 | 62 | # Version of your assets, change this if you want to expire all your assets 63 | config.assets.version = '1.0' 64 | 65 | # If you are deploying Rails 3.1+ on Heroku, you may want to set: 66 | config.assets.initialize_on_precompile = false 67 | 68 | # By default Rails API does not include the session middleware. 69 | # Add the middleware back in to application b/c it requred by Devise and Warden 70 | config.middleware.use ActionDispatch::Session::CookieStore 71 | 72 | # Add Rack::MethodOverride middleware in order to support DELETE/PUT requests 73 | # in api_taster 74 | config.middleware.use Rack::MethodOverride 75 | 76 | # Parameter keys that are not explicitly permitted will be raised as exception 77 | config.action_controller.action_on_unpermitted_parameters = :raise 78 | 79 | # Default host for action mailer, initializers/mailer.rb 80 | config.host = 'localhost:5000' 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /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. You are now signed in." 7 | send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." 8 | 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." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account was not activated yet." 12 | invalid: "Invalid email or password." 13 | invalid_token: "Invalid authentication token." 14 | locked: "Your account is locked." 15 | not_found_in_database: "Invalid email or password." 16 | timeout: "Your session expired, please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: "You have to confirm your account before continuing." 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock Instructions" 26 | omniauth_callbacks: 27 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 28 | success: "Successfully authenticated from %{kind} account." 29 | passwords: 30 | 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." 31 | send_instructions: "You will receive an email with instructions about how to reset your password in a few minutes." 32 | 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." 33 | updated: "Your password was changed successfully. You are now signed in." 34 | updated_not_active: "Your password was changed successfully." 35 | registrations: 36 | destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." 37 | signed_up: "Welcome! You have signed up successfully." 38 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 39 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 40 | 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." 41 | 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." 42 | updated: "You updated your account successfully." 43 | sessions: 44 | signed_in: "Signed in successfully." 45 | signed_out: "Signed out successfully." 46 | unlocks: 47 | send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." 48 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." 49 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 50 | errors: 51 | messages: 52 | already_confirmed: "was already confirmed, please try signing in" 53 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 54 | expired: "has expired, please request a new one" 55 | not_found: "not found" 56 | not_locked: "was not locked" 57 | not_saved: 58 | one: "1 error prohibited this %{resource} from being saved:" 59 | other: "%{count} errors prohibited this %{resource} from being saved:" 60 | -------------------------------------------------------------------------------- /spec/api/units_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'resource units' do 4 | let!(:user) { create :user } 5 | let!(:location) { create :location } 6 | let(:params) { { authentication_token: user.authentication_token } } 7 | let(:params_with_unit_attributes) { params.merge(unit: unit_attributes) } 8 | let(:unit_attributes) do 9 | attributes_for(:unit). 10 | merge(location_id: location.id, user_id: user.id) 11 | end 12 | subject { json_response_body } 13 | 14 | describe 'list' do 15 | let!(:units) { create_list :unit, 2 } 16 | let!(:user_units) { create_list :unit, 2, user: user } 17 | let!(:location_units) { create_list :unit, 2, location: location } 18 | 19 | describe 'GET /units' do 20 | let(:method) { :get } 21 | let(:url) { '/units' } 22 | 23 | it_behaves_like 'a method that requires an authentication' 24 | 25 | context 'with authentication token' do 26 | before { get url, params } 27 | 28 | it { should be_a_kind_of Array } 29 | its(:first) { should be_a_unit_representation(units.first) } 30 | its(:count) { should eq(6) } 31 | 32 | context 'have user' do 33 | subject { json_response_body.first['user'] } 34 | it { should be_a_user_representation(units.first.user) } 35 | end 36 | 37 | context 'have location' do 38 | subject { json_response_body.first['location'] } 39 | it { should be_a_location_representation(units.first.location) } 40 | end 41 | end 42 | end 43 | 44 | describe 'GET /users/:id/units' do 45 | let(:method) { :get } 46 | let(:url) { "/users/#{user.id}/units" } 47 | 48 | it_behaves_like 'a method that requires an authentication' 49 | 50 | context 'with authentication token' do 51 | before { get url, params } 52 | 53 | it { should be_a_kind_of Array } 54 | its(:first) { should be_a_unit_representation(user_units.first) } 55 | its(:count) { should eq(2) } 56 | 57 | context 'without user' do 58 | subject { json_response_body.first['user'] } 59 | it { should be_nil } 60 | end 61 | 62 | context 'have location' do 63 | subject { json_response_body.first['location'] } 64 | it { should be_a_location_representation(user_units.first.location) } 65 | end 66 | end 67 | end 68 | 69 | describe 'GET /locations/:id/units' do 70 | let(:method) { :get } 71 | let(:url) { "/locations/#{location.id}/units" } 72 | 73 | it_behaves_like 'a method that requires an authentication' 74 | 75 | context 'with authentication token' do 76 | before { get url, params } 77 | 78 | it { should be_a_kind_of Array } 79 | its(:first) { should be_a_unit_representation(location_units.first) } 80 | its(:count) { should eq(2) } 81 | 82 | context 'have user' do 83 | subject { json_response_body.first['user'] } 84 | it { should be_a_user_representation(location_units.first.user) } 85 | end 86 | 87 | context 'without location' do 88 | subject { json_response_body.first['location'] } 89 | it { should be_nil } 90 | end 91 | end 92 | end 93 | end 94 | 95 | describe 'GET /units/:id' do 96 | let!(:unit) { create :unit, user: user, location: location } 97 | let(:method) { :get } 98 | let(:url) { "/units/#{unit.id}" } 99 | 100 | it_behaves_like 'a method that requires an authentication' 101 | 102 | context 'with authentication token' do 103 | before { get url, params } 104 | 105 | it { should be_a_unit_representation(unit) } 106 | 107 | context 'have user' do 108 | subject { json_response_body['user'] } 109 | it { should be_a_user_representation(user) } 110 | end 111 | 112 | context 'have location' do 113 | subject { json_response_body['location'] } 114 | it { should be_a_location_representation(location) } 115 | end 116 | end 117 | end 118 | 119 | describe 'POST /units' do 120 | let(:method) { :post } 121 | let(:url) { "/units" } 122 | 123 | it_behaves_like 'a method that requires an authentication' 124 | 125 | context 'with authentication token' do 126 | before { post url, params_with_unit_attributes } 127 | 128 | it { should be_a_unit_representation(user.units.last) } 129 | end 130 | end 131 | 132 | describe 'PUT /units/:id' do 133 | let!(:unit) { create :unit, user: user, location: location } 134 | let(:method) { :put } 135 | let(:url) { "/units/#{unit.id}" } 136 | 137 | it_behaves_like 'a method that requires an authentication' 138 | 139 | context 'with authentication token' do 140 | before do 141 | put url, params_with_unit_attributes 142 | 143 | unit.assign_attributes(unit_attributes) 144 | end 145 | 146 | it { should be_a_unit_representation(unit) } 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/james2m/seedbank.git 3 | revision: c7a272751336f0d17103028f45b88eac62cbedd7 4 | specs: 5 | seedbank (0.3.0.pre2) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actionmailer (3.2.13) 11 | actionpack (= 3.2.13) 12 | mail (~> 2.5.3) 13 | actionpack (3.2.13) 14 | activemodel (= 3.2.13) 15 | activesupport (= 3.2.13) 16 | builder (~> 3.0.0) 17 | erubis (~> 2.7.0) 18 | journey (~> 1.0.4) 19 | rack (~> 1.4.5) 20 | rack-cache (~> 1.2) 21 | rack-test (~> 0.6.1) 22 | sprockets (~> 2.2.1) 23 | active_model_serializers (0.8.1) 24 | activemodel (>= 3.0) 25 | activemodel (3.2.13) 26 | activesupport (= 3.2.13) 27 | builder (~> 3.0.0) 28 | activerecord (3.2.13) 29 | activemodel (= 3.2.13) 30 | activesupport (= 3.2.13) 31 | arel (~> 3.0.2) 32 | tzinfo (~> 0.3.29) 33 | activeresource (3.2.13) 34 | activemodel (= 3.2.13) 35 | activesupport (= 3.2.13) 36 | activesupport (3.2.13) 37 | i18n (= 0.6.1) 38 | multi_json (~> 1.0) 39 | addressable (2.3.5) 40 | api_taster (0.7.0) 41 | bootstrap-sass (~> 2.1) 42 | jquery-rails 43 | rails (~> 3.2.0) 44 | redcarpet 45 | remotipart (~> 1.0) 46 | sass-rails 47 | arel (3.0.2) 48 | awesome_print (1.1.0) 49 | bcrypt-ruby (3.0.1) 50 | binding_of_caller (0.7.2) 51 | debug_inspector (>= 0.0.1) 52 | bootstrap-sass (2.3.2.2) 53 | sass (~> 3.2) 54 | brakeman (2.0.0) 55 | erubis (~> 2.6) 56 | fastercsv (~> 1.5) 57 | haml (>= 3.0, < 5.0) 58 | highline (~> 1.6.19) 59 | multi_json (~> 1.2) 60 | ruby2ruby (~> 2.0.5) 61 | ruby_parser (~> 3.1.1) 62 | sass (~> 3.0) 63 | slim (~> 1.3.6) 64 | terminal-table (~> 1.4) 65 | builder (3.0.4) 66 | bullet (4.6.0) 67 | uniform_notifier 68 | capybara (2.1.0) 69 | mime-types (>= 1.16) 70 | nokogiri (>= 1.3.3) 71 | rack (>= 1.0.0) 72 | rack-test (>= 0.5.4) 73 | xpath (~> 2.0) 74 | choice (0.1.6) 75 | code_analyzer (0.3.2) 76 | sexp_processor 77 | coderay (1.0.9) 78 | colored (1.2) 79 | columnize (0.3.6) 80 | crack (0.4.0) 81 | safe_yaml (~> 0.9.0) 82 | daemons (1.1.9) 83 | database_cleaner (1.0.1) 84 | debug_inspector (0.0.2) 85 | debugger (1.6.5) 86 | columnize (>= 0.3.1) 87 | debugger-linecache (~> 1.2.0) 88 | debugger-ruby_core_source (~> 1.3.1) 89 | debugger-linecache (1.2.0) 90 | debugger-ruby_core_source (1.3.1) 91 | decent_exposure (2.2.0) 92 | devise (2.2.4) 93 | bcrypt-ruby (~> 3.0) 94 | orm_adapter (~> 0.1) 95 | railties (~> 3.1) 96 | warden (~> 1.2.1) 97 | diff-lcs (1.2.4) 98 | dotenv (0.8.0) 99 | email_spec (1.4.0) 100 | launchy (~> 2.1) 101 | mail (~> 2.2) 102 | erubis (2.7.0) 103 | eventmachine (1.0.3) 104 | factory_girl (4.2.0) 105 | activesupport (>= 3.0.0) 106 | factory_girl_rails (4.2.1) 107 | factory_girl (~> 4.2.0) 108 | railties (>= 3.0.0) 109 | faker (1.1.2) 110 | i18n (~> 0.5) 111 | fastercsv (1.5.5) 112 | ffi (1.9.0) 113 | foreman (0.63.0) 114 | dotenv (>= 0.7) 115 | thor (>= 0.13.6) 116 | formatador (0.2.4) 117 | guard (1.8.1) 118 | formatador (>= 0.2.4) 119 | listen (>= 1.0.0) 120 | lumberjack (>= 1.0.2) 121 | pry (>= 0.9.10) 122 | thor (>= 0.14.6) 123 | guard-rspec (3.0.2) 124 | guard (>= 1.8) 125 | rspec (~> 2.13) 126 | haml (4.0.3) 127 | tilt 128 | highline (1.6.19) 129 | hike (1.2.3) 130 | i18n (0.6.1) 131 | interactor (2.0.0) 132 | interactor-rails (1.0.1) 133 | interactor (< 3) 134 | rails (>= 3, < 5) 135 | journey (1.0.4) 136 | jquery-rails (3.0.4) 137 | railties (>= 3.0, < 5.0) 138 | thor (>= 0.14, < 2.0) 139 | json (1.8.0) 140 | launchy (2.3.0) 141 | addressable (~> 2.3) 142 | letter_opener (1.1.2) 143 | launchy (~> 2.2) 144 | listen (1.2.2) 145 | rb-fsevent (>= 0.9.3) 146 | rb-inotify (>= 0.9) 147 | rb-kqueue (>= 0.2) 148 | lumberjack (1.0.4) 149 | mail (2.5.4) 150 | mime-types (~> 1.16) 151 | treetop (~> 1.4.8) 152 | mail_safe (0.3.1) 153 | actionmailer (>= 1.3.6) 154 | method_source (0.8.1) 155 | mime-types (1.23) 156 | mini_portile (0.5.0) 157 | multi_json (1.7.7) 158 | nokogiri (1.6.0) 159 | mini_portile (~> 0.5.0) 160 | orm_adapter (0.4.0) 161 | pg (0.15.1) 162 | polyglot (0.3.3) 163 | pry (0.9.12.2) 164 | coderay (~> 1.0.5) 165 | method_source (~> 0.8) 166 | slop (~> 3.4) 167 | pry-debugger (0.2.2) 168 | debugger (~> 1.3) 169 | pry (~> 0.9.10) 170 | pry-rails (0.3.2) 171 | pry (>= 0.9.10) 172 | pry-remote (0.1.7) 173 | pry (~> 0.9) 174 | slop (~> 3.0) 175 | pry-stack_explorer (0.4.9.1) 176 | binding_of_caller (>= 0.7) 177 | pry (>= 0.9.11) 178 | rack (1.4.5) 179 | rack-cache (1.2) 180 | rack (>= 0.4) 181 | rack-ssl (1.3.3) 182 | rack 183 | rack-test (0.6.2) 184 | rack (>= 1.0) 185 | rails (3.2.13) 186 | actionmailer (= 3.2.13) 187 | actionpack (= 3.2.13) 188 | activerecord (= 3.2.13) 189 | activeresource (= 3.2.13) 190 | activesupport (= 3.2.13) 191 | bundler (~> 1.0) 192 | railties (= 3.2.13) 193 | rails-api (0.1.0) 194 | actionpack (>= 3.2.11) 195 | railties (>= 3.2.11) 196 | tzinfo (~> 0.3.31) 197 | rails-erd (1.1.0) 198 | activerecord (>= 3.0) 199 | activesupport (>= 3.0) 200 | choice (~> 0.1.6) 201 | ruby-graphviz (~> 1.0.4) 202 | rails_best_practices (1.13.8) 203 | activesupport 204 | awesome_print 205 | code_analyzer 206 | colored 207 | erubis 208 | i18n 209 | ruby-progressbar 210 | railties (3.2.13) 211 | actionpack (= 3.2.13) 212 | activesupport (= 3.2.13) 213 | rack-ssl (~> 1.3.2) 214 | rake (>= 0.8.7) 215 | rdoc (~> 3.4) 216 | thor (>= 0.14.6, < 2.0) 217 | rake (10.1.0) 218 | rb-fsevent (0.9.3) 219 | rb-inotify (0.9.0) 220 | ffi (>= 0.5.0) 221 | rb-kqueue (0.2.0) 222 | ffi (>= 0.5.0) 223 | rdoc (3.12.2) 224 | json (~> 1.4) 225 | redcarpet (3.0.0) 226 | remotipart (1.2.1) 227 | rollbar (0.10.11) 228 | multi_json (~> 1.5) 229 | rspec (2.13.0) 230 | rspec-core (~> 2.13.0) 231 | rspec-expectations (~> 2.13.0) 232 | rspec-mocks (~> 2.13.0) 233 | rspec-core (2.13.1) 234 | rspec-expectations (2.13.0) 235 | diff-lcs (>= 1.1.3, < 2.0) 236 | rspec-mocks (2.13.1) 237 | rspec-rails (2.13.2) 238 | actionpack (>= 3.0) 239 | activesupport (>= 3.0) 240 | railties (>= 3.0) 241 | rspec-core (~> 2.13.0) 242 | rspec-expectations (~> 2.13.0) 243 | rspec-mocks (~> 2.13.0) 244 | ruby-graphviz (1.0.9) 245 | ruby-progressbar (1.1.1) 246 | ruby2ruby (2.0.6) 247 | ruby_parser (~> 3.1) 248 | sexp_processor (~> 4.0) 249 | ruby_parser (3.1.3) 250 | sexp_processor (~> 4.1) 251 | safe_yaml (0.9.3) 252 | sass (3.2.9) 253 | sass-rails (3.2.6) 254 | railties (~> 3.2.0) 255 | sass (>= 3.1.10) 256 | tilt (~> 1.3) 257 | sexp_processor (4.2.1) 258 | shoulda-matchers (2.2.0) 259 | activesupport (>= 3.0.0) 260 | simplecov (0.7.1) 261 | multi_json (~> 1.0) 262 | simplecov-html (~> 0.7.1) 263 | simplecov-html (0.7.1) 264 | slim (1.3.9) 265 | temple (~> 0.6.3) 266 | tilt (~> 1.3, >= 1.3.3) 267 | slop (3.4.5) 268 | sprockets (2.2.2) 269 | hike (~> 1.2) 270 | multi_json (~> 1.0) 271 | rack (~> 1.0) 272 | tilt (~> 1.1, != 1.3.0) 273 | strong_parameters (0.2.1) 274 | actionpack (~> 3.0) 275 | activemodel (~> 3.0) 276 | railties (~> 3.0) 277 | temple (0.6.5) 278 | terminal-table (1.4.5) 279 | thin (1.5.1) 280 | daemons (>= 1.0.9) 281 | eventmachine (>= 0.12.6) 282 | rack (>= 1.0.0) 283 | thor (0.18.1) 284 | tilt (1.4.1) 285 | treetop (1.4.14) 286 | polyglot 287 | polyglot (>= 0.3.1) 288 | tzinfo (0.3.37) 289 | uniform_notifier (1.2.0) 290 | warden (1.2.1) 291 | rack (>= 1.0) 292 | webmock (1.12.3) 293 | addressable (>= 2.2.7) 294 | crack (>= 0.3.2) 295 | xpath (2.0.0) 296 | nokogiri (~> 1.3) 297 | zeus (0.13.3) 298 | method_source (>= 0.6.7) 299 | 300 | PLATFORMS 301 | ruby 302 | 303 | DEPENDENCIES 304 | active_model_serializers 305 | api_taster 306 | brakeman 307 | bullet 308 | capybara 309 | database_cleaner 310 | decent_exposure 311 | devise 312 | dotenv 313 | email_spec 314 | factory_girl_rails 315 | faker 316 | foreman 317 | guard-rspec 318 | interactor-rails 319 | letter_opener 320 | mail_safe 321 | pg 322 | pry-debugger 323 | pry-rails 324 | pry-remote 325 | pry-stack_explorer 326 | rails (= 3.2.13) 327 | rails-api 328 | rails-erd 329 | rails_best_practices 330 | rb-fsevent 331 | rollbar 332 | rspec-rails 333 | seedbank! 334 | shoulda-matchers 335 | simplecov 336 | strong_parameters 337 | thin 338 | webmock 339 | zeus 340 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. 2 | # Many of these configuration options can be set straight in your model. 3 | Devise.setup do |config| 4 | # ==> Mailer Configuration 5 | # Configure the e-mail address which will be shown in Devise::Mailer, 6 | # note that it will be overwritten if you use your own mailer class with default "from" parameter. 7 | config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" 8 | 9 | # Configure the class responsible to send e-mails. 10 | # config.mailer = "Devise::Mailer" 11 | 12 | # ==> ORM configuration 13 | # Load and configure the ORM. Supports :active_record (default) and 14 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 15 | # available as additional gems. 16 | require 'devise/orm/active_record' 17 | 18 | # ==> Configuration for any authentication mechanism 19 | # Configure which keys are used when authenticating a user. The default is 20 | # just :email. You can configure it to use [:username, :subdomain], so for 21 | # authenticating a user, both parameters are required. Remember that those 22 | # parameters are used only when authenticating and not when retrieving from 23 | # session. If you need permissions, you should implement that in a before filter. 24 | # You can also supply a hash where the value is a boolean determining whether 25 | # or not authentication should be aborted when the value is not present. 26 | # config.authentication_keys = [ :email ] 27 | 28 | # Configure parameters from the request object used for authentication. Each entry 29 | # given should be a request method and it will automatically be passed to the 30 | # find_for_authentication method and considered in your model lookup. For instance, 31 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 32 | # The same considerations mentioned for authentication_keys also apply to request_keys. 33 | # config.request_keys = [] 34 | 35 | # Configure which authentication keys should be case-insensitive. 36 | # These keys will be downcased upon creating or modifying a user and when used 37 | # to authenticate or find a user. Default is :email. 38 | config.case_insensitive_keys = [ :email ] 39 | 40 | # Configure which authentication keys should have whitespace stripped. 41 | # These keys will have whitespace before and after removed upon creating or 42 | # modifying a user and when used to authenticate or find a user. Default is :email. 43 | config.strip_whitespace_keys = [ :email ] 44 | 45 | # Tell if authentication through request.params is enabled. True by default. 46 | # It can be set to an array that will enable params authentication only for the 47 | # given strategies, for example, `config.params_authenticatable = [:database]` will 48 | # enable it only for database (email + password) authentication. 49 | # config.params_authenticatable = true 50 | 51 | # Tell if authentication through HTTP Basic Auth is enabled. False by default. 52 | # It can be set to an array that will enable http authentication only for the 53 | # given strategies, for example, `config.http_authenticatable = [:token]` will 54 | # enable it only for token authentication. 55 | # config.http_authenticatable = false 56 | 57 | # If http headers should be returned for AJAX requests. True by default. 58 | # config.http_authenticatable_on_xhr = true 59 | 60 | # The realm used in Http Basic Authentication. "Application" by default. 61 | # config.http_authentication_realm = "Application" 62 | 63 | # It will change confirmation, password recovery and other workflows 64 | # to behave the same regardless if the e-mail provided was right or wrong. 65 | # Does not affect registerable. 66 | # config.paranoid = true 67 | 68 | # By default Devise will store the user in session. You can skip storage for 69 | # :http_auth and :token_auth by adding those symbols to the array below. 70 | # Notice that if you are skipping storage for all authentication paths, you 71 | # may want to disable generating routes to Devise's sessions controller by 72 | # passing :skip => :sessions to `devise_for` in your config/routes.rb 73 | config.skip_session_storage = [:http_auth] 74 | 75 | # ==> Configuration for :database_authenticatable 76 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 77 | # using other encryptors, it sets how many times you want the password re-encrypted. 78 | # 79 | # Limiting the stretches to just one in testing will increase the performance of 80 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 81 | # a value less than 10 in other environments. 82 | config.stretches = Rails.env.test? ? 1 : 10 83 | 84 | # Setup a pepper to generate the encrypted password. 85 | # config.pepper = "5047b130f92d256479f134ed6a8bf278dfa696a8dc63442f124623f2c9cedb2d9b3718a738d15125fc9da48710b3cd12804d53cd9c450426e4313a101a753fae" 86 | 87 | # ==> Configuration for :confirmable 88 | # A period that the user is allowed to access the website even without 89 | # confirming his account. For instance, if set to 2.days, the user will be 90 | # able to access the website for two days without confirming his account, 91 | # access will be blocked just in the third day. Default is 0.days, meaning 92 | # the user cannot access the website without confirming his account. 93 | # config.allow_unconfirmed_access_for = 2.days 94 | 95 | # A period that the user is allowed to confirm their account before their 96 | # token becomes invalid. For example, if set to 3.days, the user can confirm 97 | # their account within 3 days after the mail was sent, but on the fourth day 98 | # their account can't be confirmed with the token any more. 99 | # Default is nil, meaning there is no restriction on how long a user can take 100 | # before confirming their account. 101 | # config.confirm_within = 3.days 102 | 103 | # If true, requires any email changes to be confirmed (exactly the same way as 104 | # initial account confirmation) to be applied. Requires additional unconfirmed_email 105 | # db field (see migrations). Until confirmed new email is stored in 106 | # unconfirmed email column, and copied to email column on successful confirmation. 107 | config.reconfirmable = true 108 | 109 | # Defines which key will be used when confirming an account 110 | # config.confirmation_keys = [ :email ] 111 | 112 | # ==> Configuration for :rememberable 113 | # The time the user will be remembered without asking for credentials again. 114 | # config.remember_for = 2.weeks 115 | 116 | # If true, extends the user's remember period when remembered via cookie. 117 | # config.extend_remember_period = false 118 | 119 | # Options to be passed to the created cookie. For instance, you can set 120 | # :secure => true in order to force SSL only cookies. 121 | # config.rememberable_options = {} 122 | 123 | # ==> Configuration for :validatable 124 | # Range for password length. Default is 8..128. 125 | config.password_length = 6..128 126 | 127 | # Email regex used to validate email formats. It simply asserts that 128 | # an one (and only one) @ exists in the given string. This is mainly 129 | # to give user feedback and not to assert the e-mail validity. 130 | # config.email_regexp = /\A[^@]+@[^@]+\z/ 131 | 132 | # ==> Configuration for :timeoutable 133 | # The time you want to timeout the user session without activity. After this 134 | # time the user will be asked for credentials again. Default is 30 minutes. 135 | # config.timeout_in = 30.minutes 136 | 137 | # If true, expires auth token on session timeout. 138 | # config.expire_auth_token_on_timeout = false 139 | 140 | # ==> Configuration for :lockable 141 | # Defines which strategy will be used to lock an account. 142 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 143 | # :none = No lock strategy. You should handle locking by yourself. 144 | # config.lock_strategy = :failed_attempts 145 | 146 | # Defines which key will be used when locking and unlocking an account 147 | # config.unlock_keys = [ :email ] 148 | 149 | # Defines which strategy will be used to unlock an account. 150 | # :email = Sends an unlock link to the user email 151 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 152 | # :both = Enables both strategies 153 | # :none = No unlock strategy. You should handle unlocking by yourself. 154 | # config.unlock_strategy = :both 155 | 156 | # Number of authentication tries before locking an account if lock_strategy 157 | # is failed attempts. 158 | # config.maximum_attempts = 20 159 | 160 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 161 | # config.unlock_in = 1.hour 162 | 163 | # ==> Configuration for :recoverable 164 | # 165 | # Defines which key will be used when recovering the password for an account 166 | # config.reset_password_keys = [ :email ] 167 | 168 | # Time interval you can reset your password with a reset password key. 169 | # Don't put a too small interval or your users won't have the time to 170 | # change their passwords. 171 | config.reset_password_within = 6.hours 172 | 173 | # ==> Configuration for :encryptable 174 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use 175 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, 176 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) 177 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy 178 | # REST_AUTH_SITE_KEY to pepper) 179 | # config.encryptor = :sha512 180 | 181 | # ==> Configuration for :token_authenticatable 182 | # Defines name of the authentication token params key 183 | config.token_authentication_key = :authentication_token 184 | 185 | # ==> Scopes configuration 186 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 187 | # "users/sessions/new". It's turned off by default because it's slower if you 188 | # are using only default views. 189 | # config.scoped_views = false 190 | 191 | # Configure the default scope given to Warden. By default it's the first 192 | # devise role declared in your routes (usually :user). 193 | # config.default_scope = :user 194 | 195 | # Set this configuration to false if you want /users/sign_out to sign out 196 | # only the current scope. By default, Devise signs out all scopes. 197 | # config.sign_out_all_scopes = true 198 | 199 | # ==> Navigation configuration 200 | # Lists the formats that should be treated as navigational. Formats like 201 | # :html, should redirect to the sign in page when the user does not have 202 | # access, but formats like :xml or :json, should return 401. 203 | # 204 | # If you have any extra navigational formats, like :iphone or :mobile, you 205 | # should add them to the navigational formats lists. 206 | # 207 | # The "*/*" below is required to match Internet Explorer requests. 208 | # config.navigational_formats = ["*/*", :html] 209 | 210 | # The default HTTP method used to sign out a resource. Default is :delete. 211 | config.sign_out_via = :delete 212 | 213 | # ==> OmniAuth 214 | # Add a new OmniAuth provider. Check the wiki for more information on setting 215 | # up on your models and hooks. 216 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' 217 | 218 | # ==> Warden configuration 219 | # If you want to use other strategies, that are not supported by Devise, or 220 | # change the failure app, you can configure them inside the config.warden block. 221 | # 222 | # config.warden do |manager| 223 | # manager.intercept_401 = false 224 | # manager.default_strategies(:scope => :user).unshift :some_external_strategy 225 | # end 226 | 227 | # ==> Mountable engine configurations 228 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine 229 | # is mountable, there are some extra configurations to be taken into account. 230 | # The following options are available, assuming the engine is mounted as: 231 | # 232 | # mount MyEngine, at: "/my_engine" 233 | # 234 | # The router that invoked `devise_for`, in the example above, would be: 235 | # config.router_name = :my_engine 236 | # 237 | # When using omniauth, Devise cannot automatically set Omniauth path, 238 | # so you need to do it manually. For the users scope, it would be: 239 | # config.omniauth_path_prefix = "/my_engine/users/auth" 240 | end 241 | --------------------------------------------------------------------------------