|  |  | @@ -19,12 +19,17 @@ def render_file(text, variables) | 
    
    |  |  | add_source 'https://rubygems.org/' | 
    
    |  |  | 
 | 
    
    |  |  | gem 'puma', '~> 3.0' | 
    
    |  |  | gem 'rails', '~> 5.0' | 
    
    |  |  | gem 'slowpoke' | 
    
    |  |  | gem 'mysql2', '>= 0.3.18', '< 0.5' # Use mysql as the database for Active Record | 
    
    |  |  | gem 'rails', '~> 5.0.0' | 
    
    |  |  | gem 'lograge' | 
    
    |  |  | gem 'wisper' | 
    
    |  |  | gem 'wisper', '2.0.0.rc1' | 
    
    |  |  | gem 'active_model_serializers' | 
    
    |  |  | gem 'rack-attack' # Rack middleware for blocking & throttling abusive requests | 
    
    |  |  | gem 'rails-i18n', '~> 5.0.0' | 
    
    |  |  | gem 'devise' | 
    
    |  |  | gem 'devise-i18n' | 
    
    |  |  | gem 'doorkeeper' | 
    
    |  |  | gem 'doorkeeper-i18n' | 
    
    |  |  | 
 | 
    
    |  |  | gem_group :development do | 
    
    |  |  | gem 'thin' | 
      
    |  |  | @@ -35,6 +40,7 @@ def render_file(text, variables) | 
    
    |  |  | gem 'capistrano3-puma', require: false | 
    
    |  |  | gem 'capistrano-sidekiq', require: false | 
    
    |  |  | gem 'better_errors' | 
    
    |  |  | gem 'listen', '~> 3.0.5' | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | gem_group :test do | 
      
    |  |  | @@ -44,7 +50,8 @@ def render_file(text, variables) | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | gem_group :development, :test do | 
    
    |  |  | gem 'spring' | 
    
    |  |  | gem 'rubocop', require: false | 
    
    |  |  | gem 'rspec-rails' | 
    
    |  |  | gem 'pry-rails' | 
    
    |  |  | gem 'pry-byebug' | 
    
    |  |  | gem 'awesome_print' | 
      
    |  |  | @@ -54,35 +61,49 @@ def render_file(text, variables) | 
    
    |  |  | 
 | 
    
    |  |  | run 'bundle install' | 
    
    |  |  | 
 | 
    
    |  |  | after_bundle do | 
    
    |  |  | setup_application | 
    
    |  |  | setup_database | 
    
    |  |  | # set_routes | 
    
    |  |  | # prepare_files | 
    
    |  |  | # setup_i18n | 
    
    |  |  | # setup_cable | 
    
    |  |  | # setup_vendor | 
    
    |  |  | # setup_git | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 2. application.rb | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | generators_config = <<-EOS | 
    
    |  |  | config.generators do |g| | 
    
    |  |  | g.test_framework :rspec | 
    
    |  |  | g.fixture_replacement :factory_girl, dir: 'spec/factories' | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | def setup_application | 
    
    |  |  | generators_config = <<-EOS | 
    
    |  |  | config.generators do |g| | 
    
    |  |  | g.test_framework :rspec | 
    
    |  |  | g.fixture_replacement :factory_girl, dir: 'spec/factories' | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | environment "config.time_zone = 'Beijing'" | 
    
    |  |  | environment "config.i18n.available_locales = ['zh-CN', :en]" | 
    
    |  |  | environment "config.i18n.default_locale = 'zh-CN'" | 
    
    |  |  | environment 'config.i18n.fallbacks = true' | 
    
    |  |  | environment 'config.middleware.use Rack::Attack' | 
    
    |  |  | environment generators_config | 
    
    |  |  | environment "config.time_zone = 'Beijing'" | 
    
    |  |  | environment "config.i18n.available_locales = ['zh-CN', :en]" | 
    
    |  |  | environment "config.i18n.default_locale = 'zh-CN'" | 
    
    |  |  | environment 'config.i18n.fallbacks = true' | 
    
    |  |  | environment 'config.middleware.use Rack::Attack' | 
    
    |  |  | environment generators_config | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 3. database.yml | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | database_temp = <<-EOS | 
    
    |  |  | def setup_database | 
    
    |  |  | database_temp = <<-EOS | 
    
    |  |  | default: &default | 
    
    |  |  | adapter: mysql2 | 
    
    |  |  | encoding: utf8 | 
    
    |  |  | pool: 5 | 
    
    |  |  | username: root | 
    
    |  |  | password: | 
    
    |  |  | password: <%= mysql_passwd %> | 
    
    |  |  | host: localhost | 
    
    |  |  |  | 
    
    |  |  | development: | 
      
    |  |  | @@ -94,5 +115,230 @@ def render_file(text, variables) | 
    
    |  |  | database: <%= app_name %>_test | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | run 'rm config/database.yml' | 
    
    |  |  | file 'config/database.yml', render_file(database_temp, app_name: app_name.downcase) | 
    
    |  |  | run 'rm config/database.yml' | 
    
    |  |  | file 'config/database.yml', render_file(database_temp, app_name: app_name.downcase, mysql_passwd: ENV['LOCAL_MYSQL_PASSWD']) | 
    
    |  |  | 
 | 
    
    |  |  | # drop_db = yes?('Drop DB for initialize? (Y/n)') | 
    
    |  |  | # rails_command 'db:drop' if drop_db | 
    
    |  |  | # rails_command 'db:setup' if drop_db | 
    
    |  |  | # rails_command 'db:migrate' | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 4. routes.rb | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def set_routes | 
    
    |  |  | api_temp = <<-EOS | 
    
    |  |  | namespace :api do | 
    
    |  |  | namespace :v1 do | 
    
    |  |  | match 'public', via: :get, to: 'root#public' | 
    
    |  |  | match '*path', via: :all, to: 'root#not_found' | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | route "root to: 'home#index'" | 
    
    |  |  | route api_temp | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 5. Files Ready | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def prepare_files | 
    
    |  |  | home_ctrl_temp = <<EOS | 
    
    |  |  | class HomeController < ApplicationController | 
    
    |  |  | def index | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | file 'app/controllers/home_controller.rb', home_ctrl_temp | 
    
    |  |  | 
 | 
    
    |  |  | api_app_temp = <<EOS | 
    
    |  |  | module Api | 
    
    |  |  | module V1 | 
    
    |  |  | class ApplicationController < ActionController::API | 
    
    |  |  | class ParameterValueNotAllowed < ActionController::ParameterMissing | 
    
    |  |  | attr_reader :values | 
    
    |  |  | def initialize(param, values) # :nodoc: | 
    
    |  |  | @param = param | 
    
    |  |  | @values = values | 
    
    |  |  | super("param: \#{param} value only allowed in: \#{values}") | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | class AccessDenied < StandardError; end | 
    
    |  |  | class PageNotFound < StandardError; end | 
    
    |  |  |  | 
    
    |  |  | rescue_from(ActionController::ParameterMissing) do |err| | 
    
    |  |  | render json: { error: 'ParameterInvalid', message: err }, status: 400 | 
    
    |  |  | end | 
    
    |  |  | rescue_from(ActiveRecord::RecordInvalid) do |err| | 
    
    |  |  | render json: { error: 'RecordInvalid', message: err }, status: 400 | 
    
    |  |  | end | 
    
    |  |  | rescue_from(AccessDenied) do |err| | 
    
    |  |  | render json: { error: 'AccessDenied', message: err }, status: 403 | 
    
    |  |  | end | 
    
    |  |  | rescue_from(ActiveRecord::RecordNotFound) do | 
    
    |  |  | render json: { error: 'ResourceNotFound' }, status: 404 | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | def requires!(name, opts = {}) | 
    
    |  |  | opts[:require] = true | 
    
    |  |  | optional!(name, opts) | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | def optional!(name, opts = {}) | 
    
    |  |  | if params[name].blank? && opts[:require] == true | 
    
    |  |  | raise ActionController::ParameterMissing.new(name) | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | if opts[:values] && params[name].present? | 
    
    |  |  | values = opts[:values].to_a | 
    
    |  |  | if !values.include?(params[name]) && !values.include?(params[name].to_i) | 
    
    |  |  | raise ParameterValueNotAllowed.new(name, opts[:values]) | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | if params[name].blank? && opts[:default].present? | 
    
    |  |  | params[name] = opts[:default] | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | def error!(data, status_code = 400) | 
    
    |  |  | render json: data, status: status_code | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | def error_404! | 
    
    |  |  | error!({ 'error' => 'Page not found' }, 404) | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | api_root_temp = <<EOS | 
    
    |  |  | module Api | 
    
    |  |  | module V1 | 
    
    |  |  | class RootController < Api::V1::ApplicationController | 
    
    |  |  | # Require access token for all actions | 
    
    |  |  | # before_action :doorkeeper_authorize! | 
    
    |  |  |  | 
    
    |  |  | def not_found | 
    
    |  |  | raise ActiveRecord::RecordNotFound | 
    
    |  |  | end | 
    
    |  |  |  | 
    
    |  |  | def public | 
    
    |  |  | { message: I18n.t('v1.root.public.success') } | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | file 'app/controllers/api/v1/application_controller.rb', api_app_temp | 
    
    |  |  | file 'app/controllers/api/v1/root_controller.rb', api_root_temp | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 6. I18n | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def setup_i18n | 
    
    |  |  | run 'rm config/locales/en.yml' | 
    
    |  |  | rails_command 'g devise:i18n:views' | 
    
    |  |  | 
 | 
    
    |  |  | i18n_api_en_temp = <<EOS | 
    
    |  |  | en: | 
    
    |  |  | v1: | 
    
    |  |  | root: | 
    
    |  |  | public: | 
    
    |  |  | success: 'You're getting public API successfully.' | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | i18n_api_zhcn_temp = <<EOS | 
    
    |  |  | zh-CN: | 
    
    |  |  | v1: | 
    
    |  |  | root: | 
    
    |  |  | public: | 
    
    |  |  | success: 'API 已可访问' | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | file 'config/locales/api.en.yml', i18n_api_en_temp | 
    
    |  |  | file 'config/locales/api.zh-CN.yml', i18n_api_zhcn_temp | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 7. cable.yml | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def setup_cable | 
    
    |  |  | cable_temp = <<-EOS | 
    
    |  |  | production: &defaults | 
    
    |  |  | adapter: redis | 
    
    |  |  | url: redis://localhost:6379/1 | 
    
    |  |  | timeout: 1 | 
    
    |  |  |  | 
    
    |  |  | development: | 
    
    |  |  | <<: *defaults | 
    
    |  |  | url: redis://localhost:6379/2 | 
    
    |  |  |  | 
    
    |  |  | test: | 
    
    |  |  | <<: *defaults | 
    
    |  |  | url: redis://localhost:6379/3 | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | run 'rm config/cable.yml' | 
    
    |  |  | file 'config/cable.yml', cable_temp | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 8. Vendor Configs | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def setup_vendor | 
    
    |  |  | # lograge | 
    
    |  |  | lograge_temp = <<-EOS | 
    
    |  |  | <%= app_name.gsub('-', '_').camelize %>::Application.configure do | 
    
    |  |  | config.lograge.enabled = true | 
    
    |  |  | end | 
    
    |  |  | EOS | 
    
    |  |  | initializer 'lograge.rb', render_file(lograge_temp, app_name: app_name) | 
    
    |  |  | 
 | 
    
    |  |  | # Devise | 
    
    |  |  | rails_command 'g devise:install' | 
    
    |  |  | environment "config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }", env: 'development' | 
    
    |  |  | rails_command 'g devise User' | 
    
    |  |  | rails_command 'db:migrate' | 
    
    |  |  | 
 | 
    
    |  |  | # Doorkeeper | 
    
    |  |  | rails_command 'g doorkeeper:install' | 
    
    |  |  | rails_command 'g doorkeeper:migration' | 
    
    |  |  | rails_command 'db:migrate' | 
    
    |  |  | end | 
    
    |  |  | 
 | 
    
    |  |  | # ==================== | 
    
    |  |  | # 8. Git Config | 
    
    |  |  | # ==================== | 
    
    |  |  | 
 | 
    
    |  |  | def setup_git | 
    
    |  |  | file '.gitignore', <<-EOS | 
    
    |  |  | .bundle | 
    
    |  |  | tmp/ | 
    
    |  |  | db/*.sqlite3 | 
    
    |  |  | log/ | 
    
    |  |  | .sass-cache/ | 
    
    |  |  | config/*.yml | 
    
    |  |  | .DS_Store | 
    
    |  |  | *.swp | 
    
    |  |  | *.swo | 
    
    |  |  | .rvmrc | 
    
    |  |  | .idea | 
    
    |  |  | EOS | 
    
    |  |  | 
 | 
    
    |  |  | git :init | 
    
    |  |  | git add: '.' | 
    
    |  |  | git commit: "-a -m 'Initial commit'" | 
    
    |  |  | end |