Skip to content

Commit 1712f3e

Browse files
stevepolitodesignDoodlingDevemilfordStefanni Brasil
authored
Support Rails 7 and Ruby 3 (#1106)
This is a major upgrade that aims to make it so generated Rails applications with suspenders are running on Rails version 7 and Ruby version 3. We took the approach of making the least amount of changes possible. We were unable to support the latest version of Ruby because of a [failing build][]. A future commit could explore how to solve for this, but for now, we decided to just stick with version `3.0.5`. We settled on `3.0.5` and not `3.0.0` in an effort to suppress parser warnings. The biggest change is that we drop support for deprecated CSS tooling by removing [Bourbon][] and introduce [PostCSS][] and [cssbundling-rails][]. We also drop [Bitters][] as a runtime dependency. Add PostCSS Normalize --------------------- In order to use [normalize][], we need to use [PostCSS Normalize][] since we are using [cssbundling-rails][]. We need to move the invocation of the `suspenders:stylesheet_base` to the `leftovers` method because this method is invoked _after_ `finish_template` is called. We do this because we were running into issues where the call to `rails css:install:postcss` had not yet run, but our generator assumes that command has already run. The method must be named `leftovers` since that's what the [finish_template][] method expects. Additionally, we only call this generator if the caller has not passed anything to the `--css` option when generating a new app. This is because Rails handles other css frameworks like `bootstrap` and `tailwind` differently. Finally, we move the invocation of `outro` to the `leftovers` method since it ensures the message will be the last thing to be printed to the console. Add bin/yarn ------------ Now that we have moved off of [Webpacker][], the [bin/yarn][] binstub is no longer generated. Because of this, we need to manually have it added during a new app build. Introduce CalVer ---------------- Because this upgrade was a breaking change, we thought it was a good time to switch to [CalVer][]. Since this project is composed of other projects, every release is a potential breaking change. Using the date as the `major` version encodes this risk. Improve console output ---------------------- Ensures the invocation of all generator methods happens _before_ we print the outro. This is because a generator invokes all methods in the class in the order they are declared. Specifically, this meant invoking `generate_views` in the `suspenders_customization` method. Prior to this, `generate_views` was invoked after the `outro` was printed. [Webpacker]: https://github.com/rails/webpacker [failing build]: https://github.com/thoughtbot/suspenders/actions/runs/3418310707 [Bourbon]: https://github.com/thoughtbot/bourbon [PostCSS]: https://postcss.org [cssbundling-rails]: https://github.com/rails/cssbundling-rails [Bitters]: https://github.com/thoughtbot/bitters [normalize]: https://necolas.github.io/normalize.css/ [PostCSS Normalize]: https://github.com/csstools/postcss-normalize [finish_template]: https://github.com/rails/rails/blob/d5124b2522130785378238ba714029ce8ef9de97/railties/lib/rails/generators/rails/plugin/plugin_generator.rb#L283-L285 [bin/yarn]: https://github.com/rails/webpacker/blob/master/lib/install/bin/yarn [CalVer]: https://calver.org Co-authored-by: Aji Slater <[email protected]> Co-authored-by: Eric Milford <[email protected]> Co-authored-by: Stefanni Brasil <[email protected]>
1 parent 5624ca5 commit 1712f3e

20 files changed

+138
-91
lines changed

.ruby-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.7.4
1+
3.0.5

NEWS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
20230113.0 (January, 13, 2023)
2+
3+
Support Rails 7 and Ruby 3. Introduce CalVer.
4+
5+
* Upgraded: Ruby to 3.0.5
6+
* Upgraded: Supported Rails version to 7.0.0
7+
* Removed: Bourbon
8+
* Removed: Bitters
9+
* Removed: Autoprefixer Rails
10+
* Added: cssbundling-rails
11+
* Added: PostCSS Autoprefixer
12+
* Added: PostCSS Normalize
13+
114
1.56.1 (July 17, 2022)
215

316
Fixes a critical error with the previous release

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,10 @@ generated projectname/Gemfile.
3434

3535
It includes application gems like:
3636

37-
* [Autoprefixer Rails](https://github.com/ai/autoprefixer-rails) for CSS vendor prefixes
38-
* [Bourbon](https://github.com/thoughtbot/bourbon) for Sass mixins
39-
* [Bitters](https://github.com/thoughtbot/bitters) for scaffold application styles
4037
* [Sidekiq](https://github.com/mperham/sidekiq) for background
4138
processing
4239
* [High Voltage](https://github.com/thoughtbot/high_voltage) for static pages
4340
* [Honeybadger](https://www.honeybadger.io/?affiliate=A43uwl) for exception notification
44-
* [Normalize](https://necolas.github.io/normalize.css/) for resetting browser styles
4541
* [Oj](http://www.ohler.com/oj/)
4642
* [Postgres](https://github.com/ged/ruby-pg) for access to the Postgres database
4743
* [Rack Canonical Host](https://github.com/tylerhunt/rack-canonical-host) to
@@ -105,6 +101,8 @@ Suspenders also comes with:
105101
* Configuration for [stylelint][stylelint]
106102
* The analytics adapter [Segment][segment] (and therefore config for Google
107103
Analytics, Intercom, Facebook Ads, Twitter Ads, etc.)
104+
* [PostCSS Autoprefixer][autoprefixer] for CSS vendor prefixes
105+
* [PostCSS Normalize][normalize] for resetting browser styles
108106

109107
[setup]: https://robots.thoughtbot.com/bin-setup
110108
[compress]: https://robots.thoughtbot.com/content-compression-with-rack-deflater
@@ -115,6 +113,8 @@ Suspenders also comes with:
115113
[hound]: https://houndci.com
116114
[stylelint]: https://stylelint.io/
117115
[segment]: https://segment.com
116+
[autoprefixer]: https://github.com/postcss/autoprefixer
117+
[normalize]: https://github.com/csstools/postcss-normalize
118118

119119
## Heroku
120120

docs/rails_7.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Rails 7
2+
3+
To create a new Rails 7 app with Suspenders, you need to have `node >= 14.6`.
4+
5+
After the app is created, run the server with `bin/dev`.

lib/suspenders/app_builder.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ def provide_setup_script
7575
run "chmod a+x bin/setup"
7676
end
7777

78+
def provide_yarn_script
79+
template "bin_yarn", "bin/yarn", force: true
80+
run "chmod a+x bin/yarn"
81+
end
82+
7883
def configure_generators
7984
config = <<-RUBY
8085
@@ -100,13 +105,13 @@ def configure_local_mail
100105

101106
def setup_asset_host
102107
replace_in_file "config/environments/production.rb",
103-
"# config.asset_host = 'http://assets.example.com'",
108+
%(# config.asset_host = "http://assets.example.com"),
104109
'config.asset_host = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST"))'
105110

106111
if File.exist?("config/initializers/assets.rb")
107112
replace_in_file "config/initializers/assets.rb",
108-
"config.assets.version = '1.0'",
109-
'config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'
113+
%(Rails.application.config.assets.version = "1.0"),
114+
'Rails.application.config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'
110115
end
111116

112117
config = <<~EOD

lib/suspenders/generators/app_generator.rb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ class AppGenerator < Rails::Generators::AppGenerator
3131
class_option :skip_system_test,
3232
type: :boolean, default: true, desc: "Skip system test files"
3333

34-
class_option :skip_turbolinks,
35-
type: :boolean, default: true, desc: "Skip turbolinks gem"
36-
37-
class_option :skip_spring, type: :boolean, default: true,
38-
desc: class_options[:skip_spring].description
34+
class_option :css,
35+
type: :string, default: "postcss", aliases: "-c", desc: "Choose CSS processor"
3936

4037
def finish_template
4138
invoke :suspenders_customization
4239
super
4340
end
4441

42+
def leftovers
43+
generate("suspenders:stylesheet_base") unless options[:api] || options[:css] != "postcss"
44+
invoke :outro
45+
end
46+
4547
def suspenders_customization
4648
invoke :customize_gemfile
4749
invoke :setup_development_environment
@@ -57,7 +59,7 @@ def suspenders_customization
5759
invoke :remove_config_comment_lines
5860
invoke :remove_routes_comment_lines
5961
invoke :run_database_migrations
60-
invoke :outro
62+
invoke :generate_views
6163
end
6264

6365
def customize_gemfile
@@ -83,6 +85,7 @@ def setup_development_environment
8385
build :set_test_delivery_method
8486
build :raise_on_unpermitted_parameters
8587
build :provide_setup_script
88+
build :provide_yarn_script
8689
build :configure_generators
8790
build :configure_i18n_for_missing_translations
8891
build :configure_quiet_assets
@@ -150,7 +153,6 @@ def generate_default
150153
generate("suspenders:profiler")
151154
generate("suspenders:json")
152155
generate("suspenders:static")
153-
generate("suspenders:stylesheet_base") unless options[:api]
154156
generate("suspenders:testing")
155157
generate("suspenders:ci")
156158
generate("suspenders:js_driver")
@@ -180,7 +182,7 @@ def generate_views
180182
end
181183

182184
def outro
183-
say "Congratulations! You just pulled our suspenders."
185+
say "\nCongratulations! You just pulled our suspenders."
184186
say honeybadger_outro
185187
end
186188

lib/suspenders/generators/stylesheet_base_generator.rb

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,14 @@
22

33
module Suspenders
44
class StylesheetBaseGenerator < Generators::Base
5-
def add_stylesheet_gems
6-
gem "bourbon", ">= 6.0.0"
7-
Bundler.with_unbundled_env { run "bundle install" }
8-
end
9-
10-
def remove_prior_config
11-
remove_file "app/assets/stylesheets/application.css"
12-
end
13-
14-
def add_css_config
5+
def setup_normalize
6+
run "yarn add postcss-normalize"
157
copy_file(
16-
"application.scss",
17-
"app/assets/stylesheets/application.scss",
8+
"application.postcss.css",
9+
"app/assets/stylesheets/application.postcss.css",
1810
force: true
1911
)
20-
end
21-
22-
def install_bitters
23-
run "bitters install --path app/assets/stylesheets"
24-
end
25-
26-
def install_normalize_css
27-
run "bin/yarn add normalize.css"
12+
copy_file "postcss.config.js", "postcss.config.js", force: true
2813
end
2914
end
3015
end

lib/suspenders/generators/views_generator.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ def create_shared_flashes
1111
copy_file "flashes_helper.rb", "app/helpers/flashes_helper.rb"
1212
end
1313

14-
def create_shared_javascripts
15-
copy_file "_javascript.html.erb",
16-
"app/views/application/_javascript.html.erb"
17-
end
18-
1914
def create_shared_css_overrides
2015
copy_file "_css_overrides.html.erb",
2116
"app/views/application/_css_overrides.html.erb"

lib/suspenders/version.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
module Suspenders
2-
RAILS_VERSION = "~> 6.1.6.1".freeze
2+
RAILS_VERSION = "~> 7.0.0".freeze
33
RUBY_VERSION = IO
44
.read("#{File.dirname(__FILE__)}/../../.ruby-version")
55
.strip
66
.freeze
7-
VERSION = "1.56.1".freeze
7+
VERSION = "20230113.0".freeze
88
end

spec/features/new_project_spec.rb

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
expect(gemfile_file).to match(
1414
/^ruby "#{Suspenders::RUBY_VERSION}"$/o
1515
)
16-
expect(gemfile_file).to match(
17-
/^gem "autoprefixer-rails"$/
18-
)
1916
expect(gemfile_file).to match(
2017
/^gem "rails", "#{Suspenders::RAILS_VERSION}"$/o
2118
)
@@ -66,6 +63,14 @@
6663
expect("bin/setup").to be_executable
6764
end
6865

66+
it "adds bin/yarn file" do
67+
expect(File).to exist("#{project_path}/bin/yarn")
68+
end
69+
70+
it "makes bin/setup executable" do
71+
expect("bin/yarn").to be_executable
72+
end
73+
6974
it "adds support file for action mailer" do
7075
expect(File).to exist("#{project_path}/spec/support/action_mailer.rb")
7176
end
@@ -255,10 +260,6 @@
255260
expect(app_json_file).to match(/"name":\s*"#{app_name.dasherize}"/)
256261
end
257262

258-
def app_name
259-
TestPaths::APP_NAME
260-
end
261-
262263
it "adds high_voltage" do
263264
gemfile = IO.read("#{project_path}/Gemfile")
264265
expect(gemfile).to match(/high_voltage/)
@@ -270,27 +271,53 @@ def app_name
270271
expect(gemfile).to match(/sassc-rails/)
271272
end
272273

273-
it "adds and configures bourbon" do
274+
it "configures Timecop safe mode" do
275+
spec_helper = read_project_file(%w[spec spec_helper.rb])
276+
expect(spec_helper).to match(/Timecop.safe_mode = true/)
277+
end
278+
279+
it "adds and configures a bundler strategy for css and js" do
274280
gemfile = read_project_file("Gemfile")
275281

276-
expect(gemfile).to match(/bourbon/)
282+
expect(gemfile).to match(/cssbundling-rails/)
283+
expect(gemfile).to match(/jsbundling-rails/)
284+
expect(File).to exist("#{project_path}/postcss.config.js")
285+
expect(File).to exist("#{project_path}/package.json")
286+
expect(File).to exist("#{project_path}/bin/dev")
287+
expect(File).to exist("#{project_path}/app/assets/stylesheets/application.postcss.css")
288+
expect(File).to exist("#{project_path}/app/javascript/application.js")
277289
end
278290

279-
it "configures bourbon, and bitters" do
280-
app_css = read_project_file(%w[app assets stylesheets application.scss])
281-
expect(app_css).to match(
282-
/normalize\.css\/normalize.*bourbon.*base/m
283-
)
291+
it "adds normalize.css" do
292+
stylesheet = read_project_file %w[app assets stylesheets application.postcss.css]
293+
dependencies = read_project_file %w[package.json]
294+
configuration = read_project_file %w[postcss.config.js]
295+
296+
expect(stylesheet).to include(%(@import "normalize.css"))
297+
expect(dependencies).to include(%("postcss-normalize"))
298+
expect(configuration).to include(%(require('postcss-normalize')))
284299
end
285300

286-
it "doesn't use turbolinks" do
287-
app_js = read_project_file(%w[app javascript packs application.js])
288-
expect(app_js).not_to match(/turbolinks/)
301+
it "imports css and js" do
302+
layout = read_project_file %w[app views layouts application.html.erb]
303+
304+
expect(layout)
305+
.to include(%(<%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>))
306+
expect(layout)
307+
.to include(%(<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>))
289308
end
290309

291-
it "configures Timecop safe mode" do
292-
spec_helper = read_project_file(%w[spec spec_helper.rb])
293-
expect(spec_helper).to match(/Timecop.safe_mode = true/)
310+
it "loads security helpers" do
311+
layout = read_project_file %w[app views layouts application.html.erb]
312+
313+
expect(layout)
314+
.to include(%(<%= csp_meta_tag %>))
315+
expect(layout)
316+
.to include(%(<%= csrf_meta_tags %>))
317+
end
318+
319+
def app_name
320+
TestPaths::APP_NAME
294321
end
295322

296323
def development_config

0 commit comments

Comments
 (0)