Choiceable All in one (maybe ?) Copy
RSpec + Spring, Guard RSpec & Livereload, ESLint, StandardRB + Spring, Lint-staged, Hotwire, Devise + Turbo Support (If use Hotwire), and Capistrano
Used 19 times
M
ML
Usage
Run this command in your Rails app directory in the terminal:
rails app:template LOCATION="https://railsbytes.com/script/VQLsmn"
Template Source
Review the code before running this template on your machine.
require "active_support/core_ext/hash/deep_merge"
require "json"
def add_gem_if_not_present(*args, **options)
gem(*args, **options) unless Gem.loaded_specs.has_key?(args[0])
end
def confirm(question)
response = ask("#{question} [Y/n]")
response == "" || response.upcase == "Y"
end
def has_webpacker_gem?
@has_webpacker_gem ||= begin
webpacker_checker_regex = /gem (['"])webpacker\1.+/
File.read("Gemfile")[webpacker_checker_regex]
end
end
def has_webpacker?
has_webpacker_gem? || USE_WEBPACKER6_BETA
end
def edit_file(path)
File.write(path, yield(File.read(path)))
end
def edit_package_json
return {} unless File.exist?("package.json")
edit_file("./package.json") do |content|
JSON.pretty_generate(yield JSON.parse(content))
end
end
def install_eslint
return unless USE_ESLINT_STANDARD
puts "Installing ESLint Standard..."
eslint_standard_packages = %w[
@babel/eslint-parser
eslint
eslint-config-standard
eslint-plugin-import
eslint-plugin-node
eslint-plugin-promise
]
run "yarn add -D #{eslint_standard_packages.join(" ")}"
edit_package_json do |json|
json.deep_merge!({
"scripts" => {
"lint:js" => "./node_modules/.bin/eslint --cache app/javascript"
}
})
end
file ".eslintrc.js", <<~JS
module.exports = {
parser: '@babel/eslint-parser',
env: {
browser: true,
es2021: true
},
extends: [
'standard'
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module'
},
rules: {}
}
JS
end
def install_devise
return unless USE_DEVISE
puts "Installing Devise..."
if USE_HOTWIRE
# template: https://railsbytes.com/templates/zr4sRp
# install Devise Authentication + Hotwire Support (With Navigational Formats)
run 'rails app:template LOCATION="https://railsbytes.com/script/zr4sRp"'
else
# template: https://railsbytes.com/templates/X8Bsjx
# install Authentication with Devise
run 'rails app:template LOCATION="https://railsbytes.com/script/X8Bsjx"'
end
end
def install_lint_staged
return unless USE_LINT_STAGED
puts "Installing lint-staged..."
run "npx mrm lint-staged"
edit_package_json do |json|
json.deep_merge!({
"lint-staged" => {
"*.js" => "eslint --cache --fix",
"{Guardfile,Gemfile,*.rb}" => "bin/standardrb --fix"
}
})
end
end
def install_standardrb
return unless USE_STANDARDRB
puts "Installing standardrb..."
edit_package_json do |json|
json.deep_merge!({
"scripts" => {"lint:rb" => "bin/standardrb"}
})
end
gem_group :development do
add_gem_if_not_present "standard"
add_gem_if_not_present "spring-commands-standard", require: false
end
Bundler.with_clean_env do
run "bundle install"
end
run "bundle exec spring binstub standardrb"
file ".standard.yml", <<~YAML
parallel: true # default: false
format: progress # default: Standard::Formatter
ignore:
- "**/db/schema.rb"
- "**/bin/*"
YAML
end
def install_rspec
puts "Installing rspec..."
run "bundle binstub rspec"
# fix rspec:install stuck by stop spring
# https://github.com/rspec/rspec-rails/issues/1860#issuecomment-346687123
run "spring stop"
generate("rspec:install")
# delete minitest directory
run "rm -rf test" if yes?("Delete /test folder ? [y/n]")
# make spec/support directory loaded
gsub_file "spec/rails_helper.rb", %r{^# (?=Dir\[Rails.root.join\()}, ""
# uncomment default rspec config in spec_helper.rb
run 'rails app:template LOCATION="https://railsbytes.com/script/XnJspa"'
# generate rspec supports
file "spec/support/factory_bot.rb", <<~RUBY
RSpec.configure do |config|
config.before { FactoryBot.rewind_sequences }
end
RUBY
edit_package_json do |json|
json.deep_merge!({
"scripts" => {
"test" => "bin/rspec",
"test:all" => "yarn run test -- --tag '~focus' --tag 'focus'",
"test:failures" => "yarn run test:all --only-failures"
}
})
end
application "config.generators.test_framework :rspec, routing_spec: false"
run "bundle exec spring binstub rspec"
end
def install_capistrano
return unless USE_CAPISTRANO
puts "Installing Capistrano..."
gem_group :deploy do
add_gem_if_not_present "capistrano", "~> 3.16", require: false
add_gem_if_not_present "capistrano-rbenv", "~> 2.2", require: false
add_gem_if_not_present "capistrano-rails", "~> 1.6", require: false
end
Bundler.with_clean_env do
run "bundle install"
end
run "bundle exec cap install"
edit_file("./Capfile") do |content|
content.sub!(%r{# (?=require "capistrano/rbenv")}, "")
content.sub!(%r{# (?=require "capistrano/bundler")}, "")
content.sub!(%r{# (?=require "capistrano/rails/assets")}, "")
content.sub!(%r{# (?=require "capistrano/rails/migrations")}, "")
content
end
edit_file("./config/deploy.rb") do |content|
content.sub!(/# append :linked_dirs.+/, <<~RUBY)
append :linked_dirs,
"log",
"tmp/pids",
"tmp/cache",
"tmp/sockets",
"node_modules",
"bundle"
RUBY
content.sub!(/# append :linked_files.+/, <<~RUBY)
append :linked_files, ".env.production.local"
RUBY
content
end
append_file "config/deploy.rb", <<~RUBY
Rake::Task["deploy:assets:backup_manifest"].clear_actions
RUBY
end
def install_hotwire
return unless USE_HOTWIRE
puts "Installing Hotwire..."
# hotwire install require sprockets to be able to run
gsub_file "config/application.rb", %r{# (?=require "sprockets/railtie")}, ""
run "bundle add hotwire-rails"
run "bundle exec rails hotwire:install"
end
USE_ESLINT_STANDARD = confirm("Use ESLint standard style ?")
USE_STANDARDRB = confirm("Use Ruby standard style (https://github.com/testdouble/standard) ?")
USE_LINT_STAGED = confirm("Install lint-staged (https://github.com/okonet/lint-staged) ?")
USE_DEVISE = confirm("Install devise for authentication ?")
USE_CAPISTRANO = confirm("Install capistrano to automate deployment ?")
# webpacker 6 use webpack 5, which have better build performance
# https://medium.com/frontend-digest/whats-new-in-webpack-5-ef619bb74fae
# the one that makes it better is uses dart-sass instead of node-sass
# https://github.com/rails/webpacker/#sass
WEBPACKER_BETA_VERSION = "6.0.0.beta.7"
USE_WEBPACKER6_BETA = yes?("Use webpacker #{WEBPACKER_BETA_VERSION} ? [y/n]")
USE_HOTWIRE = has_webpacker? && confirm("Install hotwire ?")
gem_group :development, :test do
add_gem_if_not_present "factory_bot_rails"
add_gem_if_not_present "rspec-rails", "~> 4.0.1"
end
gem_group :development do
# run RSpec after file changed when using guard
add_gem_if_not_present "guard-rspec", require: false
# app views livereload
add_gem_if_not_present "guard-livereload", "~> 2.5.2", require: false
add_gem_if_not_present "rack-livereload"
add_gem_if_not_present "spring-commands-rspec", require: false
end
environment(
"config.middleware.insert_after ActionDispatch::Static, Rack::LiveReload",
env: "development"
)
add_gem_if_not_present "dotenv-rails"
Bundler.with_clean_env do
run "bundle install"
end
install_rspec
install_eslint
install_lint_staged
install_standardrb
install_devise
install_capistrano
if USE_WEBPACKER6_BETA
run "bundle remove webpacker" if has_webpacker_gem?
run %(bundle add webpacker -v "#{WEBPACKER_BETA_VERSION}")
run "bundle exec rails webpacker:install"
edit_file("./config/webpacker.yml") do |content|
content.sub!(%r{(?<=source_path: )app/javascript}, "app/packs")
content.sub!(/(?<=source_entry_path: )packs/, "entrypoints")
content
end
# CSS: https://github.com/rails/webpacker/#css
# SASS: https://github.com/rails/webpacker/#sass
css_support_packages = %w[
css-loader
mini-css-extract-plugin
css-minimizer-webpack-plugin
sass
sass-loader
]
run "yarn add #{css_support_packages.join(" ")}"
else
run "bundle exec rails webpacker:install"
end
install_hotwire
run "bundle exec guard init"
run "bundle binstub guard"
# generate home page
generate(:controller, "home", "index", "--skip-routes")
route %(root to: "home#index")
if USE_WEBPACKER6_BETA
puts <<~README
You are using webpacker #{WEBPACKER_BETA_VERSION}, please update javascript file in app/packs/entrypoints
README
end
Comments
Vinicius Rebouças Vieira
Thanks for the script, but for me it only worked when I removed the block
Bundler.with_clean_env
do
run "bundle install"
end
and I just left
run "bundle install"