Skip to content

Instantly share code, notes, and snippets.

@DotHide
Last active April 16, 2019 14:56
Show Gist options
  • Save DotHide/f7ee2c96c94eba718050c7d775fe1737 to your computer and use it in GitHub Desktop.
Save DotHide/f7ee2c96c94eba718050c7d775fe1737 to your computer and use it in GitHub Desktop.
Rails 5 API Application Template
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
@DotHide
Copy link
Author

DotHide commented Aug 4, 2016

Usage

$ rails new <project_name> -m https://gist.github.com/DotHide/f7ee2c96c94eba718050c7d775fe1737/raw/eaa482192a187af5eb374099c35c8824cdc5412b/rails-api-template.rb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment