ruby_ui_scaffold 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea2c9998050e2208005c500148ed961b083d93530e699992e5d8c2cd2463df05
4
- data.tar.gz: 2331070feb2defcd9763082d11b8dd8c38a3523e2e3f1333eca359dd1b042d09
3
+ metadata.gz: aa48925787982afab3d09cbaff717c090245587dc2c6e6bfd2a9754d0d2945c4
4
+ data.tar.gz: 00ec82e81ac9d9b06c7f2922dce6e02b7a2866a436ebca8d97102c9f5c66b4ad
5
5
  SHA512:
6
- metadata.gz: b1965a5ee407847b93b9c01410ac939d9383143f864d7b9d96e2691304ff3f9e7034e7ed61910aa82421b8164760b1273dbdc9685906c083a1d3f1bed79bc692
7
- data.tar.gz: fdde9d0a8f65ad928ece8044b07ec1dda306576d48e49bbed7eda5bfdb5ca3822278c9823109f7c977d5f383e2aa57b0130b53e41da3343d9b3c0de690177579
6
+ metadata.gz: d5fac2bf36315c42e793cd3dc01aeec389d016bd94f315d782bd162914304ee72f08a335a7fe51cfba90c1f9d73d6238a07a14c504a1ab5b31f48f402dd53364
7
+ data.tar.gz: e18f9aa8c59ac5eac1f0286679885e850549aebb360f450bf4358ae535d5b091cb9096edf520e6da82b71819cbd9fee755d7bb762068a3d29ba3fcf1e35ca3df
data/CHANGELOG.md CHANGED
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.1] - 2026-11-12
11
+
12
+ ### Fixed
13
+
14
+ - **`rails g ruby_ui_scaffold` generated no model or migration** (and having
15
+ the gem in the Gemfile broke plain `rails g model` too). The Railtie's
16
+ `generators` block required the generator classes, which loaded Rails'
17
+ `ModelGenerator` before `Rails::Generators.configure!` and froze its `:orm`
18
+ hook as `false`. The Railtie now only sets option defaults; generator
19
+ classes load lazily, after configuration.
20
+ - **Edit form crashed for `decimal` columns** with
21
+ `Phlex::ArgumentError (Invalid attribute value for value: 0.58206e3)` —
22
+ Phlex 2 rejects `BigDecimal` attribute values. The input value is now
23
+ stringified (`@record.price&.to_s` → `"582.06"`).
24
+ - **Boolean `Badge` rendered without colors.** Templates passed the variant
25
+ as a string (`"success"`), but `RubyUI::Badge::COLORS` is symbol-keyed and
26
+ Badge doesn't `to_sym` it. Variants are now symbols (`:success` / `:outline`).
27
+
28
+ ### Changed
29
+
30
+ - **`ruby_ui` now comes from RubyGems.** The installer adds
31
+ `gem "ruby_ui", "~> 1.6", require: false` instead of tracking the GitHub
32
+ `main` branch. Verified end-to-end against ruby_ui 1.6.0. Existing GitHub
33
+ entries in a Gemfile are still detected and left alone.
34
+
35
+ ### Added
36
+
37
+ - **Ruby × Rails compatibility matrix** in the README and a GitHub Actions CI
38
+ workflow that runs the test suite on Ruby 3.2, 3.3, 3.4 and 4.0 against
39
+ Rails 7.1, 7.2, 8.0 and 8.1 (per-version Gemfiles under `gemfiles/`).
40
+
41
+ ### Changed
42
+
43
+ - **Minimum Ruby raised to 3.2.** Phlex 2.x (required by `phlex-rails >= 2.0`)
44
+ already needs Ruby 3.2+, so the previous `>= 3.1` couldn't be installed on 3.1.
45
+
10
46
  ## [0.1.0] - 2026-06-09
11
47
 
12
48
  ### Added
@@ -339,5 +375,6 @@ if your `Components::Base` already declares it.
339
375
  (not `"ruby_ui_scaffold:ruby_ui_scaffold"`) to avoid `find_by_namespace`
340
376
  shadowing of the sub-generators when hooks fire.
341
377
 
342
- [Unreleased]: https://github.com/jacksonpires/ruby_ui_scaffold/compare/v0.1.0...HEAD
378
+ [Unreleased]: https://github.com/jacksonpires/ruby_ui_scaffold/compare/v0.1.1...HEAD
379
+ [0.1.1]: https://github.com/jacksonpires/ruby_ui_scaffold/compare/v0.1.0...v0.1.1
343
380
  [0.1.0]: https://github.com/jacksonpires/ruby_ui_scaffold/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ruby_ui_scaffold
2
2
 
3
+ [![CI](https://github.com/jacksonpires/ruby_ui_scaffold/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jacksonpires/ruby_ui_scaffold/actions/workflows/ci.yml)
4
+
3
5
  Rails scaffold generator that outputs **Phlex views built with [ruby_ui](https://github.com/ruby-ui/ruby_ui) components**, plus a smart `seed` command to populate models with fake data.
4
6
 
5
7
  Drop-in alternative to `rails g scaffold` — generates model, migration, controller, routes, tests, and Phlex view classes wired to ruby_ui components.
@@ -8,9 +10,30 @@ Drop-in alternative to `rails g scaffold` — generates model, migration, contro
8
10
 
9
11
  ## Requirements
10
12
 
13
+ - Ruby 3.2+
11
14
  - Rails 7.1+
12
15
  - Tailwind CSS (any Rails Tailwind setup — `tailwindcss-rails` is fine)
13
16
 
17
+ ### Compatibility matrix
18
+
19
+ The full test suite runs in CI against every combination below.
20
+
21
+ | Ruby \ Rails | 7.1 | 7.2 | 8.0 | 8.1 |
22
+ |--------------|:---:|:---:|:---:|:---:|
23
+ | **4.0** | ✅ | ✅ | ✅ | ✅ |
24
+ | **3.4** | ✅ | ✅ | ✅ | ✅ |
25
+ | **3.3** | ✅ | ✅ | ✅ | ✅ |
26
+ | **3.2** | ✅ | ✅ | ✅ | ✅ |
27
+
28
+ Last verified with Ruby 4.0.9 and Rails 8.1.4.1. Ruby 3.1 isn't supported because Phlex 2.x (required by `phlex-rails >= 2.0`) needs Ruby 3.2+.
29
+
30
+ To run the suite against a specific Rails version locally:
31
+
32
+ ```bash
33
+ BUNDLE_GEMFILE=gemfiles/rails_8.1.gemfile bundle install
34
+ BUNDLE_GEMFILE=gemfiles/rails_8.1.gemfile bundle exec rake test
35
+ ```
36
+
14
37
  ## Disclaimer
15
38
 
16
39
  `ruby_ui_scaffold` is a development-only generator built on the [`ruby_ui`](https://github.com/ruby-ui/ruby_ui) component library — you add both to your app. [`faker`](https://github.com/faker-ruby/faker) and [`lucide-rails`](https://github.com/heyvito/lucide-rails) come along automatically as runtime dependencies of `ruby_ui_scaffold` — `faker` powers the `seed` command, and `lucide-rails` renders the icons in the generated views (the index action menu plus the New / Edit / Create / Update buttons).
@@ -25,7 +48,7 @@ On a fresh Rails app, add **both** gems to your `Gemfile` — `ruby_ui` (the com
25
48
 
26
49
  ```ruby
27
50
  # Gemfile
28
- gem "ruby_ui", github: "ruby-ui/ruby_ui", branch: "main", require: false
51
+ gem "ruby_ui", "~> 1.6", require: false
29
52
 
30
53
  group :development do
31
54
  gem "ruby_ui_scaffold"
@@ -51,7 +74,7 @@ That's it. The installer wires up phlex, ruby_ui, and the base scaffold componen
51
74
  <details>
52
75
  <summary>What the installer does</summary>
53
76
 
54
- 0. **ruby_ui gem bootstrap** — if `ruby_ui` isn't loadable, adds `gem "ruby_ui", github: "ruby-ui/ruby_ui", branch: "main", require: false` to the Gemfile (unless an entry already exists) and runs `bundle install`. Skipped entirely once the gem loads.
77
+ 0. **ruby_ui gem bootstrap** — if `ruby_ui` isn't loadable, adds `gem "ruby_ui", "~> 1.6", require: false` (from RubyGems) to the Gemfile (unless an entry already exists) and runs `bundle install`. Skipped entirely once the gem loads.
55
78
  1. **`phlex:install`** — creates `app/views/base.rb` (`Views::Base`), `app/components/base.rb` (`Components::Base`), and `config/initializers/phlex.rb` (wires the `Views::` autoloader). Skipped if `app/views/base.rb` already exists.
56
79
  2. **`ruby_ui:install`** — mixes `include RubyUI` into `Components::Base`, adds `config/initializers/ruby_ui.rb`, and the Tailwind preset. Skipped if `Components::Base` already includes RubyUI.
57
80
  3. **Base components** — installs the components every scaffold's shell uses regardless of columns/flags: `table`, `link`, `button`, `card`, `typography`, `dropdown_menu`, `alert_dialog`, `form`, `input`. Each is skipped if already present. The installer does **not** run `ruby_ui:component:all` — column/flag-specific components are installed on demand (see below).
@@ -431,7 +454,8 @@ Controllers render via the fully-qualified constant — `render ::Views::Buddies
431
454
  | `string` | `Input(type: "text")` |
432
455
  | `text` | `Textarea(rows: 4)` |
433
456
  | `integer` | `Input(type: "number", step: 1)` |
434
- | `float`, `decimal` | `Input(type: "number", step: "any")` |
457
+ | `float` | `Input(type: "number", step: "any")` |
458
+ | `decimal` | `Input(type: "number", step: "any")` — value stringified (`&.to_s`) |
435
459
  | `boolean` | `Checkbox` + hidden `"0"` |
436
460
  | `date` | `DatePicker` (ruby_ui — Popover + Calendar over a submittable input) |
437
461
  | `time` | `Input(type: "time")` |
@@ -21,6 +21,11 @@ module RubyUiScaffold
21
21
  class InstallGenerator < ::Rails::Generators::Base
22
22
  include ::RubyUiScaffold::ComponentInstaller
23
23
 
24
+ # Version constraint for the `ruby_ui` Gemfile entry the installer adds.
25
+ # ruby_ui is published on RubyGems; 1.6 is the oldest release this gem's
26
+ # generated views and component set were verified against.
27
+ RUBY_UI_REQUIREMENT = "~> 1.6"
28
+
24
29
  desc "Install the ruby_ui gem, phlex, ruby_ui, and the base scaffold components."
25
30
 
26
31
  def check_phlex_rails_gem
@@ -37,9 +42,9 @@ module RubyUiScaffold
37
42
  end
38
43
 
39
44
  # Ensure the `ruby_ui` gem is available. Unlike `phlex-rails` (a declared
40
- # runtime dependency of this gem), `ruby_ui` is distributed via GitHub and
41
- # can't be a gemspec dependency — so on a fresh app it usually isn't
42
- # bundled yet. Rather than abort, add it to the Gemfile and `bundle
45
+ # runtime dependency of this gem), `ruby_ui` is left to the host app's
46
+ # Gemfile (so the app controls its version and group, as ruby_ui's own
47
+ # docs recommend) — so on a fresh app it usually isn't bundled yet. Rather than abort, add it to the Gemfile and `bundle
43
48
  # install` automatically, then let the rest of the installer proceed:
44
49
  # the subsequent `ruby_ui:install` / `ruby_ui:component` steps run in
45
50
  # subprocesses (via run_rails_generator!) that boot with the freshly
@@ -56,7 +61,7 @@ module RubyUiScaffold
56
61
  say "\n → ruby_ui is in the Gemfile but not bundled yet — running `bundle install`.", :cyan
57
62
  else
58
63
  say "\n → ruby_ui gem not found — adding it to your Gemfile.", :cyan
59
- gem "ruby_ui", github: "ruby-ui/ruby_ui", branch: "main", require: false
64
+ gem "ruby_ui", RUBY_UI_REQUIREMENT, require: false
60
65
  end
61
66
 
62
67
  run_bundle_install!
@@ -137,7 +142,7 @@ module RubyUiScaffold
137
142
  def abort_ruby_ui_unavailable!
138
143
  say "\n ❌ The `ruby_ui` gem isn't available and no Gemfile was found to add it to.", :red
139
144
  say " Add it to your Gemfile, then bundle and retry:\n", :red
140
- say %( gem "ruby_ui", github: "ruby-ui/ruby_ui", branch: "main", require: false), :cyan
145
+ say %( gem "ruby_ui", "#{RUBY_UI_REQUIREMENT}", require: false), :cyan
141
146
  say " bundle install"
142
147
  say " bin/rails g ruby_ui_scaffold:install\n", :cyan
143
148
  exit(1)
@@ -3,6 +3,17 @@
3
3
  require "rails/generators"
4
4
  require "rails/generators/rails/scaffold/scaffold_generator"
5
5
 
6
+ # Load our sub-generators eagerly, together with this entry point. Rails'
7
+ # hook lookup (Rails::Command::Behavior#lookup) requires only the FIRST
8
+ # existing candidate file: for the views hook (`find_by_namespace(
9
+ # "ruby_ui_scaffold", "ruby_ui_scaffold", "scaffold")`) that is THIS file,
10
+ # so `scaffold/scaffold_generator.rb` would never be loaded and the hook
11
+ # reports "ruby_ui_scaffold [not found]". This file itself is loaded lazily
12
+ # by the namespace lookup — after `Rails::Generators.configure!` — so these
13
+ # requires can't freeze option defaults too early (see Railtie).
14
+ require "generators/ruby_ui_scaffold/scaffold_controller/scaffold_controller_generator"
15
+ require "generators/ruby_ui_scaffold/scaffold/scaffold_generator"
16
+
6
17
  module RubyUiScaffold
7
18
  module Generators
8
19
  # Entry point: `rails g ruby_ui_scaffold User name:string ...`
@@ -43,7 +43,7 @@ class Views::<%= controller_class_name %>::Index < Views::Base
43
43
  <% attributes.reject { |a| a.respond_to?(:password_digest?) && a.password_digest? }.each do |attribute| -%>
44
44
  <% if attribute.type == :boolean -%>
45
45
  TableCell do
46
- Badge(variant: <%= singular_table_name %>.<%= attribute.column_name %>? ? "success" : "outline") do
46
+ Badge(variant: <%= singular_table_name %>.<%= attribute.column_name %>? ? :success : :outline) do
47
47
  <%= singular_table_name %>.<%= attribute.column_name %>? ? "Yes" : "No"
48
48
  end
49
49
  end
@@ -86,7 +86,7 @@ class Views::<%= controller_class_name %>::Index < Views::Base
86
86
  <% attributes.reject { |a| a.respond_to?(:password_digest?) && a.password_digest? }.each do |attribute| -%>
87
87
  <% if attribute.type == :boolean -%>
88
88
  TableCell do
89
- Badge(variant: <%= singular_table_name %>.<%= attribute.column_name %>? ? "success" : "outline") do
89
+ Badge(variant: <%= singular_table_name %>.<%= attribute.column_name %>? ? :success : :outline) do
90
90
  <%= singular_table_name %>.<%= attribute.column_name %>? ? "Yes" : "No"
91
91
  end
92
92
  end
@@ -35,7 +35,7 @@ class Views::<%= controller_class_name %>::Show < Views::Base
35
35
  div do
36
36
  Text(weight: "medium") { "<%= attribute.human_name %>:" }
37
37
  <% if attribute.type == :boolean -%>
38
- Badge(variant: @<%= singular_table_name %>.<%= attribute.column_name %>? ? "success" : "outline") do
38
+ Badge(variant: @<%= singular_table_name %>.<%= attribute.column_name %>? ? :success : :outline) do
39
39
  @<%= singular_table_name %>.<%= attribute.column_name %>? ? "Yes" : "No"
40
40
  end
41
41
  <% elsif reference_associations.include?(attribute.name.to_sym) -%>
@@ -3,6 +3,10 @@
3
3
  require "rails/generators"
4
4
  require "rails/generators/rails/scaffold_controller/scaffold_controller_generator"
5
5
  require "ruby_ui_scaffold/attribute_helpers"
6
+ # Our template_engine hook target. Required directly so a standalone
7
+ # `rails g ruby_ui_scaffold:scaffold_controller` resolves it too (see the
8
+ # note in ruby_ui_scaffold_generator.rb on Rails' first-match lookup).
9
+ require "generators/ruby_ui_scaffold/scaffold/scaffold_generator"
6
10
 
7
11
  module RubyUiScaffold
8
12
  module Generators
@@ -38,7 +38,10 @@ module RubyUiScaffold
38
38
  when :text then textarea
39
39
  when :boolean then checkbox
40
40
  when :integer then input("number", step: 1)
41
- when :float, :decimal then input("number", step: "any")
41
+ when :float then input("number", step: "any")
42
+ # Phlex 2 rejects BigDecimal attribute values (Phlex::ArgumentError), so
43
+ # stringify — ActiveSupport makes BigDecimal#to_s plain notation ("582.06").
44
+ when :decimal then input("number", step: "any", value_suffix: "&.to_s")
42
45
  when :date then date_picker
43
46
  when :time then input("time", value_suffix: %q{&.strftime("%H:%M")})
44
47
  when :datetime, :timestamp then input("datetime-local", value_suffix: %q{&.strftime("%Y-%m-%dT%H:%M")})
@@ -6,20 +6,24 @@ module RubyUiScaffold
6
6
  # (i.e. on `rails g`), not at app boot — important because
7
7
  # Rails::Generators isn't loaded at boot.
8
8
  generators do
9
- # IMPORTANT: set option defaults BEFORE requiring the generator
10
- # classes. `class_option(...)` (called by `hook_for`) freezes the
11
- # default at class-definition time via `default_value_for_option`,
12
- # which reads from Rails::Generators.options.
9
+ # Only set option defaults here — do NOT require any generator class.
13
10
  #
14
- # We only need to override template_engine — the scaffold_controller
15
- # default falls back to :scaffold_controller (Rails-wide), which
16
- # combined with our base_name routes correctly to ours.
11
+ # Rails runs every railtie's `generators` block BEFORE
12
+ # `Rails::Generators.configure!(app.config.generators)` (see
13
+ # Rails::Engine#load_generators). `hook_for`/`class_option` freeze their
14
+ # defaults at class-definition time, so requiring our generators here
15
+ # would also load Rails' ScaffoldGenerator → ModelGenerator early, and
16
+ # their `:orm` hook would freeze as `false` (the pre-configure default)
17
+ # instead of `:active_record` — silently skipping the model + migration
18
+ # for `rails g ruby_ui_scaffold` AND plain `rails g model`.
19
+ #
20
+ # Our generator classes are instead loaded lazily by Rails' namespace
21
+ # lookup (`generators/ruby_ui_scaffold/...`), after configure! has run,
22
+ # and they read this template_engine default at that point. The
23
+ # scaffold_controller default falls back to :scaffold_controller
24
+ # (Rails-wide), which combined with our base_name routes to ours.
17
25
  ::Rails::Generators.options[:ruby_ui_scaffold] ||= {}
18
26
  ::Rails::Generators.options[:ruby_ui_scaffold][:template_engine] = "ruby_ui_scaffold"
19
-
20
- require "generators/ruby_ui_scaffold/ruby_ui_scaffold_generator"
21
- require "generators/ruby_ui_scaffold/scaffold_controller/scaffold_controller_generator"
22
- require "generators/ruby_ui_scaffold/scaffold/scaffold_generator"
23
27
  end
24
28
  end
25
29
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyUiScaffold
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_ui_scaffold
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jackson Pires
@@ -184,14 +184,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
186
186
  - !ruby/object:Gem::Version
187
- version: 3.1.0
187
+ version: 3.2.0
188
188
  required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - ">="
191
191
  - !ruby/object:Gem::Version
192
192
  version: '0'
193
193
  requirements: []
194
- rubygems_version: 4.0.6
194
+ rubygems_version: 4.0.20
195
195
  specification_version: 4
196
196
  summary: Rails scaffold generator that outputs Phlex views built with ruby_ui components.
197
197
  test_files: []