Last active
April 16, 2019 14:56
-
-
Save DotHide/f7ee2c96c94eba718050c7d775fe1737 to your computer and use it in GitHub Desktop.
Rails 5 API Application Template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'erb' | |
require 'ostruct' | |
# ==================== | |
# 0. Helper | |
# ==================== | |
def render_file(text, variables) | |
struct = OpenStruct.new(variables) | |
rendered_file = ERB.new(text).result(struct.instance_eval { binding }) | |
end | |
# ==================== | |
# 1. Gem File | |
# ==================== | |
run 'rm Gemfile && touch Gemfile' | |
add_source 'https://rubygems.org/' | |
gem 'puma', '~> 3.0' | |
gem 'mysql2', '>= 0.3.18', '< 0.5' # Use mysql as the database for Active Record | |
gem 'rails', '~> 5.0.0' | |
gem 'lograge' | |
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' | |
gem 'capistrano', require: false | |
gem 'capistrano-bundler', require: false | |
gem 'capistrano-chruby', require: false | |
gem 'capistrano-rails', require: false | |
gem 'capistrano3-puma', require: false | |
gem 'capistrano-sidekiq', require: false | |
gem 'better_errors' | |
gem 'listen', '~> 3.0.5' | |
end | |
gem_group :test do | |
gem 'rspec' | |
gem 'factory_girl_rails' | |
gem 'database_cleaner' | |
end | |
gem_group :development, :test do | |
gem 'rubocop', require: false | |
gem 'rspec-rails' | |
gem 'pry-rails' | |
gem 'pry-byebug' | |
gem 'awesome_print' | |
gem 'faker' | |
gem 'binding_of_caller' | |
end | |
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 | |
# ==================== | |
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 | |
end | |
# ==================== | |
# 3. database.yml | |
# ==================== | |
def setup_database | |
database_temp = <<-EOS | |
default: &default | |
adapter: mysql2 | |
encoding: utf8 | |
pool: 5 | |
username: root | |
password: <%= mysql_passwd %> | |
host: localhost | |
development: | |
<<: *default | |
database: <%= app_name %>_development | |
test: | |
<<: *default | |
database: <%= app_name %>_test | |
EOS | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage