template.rb 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. require "fileutils"
  2. require "shellwords"
  3. # Copied from: https://github.com/mattbrictson/rails-template
  4. # Copied from: https://github.com/excid3/jumpstart
  5. def add_template_repository_to_source_path
  6. if __FILE__ =~ %r{\Ahttps?://}
  7. require "tmpdir"
  8. source_paths.unshift(tempdir = Dir.mktmpdir("jumpstart-"))
  9. at_exit { FileUtils.remove_entry(tempdir) }
  10. git clone: [
  11. "--quiet",
  12. "http://gogs.anxgang.com/Hiskio/jumpstart.git",
  13. tempdir
  14. ].map(&:shellescape).join(" ")
  15. if (branch = __FILE__[%r{jumpstart/(.+)/template.rb}, 1])
  16. Dir.chdir(tempdir) { git checkout: branch }
  17. end
  18. else
  19. source_paths.unshift(File.dirname(__FILE__))
  20. end
  21. end
  22. def rails_version
  23. @rails_version ||= Gem::Version.new(Rails::VERSION::STRING)
  24. end
  25. def rails_5?
  26. Gem::Requirement.new(">= 5.2.0", "< 6.0.0.beta1").satisfied_by? rails_version
  27. end
  28. def rails_6?
  29. Gem::Requirement.new(">= 6.0.0.beta1", "< 7").satisfied_by? rails_version
  30. end
  31. def add_gems
  32. gem 'administrate', github: "excid3/administrate", branch: 'jumpstart'
  33. gem 'bootstrap', '~> 4.3', '>= 4.3.1'
  34. gem 'devise', '~> 4.7', '>= 4.7.0'
  35. gem 'devise-bootstrapped', github: 'excid3/devise-bootstrapped', branch: 'bootstrap4'
  36. gem 'devise_masquerade', '~> 0.6.2'
  37. gem 'font-awesome-sass', '~> 5.6', '>= 5.6.1'
  38. gem 'friendly_id', '~> 5.2', '>= 5.2.5'
  39. gem 'gravatar_image_tag', github: 'mdeering/gravatar_image_tag'
  40. gem 'mini_magick', '~> 4.9', '>= 4.9.2'
  41. gem 'name_of_person', '~> 1.1'
  42. gem 'omniauth-facebook', '~> 5.0'
  43. gem 'omniauth-github', '~> 1.3'
  44. gem 'omniauth-twitter', '~> 1.4'
  45. gem 'sidekiq', '~> 5.2', '>= 5.2.5'
  46. gem 'sitemap_generator', '~> 6.0', '>= 6.0.1'
  47. gem 'whenever', require: false
  48. gem 'simple_form', '~> 4.1.0'
  49. gem "breadcrumbs_on_rails", '~> 3.0.1'
  50. gem_group :development do
  51. gem 'pry', '~> 0.12.2'
  52. gem 'bullet', '~> 6.0.0'
  53. end
  54. if rails_5?
  55. gsub_file "Gemfile", /gem 'sqlite3'/, "gem 'sqlite3', '~> 1.3.0'"
  56. gem 'webpacker', '~> 4.0.1'
  57. end
  58. end
  59. def set_application_name
  60. # Add Application Name to Config
  61. if rails_5?
  62. environment "config.application_name = Rails.application.class.parent_name"
  63. else
  64. environment "config.application_name = Rails.application.class.module_parent_name"
  65. end
  66. # Announce the user where he can change the application name in the future.
  67. puts "You can change application name inside: ./config/application.rb"
  68. end
  69. def add_users
  70. # Install Devise
  71. generate "devise:install"
  72. # Configure Devise
  73. environment "config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }",
  74. env: 'development'
  75. route "root to: 'home#index'"
  76. # Devise notices are installed via Bootstrap
  77. generate "devise:views:bootstrapped"
  78. # Create Devise User
  79. generate :devise, "User",
  80. "first_name",
  81. "last_name",
  82. "announcements_last_read_at:datetime",
  83. "admin:boolean"
  84. # Set admin default to false
  85. in_root do
  86. migration = Dir.glob("db/migrate/*").max_by{ |f| File.mtime(f) }
  87. gsub_file migration, /:admin/, ":admin, default: false"
  88. end
  89. if Gem::Requirement.new("> 5.2").satisfied_by? rails_version
  90. gsub_file "config/initializers/devise.rb",
  91. / # config.secret_key = .+/,
  92. " config.secret_key = Rails.application.credentials.secret_key_base"
  93. end
  94. # Add Devise masqueradable to users
  95. inject_into_file("app/models/user.rb", "omniauthable, :masqueradable, :", after: "devise :")
  96. end
  97. def add_webpack
  98. # Rails 6+ comes with webpacker by default, so we can skip this step
  99. return if rails_6?
  100. # Our application layout already includes the javascript_pack_tag,
  101. # so we don't need to inject it
  102. rails_command 'webpacker:install'
  103. end
  104. def add_javascript
  105. run "yarn add expose-loader jquery popper.js bootstrap data-confirm-modal local-time"
  106. if rails_5?
  107. run "yarn add turbolinks @rails/actioncable@pre @rails/actiontext@pre @rails/activestorage@pre @rails/ujs@pre"
  108. end
  109. content = <<-JS
  110. const webpack = require('webpack')
  111. environment.plugins.append('Provide', new webpack.ProvidePlugin({
  112. $: 'jquery',
  113. jQuery: 'jquery',
  114. Rails: '@rails/ujs'
  115. }))
  116. JS
  117. insert_into_file 'config/webpack/environment.js', content + "\n", before: "module.exports = environment"
  118. end
  119. def copy_templates
  120. remove_file "app/assets/stylesheets/application.css"
  121. copy_file "Procfile"
  122. copy_file "Procfile.dev"
  123. copy_file ".foreman"
  124. directory "app", force: true
  125. directory "config", force: true
  126. directory "lib", force: true
  127. route "get '/terms', to: 'home#terms'"
  128. route "get '/privacy', to: 'home#privacy'"
  129. end
  130. def add_sidekiq
  131. environment "config.active_job.queue_adapter = :sidekiq"
  132. insert_into_file "config/routes.rb",
  133. "require 'sidekiq/web'\n\n",
  134. before: "Rails.application.routes.draw do"
  135. content = <<-RUBY
  136. authenticate :user, lambda { |u| u.admin? } do
  137. mount Sidekiq::Web => '/sidekiq'
  138. end
  139. RUBY
  140. insert_into_file "config/routes.rb", "#{content}\n\n", after: "Rails.application.routes.draw do\n"
  141. end
  142. def add_announcements
  143. generate "model Announcement published_at:datetime announcement_type name description:text"
  144. route "resources :announcements, only: [:index]"
  145. end
  146. def add_notifications
  147. generate "model Notification recipient_id:bigint actor_id:bigint read_at:datetime action:string notifiable_id:bigint notifiable_type:string"
  148. route "resources :notifications, only: [:index]"
  149. end
  150. def add_administrate
  151. generate "administrate:install"
  152. gsub_file "app/dashboards/announcement_dashboard.rb",
  153. /announcement_type: Field::String/,
  154. "announcement_type: Field::Select.with_options(collection: Announcement::TYPES)"
  155. gsub_file "app/dashboards/user_dashboard.rb",
  156. /email: Field::String/,
  157. "email: Field::String,\n password: Field::String.with_options(searchable: false)"
  158. gsub_file "app/dashboards/user_dashboard.rb",
  159. /FORM_ATTRIBUTES = \[/,
  160. "FORM_ATTRIBUTES = [\n :password,"
  161. gsub_file "app/controllers/admin/application_controller.rb",
  162. /# TODO Add authentication logic here\./,
  163. "redirect_to '/', alert: 'Not authorized.' unless user_signed_in? && current_user.admin?"
  164. environment do <<-RUBY
  165. # Expose our application's helpers to Administrate
  166. config.to_prepare do
  167. Administrate::ApplicationController.helper #{@app_name.camelize}::Application.helpers
  168. end
  169. RUBY
  170. end
  171. end
  172. def add_multiple_authentication
  173. insert_into_file "config/routes.rb",
  174. ', controllers: { omniauth_callbacks: "users/omniauth_callbacks" }',
  175. after: " devise_for :users"
  176. generate "model Service user:references provider uid access_token access_token_secret refresh_token expires_at:datetime auth:text"
  177. template = """
  178. env_creds = Rails.application.credentials[Rails.env.to_sym] || {}
  179. %i{ facebook twitter github }.each do |provider|
  180. if options = env_creds[provider]
  181. config.omniauth provider, options[:app_id], options[:app_secret], options.fetch(:options, {})
  182. end
  183. end
  184. """.strip
  185. insert_into_file "config/initializers/devise.rb", " " + template + "\n\n",
  186. before: " # ==> Warden configuration"
  187. end
  188. def add_whenever
  189. run "wheneverize ."
  190. end
  191. def add_friendly_id
  192. generate "friendly_id"
  193. insert_into_file(
  194. Dir["db/migrate/**/*friendly_id_slugs.rb"].first,
  195. "[5.2]",
  196. after: "ActiveRecord::Migration"
  197. )
  198. end
  199. def add_simple_form
  200. generate "simple_form:install --bootstrap"
  201. end
  202. def add_breadcrumbs
  203. content = <<-RUBY
  204. config.i18n.default_locale = 'zh-TW'
  205. config.time_zone = 'Taipei'
  206. RUBY
  207. insert_into_file "config/application.rb", "#{content}\n\n", after: "class Application < Rails::Application\n"
  208. end
  209. def stop_spring
  210. run "spring stop"
  211. end
  212. def add_sitemap
  213. rails_command "sitemap:install"
  214. end
  215. def add_bullet
  216. conf = <<-RUBY
  217. config.after_initialize do
  218. Bullet.enable = true
  219. # Bullet.sentry = true
  220. # Bullet.alert = true
  221. # Bullet.bullet_logger = true
  222. Bullet.console = true
  223. # Bullet.growl = true
  224. # Bullet.xmpp = { :account => 'bullets_account@jabber.org',
  225. # :password => 'bullets_password_for_jabber',
  226. # :receiver => 'your_account@jabber.org',
  227. # :show_online_status => true }
  228. # Bullet.rails_logger = true
  229. # Bullet.honeybadger = true
  230. # Bullet.bugsnag = true
  231. # Bullet.airbrake = true
  232. # Bullet.rollbar = true
  233. Bullet.add_footer = true
  234. # Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
  235. # Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
  236. # Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
  237. end
  238. RUBY
  239. environment(conf, env: 'development')
  240. end
  241. # Main setup
  242. add_template_repository_to_source_path
  243. add_gems
  244. after_bundle do
  245. set_application_name
  246. stop_spring
  247. add_users
  248. add_webpack
  249. add_javascript
  250. add_announcements
  251. add_notifications
  252. add_multiple_authentication
  253. add_sidekiq
  254. add_friendly_id
  255. add_simple_form
  256. add_breadcrumbs
  257. copy_templates
  258. add_whenever
  259. add_sitemap
  260. add_bullet
  261. # Migrate
  262. rails_command "db:create"
  263. rails_command "db:migrate"
  264. # Migrations must be done before this
  265. add_administrate
  266. # Commit everything to git
  267. git :init
  268. git add: "."
  269. git commit: %Q{ -m 'Initial commit' }
  270. say
  271. say "Jumpstart app successfully created!", :blue
  272. say
  273. say "To get started with your new app:", :green
  274. say "cd #{app_name} - Switch to your new app's directory."
  275. say "foreman start - Run Rails, sidekiq, and webpack-dev-server."
  276. end