├── README.md ├── minimal.rb ├── devise.rb ├── minimal_rspec_factory_bot.rb └── devise_rspec_factory_bot.rb /README.md: -------------------------------------------------------------------------------- 1 | # Rails Tailwind template 2 | 3 | Quickly generate a rails app with Tailwind css library and the gem devise. 4 | Thanks to Le Wagon : https://github.com/lewagon/rails-templates (same template with bootstrap ) 5 | 6 | # Get started 7 | 8 | ## Issue with Minimal template - it will be settled quickly 9 | ## Minimal 10 | Get a minimal rails app ready to be deployed on Heroku with Tailwind, Simple form and debugging gems. 11 | 12 | ```sh 13 | $ rails new \ 14 | --database postgresql \ 15 | --webpack \ 16 | -m https://raw.githubusercontent.com/lioruby/rails-tailwind-template/master/minimal.rb \ 17 | CHANGE_THIS_TO_YOUR_RAILS_APP_NAME 18 | ``` 19 | 20 | ### Minimal with rspec, factory_bot and shoulda-matchers gems 21 | ```sh 22 | $ rails new \ 23 | --database postgresql \ 24 | --webpack \ 25 | -m https://raw.githubusercontent.com/lioruby/rails-tailwind-template/master/minimal_rspec_factory_bot.rb \ 26 | CHANGE_THIS_TO_YOUR_RAILS_APP_NAME 27 | ``` 28 | 29 | ## Devise 30 | Same as minimal plus a Devise install with a generated User model. 31 | 32 | ```sh 33 | $ rails new \ 34 | --database postgresql \ 35 | --webpack \ 36 | -m https://raw.githubusercontent.com/lioruby/rails-tailwind-template/master/devise.rb \ 37 | CHANGE_THIS_TO_YOUR_RAILS_APP_NAME 38 | ``` 39 | 40 | ### Devise with rspec, factory_bot and shoulda-matchers gems 41 | it generate a spec directly for the user model 42 | 43 | ```sh 44 | $ rails new \ 45 | --database postgresql \ 46 | --webpack \ 47 | -m https://raw.githubusercontent.com/lioruby/rails-tailwind-template/master/devise_rspec_factory_bot.rb \ 48 | CHANGE_THIS_TO_YOUR_RAILS_APP_NAME 49 | ``` 50 | -------------------------------------------------------------------------------- /minimal.rb: -------------------------------------------------------------------------------- 1 | run "if uname | grep -q 'Darwin'; then pgrep spring | xargs kill -9; fi" 2 | 3 | # GEMFILE 4 | ######################################## 5 | inject_into_file 'Gemfile', before: 'group :development, :test do' do 6 | <<~RUBY 7 | 8 | gem 'autoprefixer-rails' 9 | gem 'font-awesome-sass' 10 | gem 'simple_form' 11 | RUBY 12 | end 13 | 14 | inject_into_file 'Gemfile', after: 'group :development, :test do' do 15 | <<-RUBY 16 | 17 | gem 'pry-byebug' 18 | gem 'pry-rails' 19 | gem 'dotenv-rails' 20 | RUBY 21 | end 22 | 23 | # Procfile 24 | ######################################## 25 | file 'Procfile', <<~YAML 26 | web: bundle exec puma -C config/puma.rb 27 | YAML 28 | 29 | # Assets in javascript file 30 | ######################################## 31 | run 'mkdir app/javascript/stylesheets' 32 | run 'touch app/javascript/stylesheets/application.scss' 33 | 34 | # Dev environment 35 | ######################################## 36 | gsub_file('config/environments/development.rb', /config\.assets\.debug.*/, 'config.assets.debug = false') 37 | 38 | # Layout 39 | ######################################## 40 | if Rails.version < "6" 41 | scripts = <<~HTML 42 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', defer: true %> 43 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 44 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 45 | HTML 46 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>", scripts) 47 | else 48 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 49 | inject_into_file 'app/views/layouts/application.html.erb', before: "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>" do 50 | <<~HTML 51 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 52 | HTML 53 | end 54 | end 55 | 56 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 57 | style = <<~HTML 58 | 59 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 60 | HTML 61 | gsub_file('app/views/layouts/application.html.erb', "<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>", style) 62 | 63 | 64 | # Generators 65 | ######################################## 66 | generators = <<~RUBY 67 | config.generators do |generate| 68 | generate.assets false 69 | generate.helper false 70 | generate.test_framework :test_unit, fixture: false 71 | end 72 | RUBY 73 | 74 | environment generators 75 | 76 | ######################################## 77 | # AFTER BUNDLE 78 | ######################################## 79 | after_bundle do 80 | # Generators: db + simple form + pages controller 81 | ######################################## 82 | rails_command 'db:drop db:create db:migrate' 83 | generate('simple_form:install') 84 | generate(:controller, 'pages', 'home', '--skip-routes', '--no-test-framework') 85 | 86 | # Routes 87 | ######################################## 88 | route "root to: 'pages#home'" 89 | 90 | # Git ignore 91 | ######################################## 92 | append_file '.gitignore', <<~TXT 93 | # Ignore .env file containing credentials. 94 | .env* 95 | # Ignore Mac and Linux file system files 96 | *.swp 97 | .DS_Store 98 | TXT 99 | 100 | # Webpacker / Yarn 101 | ######################################## 102 | run 'yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9' 103 | append_file 'app/javascript/packs/application.js', <<~JS 104 | // ---------------------------------------------------- 105 | // WRITE YOUR OWN JS STARTING FROM HERE 👇 106 | // ---------------------------------------------------- 107 | // External imports 108 | 109 | // Internal imports, e.g: 110 | import '../stylesheets/application.scss'; 111 | 112 | 113 | document.addEventListener('turbolinks:load', () => { 114 | // Call your functions here, e.g: 115 | }); 116 | JS 117 | 118 | # Postcss.config.js 119 | ######################################## 120 | 121 | gsub_file('./postcss.config.js', /.+/, '') 122 | 123 | inject_into_file './postcss.config.js' do 124 | <<~JS 125 | module.exports = { 126 | plugins: [ 127 | require('postcss-import'), 128 | require('postcss-flexbugs-fixes'), 129 | require('postcss-preset-env')({ 130 | autoprefixer: { 131 | flexbox: 'no-2009' 132 | }, 133 | stage: 3 134 | }), 135 | require('tailwindcss'), 136 | require('autoprefixer'), 137 | ] 138 | }; 139 | JS 140 | end 141 | 142 | # Create Tailwind.config.js file 143 | 144 | run 'touch tailwind.config.js' 145 | 146 | inject_into_file './tailwind.config.js' do 147 | <<~JS 148 | module.exports = { 149 | purge: [], 150 | darkMode: false, // or 'media' or 'class' 151 | theme: { 152 | extend: {}, 153 | }, 154 | variants: { 155 | extend: {}, 156 | }, 157 | plugins: [], 158 | }; 159 | JS 160 | 161 | end 162 | 163 | # Include Tailwind in app 164 | 165 | inject_into_file 'app/javascript/stylesheets/application.scss' do 166 | <<~SCSS 167 | @import "tailwindcss/base"; 168 | @import "tailwindcss/components"; 169 | @import "tailwindcss/utilities"; 170 | SCSS 171 | end 172 | 173 | # Include FontAwesome in app 174 | run 'mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss' 175 | inject_into_file 'app/assets/stylesheets/application.scss' do 176 | <<~SCSS 177 | @import "font-awesome-sprockets"; 178 | @import "font-awesome"; 179 | SCSS 180 | end 181 | 182 | # Dotenv 183 | ######################################## 184 | run 'touch .env' 185 | 186 | # Rubocop 187 | ######################################## 188 | run 'curl -L https://raw.githubusercontent.com/lewagon/rails-templates/master/.rubocop.yml > .rubocop.yml' 189 | 190 | # Git 191 | ######################################## 192 | git add: '.' 193 | git commit: "-m 'Initial commit'" 194 | 195 | # Fix puma config 196 | gsub_file('config/puma.rb', 'pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }', '# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }') 197 | end 198 | -------------------------------------------------------------------------------- /devise.rb: -------------------------------------------------------------------------------- 1 | run "if uname | grep -q 'Darwin'; then pgrep spring | xargs kill -9; fi" 2 | 3 | # GEMFILE 4 | ######################################## 5 | inject_into_file 'Gemfile', before: 'group :development, :test do' do 6 | <<~RUBY 7 | 8 | gem 'devise' 9 | gem 'autoprefixer-rails' 10 | gem 'font-awesome-sass' 11 | gem 'simple_form' 12 | RUBY 13 | end 14 | 15 | inject_into_file 'Gemfile', after: 'group :development, :test do' do 16 | <<-RUBY 17 | 18 | gem 'pry-byebug' 19 | gem 'pry-rails' 20 | gem 'dotenv-rails' 21 | RUBY 22 | end 23 | 24 | # Procfile 25 | ######################################## 26 | file 'Procfile', <<~YAML 27 | web: bundle exec puma -C config/puma.rb 28 | YAML 29 | 30 | # Assets in javascript file 31 | ######################################## 32 | run 'mkdir app/javascript/stylesheets' 33 | run 'touch app/javascript/stylesheets/application.scss' 34 | 35 | # Dev environment 36 | ######################################## 37 | gsub_file('config/environments/development.rb', /config\.assets\.debug.*/, 'config.assets.debug = false') 38 | 39 | # Layout 40 | ######################################## 41 | if Rails.version < "6" 42 | scripts = <<~HTML 43 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', defer: true %> 44 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 45 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 46 | HTML 47 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>", scripts) 48 | else 49 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 50 | inject_into_file 'app/views/layouts/application.html.erb', before: "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>" do 51 | <<~HTML 52 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 53 | HTML 54 | end 55 | end 56 | 57 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 58 | style = <<~HTML 59 | 60 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 61 | HTML 62 | gsub_file('app/views/layouts/application.html.erb', "<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>", style) 63 | 64 | 65 | # Generators 66 | ######################################## 67 | generators = <<~RUBY 68 | config.generators do |generate| 69 | generate.assets false 70 | generate.helper false 71 | generate.test_framework :test_unit, fixture: false 72 | end 73 | RUBY 74 | 75 | environment generators 76 | 77 | # Insert Devise flashes 78 | file 'app/views/shared/_flashes.html.erb', <<~HTML 79 | <% if notice %> 80 | 86 | <% end %> 87 | <% if alert %> 88 | 94 | <% end %> 95 | HTML 96 | 97 | inject_into_file 'app/views/layouts/application.html.erb', after: "<%= yield %>" do 98 | <<-HTML 99 | <%= render 'shared/flashes' %> 100 | HTML 101 | end 102 | 103 | ######################################## 104 | # AFTER BUNDLE 105 | ######################################## 106 | after_bundle do 107 | # Generators: db + simple form + pages controller 108 | ######################################## 109 | rails_command 'db:drop db:create db:migrate' 110 | generate('simple_form:install') 111 | generate(:controller, 'pages', 'home', '--skip-routes', '--no-test-framework') 112 | 113 | # Routes 114 | ######################################## 115 | route "root to: 'pages#home'" 116 | 117 | # Git ignore 118 | ######################################## 119 | append_file '.gitignore', <<~TXT 120 | # Ignore .env file containing credentials. 121 | .env* 122 | # Ignore Mac and Linux file system files 123 | *.swp 124 | .DS_Store 125 | TXT 126 | 127 | # Devise install + user 128 | ######################################## 129 | generate('devise:install') 130 | generate('devise', 'User') 131 | # App controller 132 | ######################################## 133 | run 'rm app/controllers/application_controller.rb' 134 | file 'app/controllers/application_controller.rb', <<~RUBY 135 | class ApplicationController < ActionController::Base 136 | #{ "protect_from_forgery with: :exception\n" if Rails.version < "5.2"} before_action :authenticate_user! 137 | end 138 | RUBY 139 | 140 | # migrate + devise views 141 | ######################################## 142 | rails_command 'db:migrate' 143 | generate('devise:views') 144 | 145 | # Pages Controller 146 | ######################################## 147 | run 'rm app/controllers/pages_controller.rb' 148 | file 'app/controllers/pages_controller.rb', <<~RUBY 149 | class PagesController < ApplicationController 150 | skip_before_action :authenticate_user!, only: [ :home ] 151 | def home 152 | end 153 | end 154 | RUBY 155 | 156 | # Environments 157 | ######################################## 158 | environment 'config.action_mailer.default_url_options = { host: "http://localhost:3000" }', env: 'development' 159 | environment 'config.action_mailer.default_url_options = { host: "http://TODO_PUT_YOUR_DOMAIN_HERE" }', env: 'production' 160 | 161 | # Webpacker / Yarn 162 | ######################################## 163 | run 'yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9' 164 | append_file 'app/javascript/packs/application.js', <<~JS 165 | // ---------------------------------------------------- 166 | // WRITE YOUR OWN JS STARTING FROM HERE 👇 167 | // ---------------------------------------------------- 168 | // External imports 169 | 170 | // Internal imports, e.g: 171 | import '../stylesheets/application.scss'; 172 | 173 | 174 | document.addEventListener('turbolinks:load', () => { 175 | // Call your functions here, e.g: 176 | }); 177 | JS 178 | 179 | # Postcss.config.js 180 | ######################################## 181 | 182 | gsub_file('./postcss.config.js', /.+/, '') 183 | 184 | inject_into_file './postcss.config.js' do 185 | <<~JS 186 | module.exports = { 187 | plugins: [ 188 | require('postcss-import'), 189 | require('postcss-flexbugs-fixes'), 190 | require('postcss-preset-env')({ 191 | autoprefixer: { 192 | flexbox: 'no-2009' 193 | }, 194 | stage: 3 195 | }), 196 | require('tailwindcss'), 197 | require('autoprefixer'), 198 | ] 199 | }; 200 | JS 201 | end 202 | 203 | # Create Tailwind.config.js file 204 | 205 | run 'touch tailwind.config.js' 206 | 207 | inject_into_file './tailwind.config.js' do 208 | <<~JS 209 | module.exports = { 210 | purge: [], 211 | darkMode: false, // or 'media' or 'class' 212 | theme: { 213 | extend: {}, 214 | }, 215 | variants: { 216 | extend: {}, 217 | }, 218 | plugins: [], 219 | }; 220 | JS 221 | end 222 | 223 | # Include Tailwind in app 224 | 225 | inject_into_file 'app/javascript/stylesheets/application.scss' do 226 | <<~SCSS 227 | @import "tailwindcss/base"; 228 | @import "tailwindcss/components"; 229 | @import "tailwindcss/utilities"; 230 | 231 | .alert { 232 | position: fixed; 233 | bottom: 8px; 234 | right: 8px; 235 | z-index: 1000; 236 | background-color: #F7F4EA; 237 | padding: 4px; 238 | font-size: 10px; 239 | border-radius: 2px; 240 | } 241 | SCSS 242 | end 243 | 244 | # Include FontAwesome in app 245 | run 'mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss' 246 | inject_into_file 'app/assets/stylesheets/application.scss' do 247 | <<~SCSS 248 | @import "font-awesome-sprockets"; 249 | @import "font-awesome"; 250 | SCSS 251 | end 252 | 253 | # Dotenv 254 | ######################################## 255 | run 'touch .env' 256 | 257 | # Rubocop 258 | ######################################## 259 | run 'curl -L https://raw.githubusercontent.com/lewagon/rails-templates/master/.rubocop.yml > .rubocop.yml' 260 | 261 | # Git 262 | ######################################## 263 | git add: '.' 264 | git commit: "-m 'Initial commit'" 265 | 266 | # Fix puma config 267 | gsub_file('config/puma.rb', 'pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }', '# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }') 268 | end 269 | -------------------------------------------------------------------------------- /minimal_rspec_factory_bot.rb: -------------------------------------------------------------------------------- 1 | run "if uname | grep -q 'Darwin'; then pgrep spring | xargs kill -9; fi" 2 | 3 | # GEMFILE 4 | ######################################## 5 | inject_into_file 'Gemfile', before: 'group :development, :test do' do 6 | <<~RUBY 7 | 8 | gem 'autoprefixer-rails' 9 | gem 'font-awesome-sass' 10 | gem 'simple_form' 11 | RUBY 12 | end 13 | 14 | inject_into_file 'Gemfile', after: 'group :development, :test do' do 15 | <<-RUBY 16 | 17 | gem 'pry-byebug' 18 | gem 'pry-rails' 19 | gem 'dotenv-rails' 20 | gem 'rspec-rails', '~> 4.0.1' 21 | gem 'factory_bot_rails', '~> 6.1' 22 | gem 'shoulda-matchers', '~> 4.0' 23 | RUBY 24 | end 25 | 26 | # Procfile 27 | ######################################## 28 | file 'Procfile', <<~YAML 29 | web: bundle exec puma -C config/puma.rb 30 | YAML 31 | 32 | # Assets in javascript file 33 | ######################################## 34 | run 'mkdir app/javascript/stylesheets' 35 | run 'touch app/javascript/stylesheets/application.scss' 36 | 37 | # Dev environment 38 | ######################################## 39 | gsub_file('config/environments/development.rb', /config\.assets\.debug.*/, 'config.assets.debug = false') 40 | 41 | # Layout 42 | ######################################## 43 | if Rails.version < "6" 44 | scripts = <<~HTML 45 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', defer: true %> 46 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 47 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 48 | HTML 49 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>", scripts) 50 | else 51 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 52 | inject_into_file 'app/views/layouts/application.html.erb', before: "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>" do 53 | <<~HTML 54 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 55 | HTML 56 | end 57 | end 58 | 59 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 60 | style = <<~HTML 61 | 62 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 63 | HTML 64 | gsub_file('app/views/layouts/application.html.erb', "<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>", style) 65 | 66 | 67 | # Generators 68 | ######################################## 69 | generators = <<~RUBY 70 | config.generators do |generate| 71 | generate.assets false 72 | generate.helper false 73 | generate.test_framework :test_unit, fixture: false 74 | end 75 | RUBY 76 | 77 | environment generators 78 | 79 | ######################################## 80 | # AFTER BUNDLE 81 | ######################################## 82 | after_bundle do 83 | # Generators: db + simple form + pages controller 84 | ######################################## 85 | rails_command 'db:drop db:create db:migrate' 86 | generate('simple_form:install') 87 | generate(:controller, 'pages', 'home', '--skip-routes', '--no-test-framework') 88 | 89 | 90 | # Generators: rspec 91 | ###################################### 92 | generate('rspec:install') 93 | 94 | # FACTORY BOT GEM 95 | # factory_bot.rb 96 | ##################################### 97 | run 'mkdir ./spec/support' 98 | run 'touch ./spec/support/factory_bot.rb' 99 | insert_into_file './spec/support/factory_bot.rb' do 100 | <<~RUBY 101 | require 'factory_bot' 102 | 103 | RSpec.configure do |config| 104 | config.include FactoryBot::Syntax::Methods 105 | end 106 | RUBY 107 | end 108 | 109 | # rails_helper.rb 110 | gsub_file('./spec/rails_helper.rb', /.+/, '') 111 | 112 | insert_into_file './spec/rails_helper.rb' do 113 | <<~RUBY 114 | require 'rails' 115 | # This file is copied to spec/ when you run 'rails generate rspec:install' 116 | require 'spec_helper' 117 | ENV['RAILS_ENV'] ||= 'test' 118 | require File.expand_path('../config/environment', __dir__) 119 | # Prevent database truncation if the environment is production 120 | abort("The Rails environment is running in production mode!") if Rails.env.production? 121 | require 'rspec/rails' 122 | require 'support/factory_bot' 123 | 124 | Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |file| require file } 125 | 126 | begin 127 | ActiveRecord::Migration.maintain_test_schema! 128 | rescue ActiveRecord::PendingMigrationError => e 129 | puts e.to_s.strip 130 | exit 1 131 | end 132 | RSpec.configure do |config| 133 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 134 | # config.fixture_path = "#{::Rails.root}/spec/fixtures" 135 | 136 | config.use_transactional_fixtures = true 137 | 138 | config.infer_spec_type_from_file_location! 139 | 140 | # Filter lines from Rails gems in backtraces. 141 | config.filter_rails_from_backtrace! 142 | # arbitrary gems may also be filtered via: 143 | # config.filter_gems_from_backtrace("gem name") 144 | end 145 | 146 | Shoulda::Matchers.configure do |config| 147 | config.integrate do |with| 148 | with.test_framework :rspec 149 | with.library :rails 150 | end 151 | end 152 | 153 | RUBY 154 | end 155 | 156 | # Delete factories folder in './test/factories' 157 | run 'rm -rf ./test/factories' 158 | 159 | 160 | # Routes 161 | ######################################## 162 | route "root to: 'pages#home'" 163 | 164 | # Git ignore 165 | ######################################## 166 | append_file '.gitignore', <<~TXT 167 | # Ignore .env file containing credentials. 168 | .env* 169 | # Ignore Mac and Linux file system files 170 | *.swp 171 | .DS_Store 172 | TXT 173 | 174 | # Webpacker / Yarn 175 | ######################################## 176 | run 'yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9' 177 | append_file 'app/javascript/packs/application.js', <<~JS 178 | // ---------------------------------------------------- 179 | // WRITE YOUR OWN JS STARTING FROM HERE 👇 180 | // ---------------------------------------------------- 181 | // External imports 182 | 183 | // Internal imports, e.g: 184 | import '../stylesheets/application.scss'; 185 | 186 | 187 | document.addEventListener('turbolinks:load', () => { 188 | // Call your functions here, e.g: 189 | }); 190 | JS 191 | 192 | # Postcss.config.js 193 | ######################################## 194 | 195 | gsub_file('./postcss.config.js', /.+/, '') 196 | 197 | inject_into_file './postcss.config.js' do 198 | <<~JS 199 | module.exports = { 200 | plugins: [ 201 | require('postcss-import'), 202 | require('postcss-flexbugs-fixes'), 203 | require('postcss-preset-env')({ 204 | autoprefixer: { 205 | flexbox: 'no-2009' 206 | }, 207 | stage: 3 208 | }), 209 | require('tailwindcss'), 210 | require('autoprefixer'), 211 | ] 212 | }; 213 | JS 214 | end 215 | 216 | # Create Tailwind.config.js file 217 | 218 | run 'touch tailwind.config.js' 219 | 220 | inject_into_file './tailwind.config.js' do 221 | <<~JS 222 | module.exports = { 223 | purge: [], 224 | darkMode: false, // or 'media' or 'class' 225 | theme: { 226 | extend: {}, 227 | }, 228 | variants: { 229 | extend: {}, 230 | }, 231 | plugins: [], 232 | }; 233 | JS 234 | 235 | end 236 | 237 | # Include Tailwind in app 238 | 239 | inject_into_file 'app/javascript/stylesheets/application.scss' do 240 | <<~SCSS 241 | @import "tailwindcss/base"; 242 | @import "tailwindcss/components"; 243 | @import "tailwindcss/utilities"; 244 | SCSS 245 | end 246 | 247 | # Include FontAwesome in app 248 | run 'mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss' 249 | inject_into_file 'app/assets/stylesheets/application.scss' do 250 | <<~SCSS 251 | @import "font-awesome-sprockets"; 252 | @import "font-awesome"; 253 | SCSS 254 | end 255 | 256 | # Dotenv 257 | ######################################## 258 | run 'touch .env' 259 | 260 | # Rubocop 261 | ######################################## 262 | run 'curl -L https://raw.githubusercontent.com/lewagon/rails-templates/master/.rubocop.yml > .rubocop.yml' 263 | 264 | # Git 265 | ######################################## 266 | git add: '.' 267 | git commit: "-m 'Initial commit'" 268 | 269 | # Fix puma config 270 | gsub_file('config/puma.rb', 'pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }', '# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }') 271 | end 272 | -------------------------------------------------------------------------------- /devise_rspec_factory_bot.rb: -------------------------------------------------------------------------------- 1 | run "if uname | grep -q 'Darwin'; then pgrep spring | xargs kill -9; fi" 2 | 3 | # GEMFILE 4 | ######################################## 5 | inject_into_file 'Gemfile', before: 'group :development, :test do' do 6 | <<~RUBY 7 | 8 | gem 'devise' 9 | gem 'autoprefixer-rails' 10 | gem 'font-awesome-sass' 11 | gem 'simple_form' 12 | RUBY 13 | end 14 | 15 | inject_into_file 'Gemfile', after: 'group :development, :test do' do 16 | <<-RUBY 17 | 18 | gem 'pry-byebug' 19 | gem 'pry-rails' 20 | gem 'dotenv-rails' 21 | gem 'rspec-rails', '~> 4.0.1' 22 | gem 'factory_bot_rails', '~> 6.1' 23 | gem 'shoulda-matchers', '~> 4.0' 24 | RUBY 25 | end 26 | 27 | # Procfile 28 | ######################################## 29 | file 'Procfile', <<~YAML 30 | web: bundle exec puma -C config/puma.rb 31 | YAML 32 | 33 | # Assets in javascript file 34 | ######################################## 35 | run 'mkdir app/javascript/stylesheets' 36 | run 'touch app/javascript/stylesheets/application.scss' 37 | 38 | # Dev environment 39 | ######################################## 40 | gsub_file('config/environments/development.rb', /config\.assets\.debug.*/, 'config.assets.debug = false') 41 | 42 | # Layout 43 | ######################################## 44 | if Rails.version < "6" 45 | scripts = <<~HTML 46 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', defer: true %> 47 | <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 48 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 49 | HTML 50 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>", scripts) 51 | else 52 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 53 | inject_into_file 'app/views/layouts/application.html.erb', before: "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>" do 54 | <<~HTML 55 | <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 56 | HTML 57 | end 58 | end 59 | 60 | gsub_file('app/views/layouts/application.html.erb', "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>", "<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>") 61 | style = <<~HTML 62 | 63 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 64 | HTML 65 | gsub_file('app/views/layouts/application.html.erb', "<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>", style) 66 | 67 | 68 | # Generators 69 | ######################################## 70 | generators = <<~RUBY 71 | config.generators do |generate| 72 | generate.assets false 73 | generate.helper false 74 | generate.test_framework :test_unit, fixture: false 75 | end 76 | RUBY 77 | 78 | environment generators 79 | 80 | # Insert Devise flashes 81 | file 'app/views/shared/_flashes.html.erb', <<~HTML 82 | <% if notice %> 83 | 89 | <% end %> 90 | <% if alert %> 91 | 97 | <% end %> 98 | HTML 99 | 100 | inject_into_file 'app/views/layouts/application.html.erb', after: "<%= yield %>" do 101 | <<-HTML 102 | <%= render 'shared/flashes' %> 103 | HTML 104 | end 105 | 106 | ######################################## 107 | # AFTER BUNDLE 108 | ######################################## 109 | after_bundle do 110 | # Generators: db + simple form + pages controller 111 | ######################################## 112 | rails_command 'db:drop db:create db:migrate' 113 | generate('simple_form:install') 114 | generate(:controller, 'pages', 'home', '--skip-routes', '--no-test-framework') 115 | 116 | # Routes 117 | ######################################## 118 | route "root to: 'pages#home'" 119 | 120 | # Git ignore 121 | ######################################## 122 | append_file '.gitignore', <<~TXT 123 | # Ignore .env file containing credentials. 124 | .env* 125 | # Ignore Mac and Linux file system files 126 | *.swp 127 | .DS_Store 128 | TXT 129 | 130 | # Devise install + user 131 | ######################################## 132 | generate('devise:install') 133 | generate('devise', 'User') 134 | 135 | # Generators: rspec + rspec User model 136 | ###################################### 137 | generate('rspec:install') 138 | generate('rspec:model user') 139 | 140 | # FACTORY BOT GEM 141 | # factory_bot.rb 142 | ##################################### 143 | run 'mkdir ./spec/support' 144 | run 'touch ./spec/support/factory_bot.rb' 145 | insert_into_file './spec/support/factory_bot.rb' do 146 | <<~RUBY 147 | require 'factory_bot' 148 | 149 | RSpec.configure do |config| 150 | config.include FactoryBot::Syntax::Methods 151 | end 152 | RUBY 153 | end 154 | 155 | 156 | # rails_helper.rb 157 | gsub_file('./spec/rails_helper.rb', /.+/, '') 158 | 159 | insert_into_file './spec/rails_helper.rb' do 160 | <<~RUBY 161 | # This file is copied to spec/ when you run 'rails generate rspec:install' 162 | require 'spec_helper' 163 | ENV['RAILS_ENV'] ||= 'test' 164 | require File.expand_path('../config/environment', __dir__) 165 | # Prevent database truncation if the environment is production 166 | abort("The Rails environment is running in production mode!") if Rails.env.production? 167 | require 'rspec/rails' 168 | require 'support/factory_bot' 169 | 170 | Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |file| require file } 171 | 172 | begin 173 | ActiveRecord::Migration.maintain_test_schema! 174 | rescue ActiveRecord::PendingMigrationError => e 175 | puts e.to_s.strip 176 | exit 1 177 | end 178 | RSpec.configure do |config| 179 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 180 | config.include Warden::Test::Helpers 181 | 182 | config.use_transactional_fixtures = true 183 | 184 | config.infer_spec_type_from_file_location! 185 | 186 | # Filter lines from Rails gems in backtraces. 187 | config.filter_rails_from_backtrace! 188 | # arbitrary gems may also be filtered via: 189 | # config.filter_gems_from_backtrace("gem name") 190 | end 191 | 192 | Shoulda::Matchers.configure do |config| 193 | config.integrate do |with| 194 | with.test_framework :rspec 195 | with.library :rails 196 | end 197 | end 198 | 199 | RUBY 200 | end 201 | 202 | 203 | # Create factory user.rb 204 | run 'touch spec/support/user.rb' 205 | 206 | insert_into_file './spec/support/user.rb' do 207 | <<~RUBY 208 | FactoryBot.define do 209 | factory :user, class: 'User' do 210 | # Insert your user here 211 | end 212 | end 213 | RUBY 214 | end 215 | 216 | # Delete factories folder in './test/factories' 217 | run 'rm -rf ./test/factories' 218 | 219 | # App controller 220 | ######################################## 221 | run 'rm app/controllers/application_controller.rb' 222 | file 'app/controllers/application_controller.rb', <<~RUBY 223 | class ApplicationController < ActionController::Base 224 | #{ "protect_from_forgery with: :exception\n" if Rails.version < "5.2"} before_action :authenticate_user! 225 | end 226 | RUBY 227 | 228 | # migrate + devise views 229 | ######################################## 230 | rails_command 'db:migrate' 231 | generate('devise:views') 232 | 233 | # Pages Controller 234 | ######################################## 235 | run 'rm app/controllers/pages_controller.rb' 236 | file 'app/controllers/pages_controller.rb', <<~RUBY 237 | class PagesController < ApplicationController 238 | skip_before_action :authenticate_user!, only: [ :home ] 239 | def home 240 | end 241 | end 242 | RUBY 243 | 244 | # Environments 245 | ######################################## 246 | environment 'config.action_mailer.default_url_options = { host: "http://localhost:3000" }', env: 'development' 247 | environment 'config.action_mailer.default_url_options = { host: "http://TODO_PUT_YOUR_DOMAIN_HERE" }', env: 'production' 248 | 249 | # Webpacker / Yarn 250 | ######################################## 251 | run 'yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9' 252 | append_file 'app/javascript/packs/application.js', <<~JS 253 | // ---------------------------------------------------- 254 | // WRITE YOUR OWN JS STARTING FROM HERE 👇 255 | // ---------------------------------------------------- 256 | // External imports 257 | 258 | // Internal imports, e.g: 259 | import '../stylesheets/application.scss'; 260 | 261 | 262 | document.addEventListener('turbolinks:load', () => { 263 | // Call your functions here, e.g: 264 | }); 265 | JS 266 | 267 | # Postcss.config.js 268 | ######################################## 269 | 270 | gsub_file('./postcss.config.js', /.+/, '') 271 | 272 | inject_into_file './postcss.config.js' do 273 | <<~JS 274 | module.exports = { 275 | plugins: [ 276 | require('postcss-import'), 277 | require('postcss-flexbugs-fixes'), 278 | require('postcss-preset-env')({ 279 | autoprefixer: { 280 | flexbox: 'no-2009' 281 | }, 282 | stage: 3 283 | }), 284 | require('tailwindcss'), 285 | require('autoprefixer'), 286 | ] 287 | }; 288 | JS 289 | end 290 | 291 | # Create Tailwind.config.js file 292 | 293 | run 'touch tailwind.config.js' 294 | 295 | inject_into_file './tailwind.config.js' do 296 | <<~JS 297 | module.exports = { 298 | purge: [], 299 | darkMode: false, // or 'media' or 'class' 300 | theme: { 301 | extend: {}, 302 | }, 303 | variants: { 304 | extend: {}, 305 | }, 306 | plugins: [], 307 | }; 308 | JS 309 | 310 | end 311 | 312 | # Include Tailwind in app 313 | 314 | inject_into_file 'app/javascript/stylesheets/application.scss' do 315 | <<~SCSS 316 | @import "tailwindcss/base"; 317 | @import "tailwindcss/components"; 318 | @import "tailwindcss/utilities"; 319 | 320 | .alert { 321 | position: fixed; 322 | bottom: 8px; 323 | right: 8px; 324 | z-index: 1000; 325 | background-color: #F7F4EA; 326 | padding: 4px; 327 | font-size: 10px; 328 | border-radius: 2px; 329 | } 330 | SCSS 331 | end 332 | 333 | # Include FontAwesome in app 334 | run 'mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss' 335 | inject_into_file 'app/assets/stylesheets/application.scss' do 336 | <<~SCSS 337 | @import "font-awesome-sprockets"; 338 | @import "font-awesome"; 339 | SCSS 340 | end 341 | 342 | # Dotenv 343 | ######################################## 344 | run 'touch .env' 345 | 346 | # Rubocop 347 | ######################################## 348 | run 'curl -L https://raw.githubusercontent.com/lewagon/rails-templates/master/.rubocop.yml > .rubocop.yml' 349 | 350 | # Git 351 | ######################################## 352 | git add: '.' 353 | git commit: "-m 'Initial commit'" 354 | 355 | # Fix puma config 356 | gsub_file('config/puma.rb', 'pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }', '# pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }') 357 | end 358 | --------------------------------------------------------------------------------