inline_forms 8.0.4 → 8.1.0
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 +4 -4
- data/CHANGELOG.md +32 -0
- data/app/controllers/inline_forms_controller.rb +23 -20
- data/app/views/inline_forms/_list.html.erb +2 -1
- data/inline_forms.gemspec +1 -1
- data/lib/generators/inline_forms_generator.rb +29 -17
- data/lib/generators/templates/application_record.rb +32 -0
- data/lib/generators/templates/model.erb +7 -14
- data/lib/inline_forms/form_elements/check_list_helper.rb +3 -5
- data/lib/inline_forms/version.rb +1 -1
- data/test/inline_forms_generator_test.rb +61 -0
- metadata +3 -13
- data/docs/git-deps-assessment.md +0 -93
- data/docs/jquery-widgets.md +0 -25
- data/docs/prompt/.gitignore +0 -5
- data/docs/prompt/test-the-example-app.md +0 -32
- data/docs/rails-8-phase4-audit.md +0 -39
- data/docs/rails-8-release.md +0 -56
- data/docs/turbo-stream-audit.md +0 -16
- data/docs/ujs-to-turbo.md +0 -207
- data/docs/zeitwerk-and-load-paths.md +0 -49
- data/lib/generators/assets/stylesheets/inline_forms.scss +0 -491
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b3b934b94b7f4b5298dea2e2a51b8c97c37c06969a3484d528e336edf17ddfde
|
|
4
|
+
data.tar.gz: fedfafb7fba445712299b4c240fc905418c665d8f29e139c17cb9abc4138fe36
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b9d1abfecdf6fa9c75c4d79967e8604e0bb408a40a08475fb7106e12b0b301a437e8192f836a39b9b5c75261ac97d5dfade6f2ba5ecea9005015814bd257028f
|
|
7
|
+
data.tar.gz: 5f62f997de89dd93334a6324d2d02fe3bd283036d3f68ee39947cd400ab57f6d3a2d959745498d2b7f5e5c567889cd02e258ed7c15fef3cf3f051f3a21ee3d60
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,38 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [8.1.0] - 2026-05-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`ApplicationRecord` template carries shared model behavior:** `has_paper_trail on: [:create, :update, :destroy]`, `attr_writer :inline_forms_attribute_list`, `self.per_page = 7`, `human_attribute_name` instance wrapper, and `def self.not_accessible_through_html?` default. Generated models inherit all of this; `lib/generators/templates/model.erb` only emits per-model differences (associations, `inline_forms_attribute_list`, `_presentation`, `<=>`, `not_accessible_through_html?` override when `_enabled` is absent).
|
|
12
|
+
- **`scope :inline_forms_list, -> { all }` and `scope :inline_forms_search, ->(_q) { all }`** on `ApplicationRecord`. Both are no-ops by default; subclasses opt in. Replaces the old `def self.order_by_clause` contract with composable Active Record relations.
|
|
13
|
+
- **Generator flags `_list_order:col` and `_list_search:col`:** emit `scope :inline_forms_list, -> { order(:col, :id) }` and `scope :inline_forms_search, ->(q) { where("col LIKE ?", "%#{q}%") }` respectively. `_list_order` also still emits `def <=>(other)` for in-memory sort on associations (used by `check_list` show). Tie-break on `:id` is added automatically so will_paginate pages stay stable.
|
|
14
|
+
- **`SPECIAL_GENERATOR_NAMES` constant** in `InlineForms::InlineFormsGenerator` consolidates `_presentation`, `_order`, `_list_order`, `_list_search`, `_enabled`, `_id`, `_no_migration`, `_no_model` so `migration?` / `attribute?` no longer drift.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`order_by_clause` is gone from the gem.** `InlineFormsController#index` / `#create`, `check_list_helper.rb`, and `app/views/inline_forms/_list.html.erb` now compose `merge(@Klass.inline_forms_list)` and `merge(@Klass.inline_forms_search(params[:search]))` instead of building raw `"table.col"` strings. Search and order are now independent (one column had to do both jobs before); models can declare each separately or neither.
|
|
19
|
+
- **Per-page pagination fix in `ApplicationRecord`:** `self.per_page = 7` (class-level, what will_paginate's `class_attribute :per_page` reads). The old `attr_reader :per_page` + `@per_page = 7` instance pair on every generated model was a no-op (described at length in 8.0.x notes); models that need a different value override with `self.per_page = N` (Photo uses `5`). The installer’s Photo override now uses `inject_into_class "app/models/photo.rb", "Photo", " self.per_page = 5\n"` instead of patching the legacy `attr_reader` block out.
|
|
20
|
+
- **`_order:col` is deprecated as an alias for `_list_order:col`.** Still works (emits the same scope plus `<=>`); the generator prints `say_status :deprecated, "_order:col is deprecated; use _list_order:col"` so existing scripts keep generating but the migration path is visible.
|
|
21
|
+
- **Installer User model:** dropped `default_scope { order :name }` and the `def self.order_by_clause; nil; end` stub. Added `scope :inline_forms_list, -> { order(:name, :id) }` with a comment about why named scopes beat `default_scope` (no `unscope`/`reorder` foot-guns; cleaner `update_all` / association inheritance).
|
|
22
|
+
- **Installer example-app generator calls** for `Locale`, `Role`, `Photo`, `Apartment`, `Owner` now pass `_list_order:name` (and `_list_search:name` for the searchable top-level models `Apartment` and `Owner`) to declare ordering and search explicitly. Replaces the implicit `order_by_clause = "name"` default that the old generator produced.
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
|
|
26
|
+
- **`lib/generators/assets/javascripts/`** (including the empty `ckeditor/` subfolder). Leftover from the CKEditor era; nothing in the gem or installer copied from it. The engine still ships JS under `app/assets/javascripts/` and `vendor/assets/javascripts/`.
|
|
27
|
+
- **`lib/generators/assets/stylesheets/inline_forms.scss`** mirror. The installer doesn't copy it; the gem stylesheet at `app/assets/stylesheets/inline_forms/inline_forms.scss` is the single source consumed via `@use "inline_forms/inline_forms"`. `inline_forms_devise.css` stays — it is the host-app override hook copied by the installer and linked from `layouts/devise.html.erb`.
|
|
28
|
+
|
|
29
|
+
### Migration notes
|
|
30
|
+
|
|
31
|
+
Existing apps upgrading from 8.0.x:
|
|
32
|
+
|
|
33
|
+
1. Replace your `app/models/application_record.rb` with the contents of `lib/generators/templates/application_record.rb` (or just merge in the new `has_paper_trail`, `self.per_page`, `inline_forms_list` / `inline_forms_search` scopes, and `not_accessible_through_html?` default).
|
|
34
|
+
2. For each model that had `def self.order_by_clause; "col"; end`, replace with `scope :inline_forms_list, -> { order(:col, :id) }`. Drop the old method; the gem no longer reads it.
|
|
35
|
+
3. If you used `default_scope { order(:name) }` for inline_forms list ordering, swap to the named scope above.
|
|
36
|
+
4. Per-model `attr_reader :per_page` / `@per_page = N` pairs are no-ops; replace with `self.per_page = N` (or remove and inherit `7` from `ApplicationRecord`).
|
|
37
|
+
5. `_order:col` in your generator scripts still works but emits a deprecation notice; switch to `_list_order:col` and add `_list_search:col` if you want the search box to filter on that column.
|
|
38
|
+
|
|
7
39
|
## [8.0.4] - 2026-05-24
|
|
8
40
|
|
|
9
41
|
### Added
|
|
@@ -36,14 +36,12 @@ class InlineFormsController < ApplicationController
|
|
|
36
36
|
@parent_class = params[:parent_class]
|
|
37
37
|
@parent_id = params[:parent_id]
|
|
38
38
|
@ul_needed = params[:ul_needed]
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
if @parent_class.
|
|
43
|
-
conditions = [ @Klass.table_name + "." + @Klass.order_by_clause + " like ?", "%#{params[:search]}%" ] if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil?
|
|
44
|
-
else
|
|
39
|
+
# Nested associated lists scope to the parent FK. Top-level lists may
|
|
40
|
+
# apply the model's `inline_forms_search` scope when ?search= is passed.
|
|
41
|
+
fk_conditions = nil
|
|
42
|
+
if @parent_class.present? && @Klass.reflect_on_association(@parent_class.underscore.to_sym)
|
|
45
43
|
foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key
|
|
46
|
-
|
|
44
|
+
fk_conditions = [ "#{foreign_key} = ?", @parent_id ]
|
|
47
45
|
end
|
|
48
46
|
# CanCan's load_and_authorize_resource sets @apartments (etc.); keep @objects in sync.
|
|
49
47
|
collection_ivar = :"@#{controller_name}"
|
|
@@ -52,9 +50,13 @@ class InlineFormsController < ApplicationController
|
|
|
52
50
|
@objects = loaded unless loaded.nil?
|
|
53
51
|
end
|
|
54
52
|
@objects ||= @Klass.accessible_by(current_ability) if cancan_enabled?
|
|
55
|
-
@objects ||= @Klass
|
|
56
|
-
@objects = @objects.
|
|
57
|
-
|
|
53
|
+
@objects ||= @Klass.all
|
|
54
|
+
@objects = @objects.merge(@Klass.inline_forms_list) if @Klass.respond_to?(:inline_forms_list)
|
|
55
|
+
if fk_conditions.nil? && params[:search].present? && @Klass.respond_to?(:inline_forms_search)
|
|
56
|
+
@objects = @objects.merge(@Klass.inline_forms_search(params[:search]))
|
|
57
|
+
end
|
|
58
|
+
@objects = @objects.where(fk_conditions) if fk_conditions
|
|
59
|
+
@objects = @objects.paginate(:page => params[:page])
|
|
58
60
|
respond_to do |format|
|
|
59
61
|
# `not_accessible_through_html?` is about preventing direct top-level
|
|
60
62
|
# HTML CRUD on this resource (e.g. /photos when only Apartment is the
|
|
@@ -139,22 +141,23 @@ class InlineFormsController < ApplicationController
|
|
|
139
141
|
end
|
|
140
142
|
@parent_class = params[:parent_class]
|
|
141
143
|
@parent_id = params[:parent_id]
|
|
142
|
-
#
|
|
143
|
-
|
|
144
|
-
if @parent_class.
|
|
145
|
-
conditions = [ @Klass.table_name + "." + @Klass.order_by_clause + " like ?", "%#{params[:search]}%" ] if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil?
|
|
146
|
-
else
|
|
144
|
+
# See #index for the order/search/parent-fk decomposition.
|
|
145
|
+
fk_conditions = nil
|
|
146
|
+
if @parent_class.present? && @Klass.reflect_on_association(@parent_class.underscore.to_sym)
|
|
147
147
|
foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key
|
|
148
|
-
|
|
148
|
+
fk_conditions = [ "#{foreign_key} = ?", @parent_id ]
|
|
149
149
|
@object[foreign_key] = @parent_id
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
if @object.save
|
|
153
153
|
flash.now[:success] = t('success', :message => @object.class.model_name.human)
|
|
154
|
-
@objects = @Klass
|
|
155
|
-
@objects = @Klass.
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
@objects = cancan_enabled? ? @Klass.accessible_by(current_ability) : @Klass.all
|
|
155
|
+
@objects = @objects.merge(@Klass.inline_forms_list) if @Klass.respond_to?(:inline_forms_list)
|
|
156
|
+
if fk_conditions.nil? && params[:search].present? && @Klass.respond_to?(:inline_forms_search)
|
|
157
|
+
@objects = @objects.merge(@Klass.inline_forms_search(params[:search]))
|
|
158
|
+
end
|
|
159
|
+
@objects = @objects.where(fk_conditions) if fk_conditions
|
|
160
|
+
@objects = @objects.paginate(:page => params[:page])
|
|
158
161
|
@object = nil
|
|
159
162
|
respond_to do |format|
|
|
160
163
|
format.html { render_list_frame_after_save } if html_list_flow_allowed?
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
<% foreign_key = parent_class.reflect_on_association(attribute.to_sym).options[:foreign_key] || parent_class.name.foreign_key -%>
|
|
35
35
|
<% model = attribute.to_s.singularize.camelcase.constantize %>
|
|
36
36
|
<% conditions = [ "#{model.table_name}.#{foreign_key} = ?", parent_id ] %>
|
|
37
|
+
<% klass = attribute.to_s.singularize.camelcase.constantize %>
|
|
37
38
|
<% objects = parent_class.find(parent_id).send(attribute) %>
|
|
38
39
|
<% objects = parent_class.find(parent_id).send(attribute).accessible_by(current_ability) if cancan_enabled? %>
|
|
39
|
-
<% objects = objects.
|
|
40
|
+
<% objects = objects.merge(klass.inline_forms_list) if klass.respond_to?(:inline_forms_list) %>
|
|
40
41
|
<% objects = objects.where(conditions).paginate(:page => params[:page]) %>
|
|
41
42
|
<% end %>
|
|
42
43
|
<% end %>
|
data/inline_forms.gemspec
CHANGED
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
|
19
19
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
|
20
20
|
s.require_paths = ["lib"]
|
|
21
21
|
|
|
22
|
-
s.add_dependency("validation_hints", ">= 8.0
|
|
22
|
+
s.add_dependency("validation_hints", ">= 8.1.0", "< 9.0")
|
|
23
23
|
s.add_dependency("rails", ">= 8.0", "< 8.1")
|
|
24
24
|
s.add_dependency("rails-i18n", ">= 8.0", "< 9.0")
|
|
25
25
|
|
|
@@ -64,19 +64,26 @@ module InlineForms
|
|
|
64
64
|
RELATIONS.has_key?(type) || special_relation?
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# Special "attribute" names that drive the generator (presentation,
|
|
68
|
+
# ordering, search, etc.) but never become real columns or fields.
|
|
69
|
+
SPECIAL_GENERATOR_NAMES = %w[
|
|
70
|
+
_presentation
|
|
71
|
+
_order
|
|
72
|
+
_list_order
|
|
73
|
+
_list_search
|
|
74
|
+
_enabled
|
|
75
|
+
_id
|
|
76
|
+
_no_migration
|
|
77
|
+
_no_model
|
|
78
|
+
].freeze
|
|
79
|
+
|
|
67
80
|
def migration?
|
|
68
81
|
not ( column_type == :no_migration ||
|
|
69
|
-
name
|
|
70
|
-
name == "_order" ||
|
|
71
|
-
name == "_enabled" ||
|
|
72
|
-
name == "_id" )
|
|
82
|
+
SPECIAL_GENERATOR_NAMES.include?(name) )
|
|
73
83
|
end
|
|
74
84
|
|
|
75
85
|
def attribute?
|
|
76
|
-
not ( name
|
|
77
|
-
name == '_order' ||
|
|
78
|
-
name == '_enabled' ||
|
|
79
|
-
name == "_id" ||
|
|
86
|
+
not ( SPECIAL_GENERATOR_NAMES.include?(name) ||
|
|
80
87
|
relation? )
|
|
81
88
|
end
|
|
82
89
|
|
|
@@ -126,10 +133,7 @@ module InlineForms
|
|
|
126
133
|
@has_attached_files = "\n"
|
|
127
134
|
@presentation = "\n"
|
|
128
135
|
@order = "\n"
|
|
129
|
-
@
|
|
130
|
-
" \"name\"\n" +
|
|
131
|
-
" end\n" +
|
|
132
|
-
"\n"
|
|
136
|
+
@list_scopes = ""
|
|
133
137
|
@carrierwave_mounters = "\n"
|
|
134
138
|
@inline_forms_attribute_list = String.new
|
|
135
139
|
|
|
@@ -165,15 +169,23 @@ module InlineForms
|
|
|
165
169
|
" end\n" +
|
|
166
170
|
"\n"
|
|
167
171
|
end
|
|
168
|
-
|
|
172
|
+
# `_list_order:col` (preferred) and the legacy alias `_order:col`
|
|
173
|
+
# both emit the inline_forms_list scope plus a Ruby `<=>` for
|
|
174
|
+
# in-memory sort (used by check_list show on the association).
|
|
175
|
+
if attribute.name == '_order' || attribute.name == '_list_order'
|
|
176
|
+
if attribute.name == '_order'
|
|
177
|
+
say_status :deprecated,
|
|
178
|
+
"_order:#{attribute.type} is deprecated; use _list_order:#{attribute.type}",
|
|
179
|
+
:yellow
|
|
180
|
+
end
|
|
169
181
|
@order << " def <=>(other)\n" +
|
|
170
182
|
" self.#{attribute.type} <=> other.#{attribute.type}\n" +
|
|
171
183
|
" end\n" +
|
|
172
184
|
"\n"
|
|
173
|
-
@
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
185
|
+
@list_scopes << " scope :inline_forms_list, -> { order(:#{attribute.type}, :id) }\n"
|
|
186
|
+
end
|
|
187
|
+
if attribute.name == '_list_search'
|
|
188
|
+
@list_scopes << " scope :inline_forms_search, ->(q) { where(\"#{attribute.type} LIKE ?\", \"%\#{q}%\") }\n"
|
|
177
189
|
end
|
|
178
190
|
if attribute.attribute?
|
|
179
191
|
attribute.attribute_type == :unknown ? commenter = '#' : commenter = ' '
|
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
class ApplicationRecord < ActiveRecord::Base
|
|
2
2
|
self.abstract_class = true
|
|
3
3
|
|
|
4
|
+
# PaperTrail 16 defaults to `on: [:create, :update, :destroy, :touch]`.
|
|
5
|
+
# ActionText's `belongs_to :record, polymorphic: true, touch: true` (set by
|
|
6
|
+
# `has_rich_text`) calls `parent.touch` on every rich-text save, which
|
|
7
|
+
# produced a parent-side `update` version with an empty changeset — visible
|
|
8
|
+
# in the inline_forms versions panel as a meaningless "empty" row whose
|
|
9
|
+
# Restore link reifies the same state (no-op). Excluding `:touch` here
|
|
10
|
+
# suppresses that noise without affecting real attribute updates.
|
|
11
|
+
has_paper_trail on: [:create, :update, :destroy]
|
|
12
|
+
|
|
13
|
+
attr_writer :inline_forms_attribute_list
|
|
14
|
+
|
|
15
|
+
# will_paginate reads Klass.per_page (class level), not instance ivars.
|
|
16
|
+
self.per_page = 7
|
|
17
|
+
|
|
18
|
+
# Default list ordering for inline_forms #index/#create and nested
|
|
19
|
+
# associated lists. Subclasses override via
|
|
20
|
+
# scope :inline_forms_list, -> { order(:col, :id) }
|
|
21
|
+
# (typically emitted by `rails g inline_forms <Model> _list_order:<col>`).
|
|
22
|
+
# `all` is a no-op so the gem adds no ORDER BY by default; pair with
|
|
23
|
+
# explicit named scopes rather than `default_scope` so callers can
|
|
24
|
+
# `unscope`/`reorder` cleanly.
|
|
25
|
+
scope :inline_forms_list, -> { all }
|
|
26
|
+
|
|
27
|
+
# Default list search; no-op so the gem's search box is inert until a model
|
|
28
|
+
# opts in via
|
|
29
|
+
# scope :inline_forms_search, ->(q) { where("col LIKE ?", "%#{q}%") }
|
|
30
|
+
# (emitted by `_list_search:<col>` in the generator).
|
|
31
|
+
scope :inline_forms_search, ->(_q) { all }
|
|
32
|
+
|
|
4
33
|
# Wrapper for @model.human_attribute_name -> Model.human_attribute_name
|
|
5
34
|
def human_attribute_name(*args)
|
|
6
35
|
self.class.human_attribute_name(*args)
|
|
7
36
|
end
|
|
8
37
|
|
|
38
|
+
def self.not_accessible_through_html?
|
|
39
|
+
false
|
|
40
|
+
end
|
|
9
41
|
end
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
class <%= name %> < ApplicationRecord
|
|
2
|
-
attr_reader :per_page
|
|
3
|
-
@per_page = 7
|
|
4
|
-
attr_writer :inline_forms_attribute_list
|
|
5
|
-
# PaperTrail 16 defaults to `on: [:create, :update, :destroy, :touch]`.
|
|
6
|
-
# ActionText's `belongs_to :record, polymorphic: true, touch: true` (set by
|
|
7
|
-
# `has_rich_text`) calls `parent.touch` on every rich-text save, which
|
|
8
|
-
# produced a parent-side `update` version with an empty changeset — visible
|
|
9
|
-
# in the inline_forms versions panel as a meaningless "empty" row whose
|
|
10
|
-
# Restore link reifies the same state (no-op). Excluding `:touch` here
|
|
11
|
-
# suppresses that noise without affecting real attribute updates.
|
|
12
|
-
has_paper_trail on: [:create, :update, :destroy]
|
|
13
2
|
<%= @carrierwave_mounters if @carrierwave_mounters.length > 1 -%>
|
|
14
3
|
<%= @belongs_to if @belongs_to.length > 1 -%>
|
|
15
4
|
<%= @has_many if @has_many.length > 1 -%>
|
|
@@ -17,14 +6,18 @@ class <%= name %> < ApplicationRecord
|
|
|
17
6
|
<%= @habtm if @habtm.length > 1 -%>
|
|
18
7
|
<%= @has_rich_text if @has_rich_text.length > 1 -%>
|
|
19
8
|
<%= @has_attached_files if @has_attached_files.length > 1 -%>
|
|
9
|
+
<% if @list_scopes && !@list_scopes.empty? -%>
|
|
10
|
+
|
|
11
|
+
<%= @list_scopes -%>
|
|
12
|
+
<% end -%>
|
|
20
13
|
<%= @presentation if @presentation.length > 1 -%>
|
|
21
14
|
<%= @inline_forms_attribute_list -%>
|
|
22
15
|
<%= @order if @order.length > 1 -%>
|
|
16
|
+
<% if @flag_not_accessible_through_html -%>
|
|
23
17
|
|
|
24
18
|
def self.not_accessible_through_html?
|
|
25
|
-
|
|
19
|
+
true
|
|
26
20
|
end
|
|
27
|
-
|
|
28
|
-
<%= @order_by_clause -%>
|
|
21
|
+
<% end -%>
|
|
29
22
|
|
|
30
23
|
end
|
|
@@ -19,11 +19,9 @@ module InlineForms
|
|
|
19
19
|
|
|
20
20
|
def check_list_edit(object, attribute)
|
|
21
21
|
object.send(attribute).build if object.send(attribute).empty?
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
values = object.send(attribute).first.class.name.constantize.order(attribute.to_s.singularize.camelcase.constantize.order_by_clause)
|
|
26
|
-
end
|
|
22
|
+
klass = object.send(attribute).first.class
|
|
23
|
+
values = cancan_enabled? ? klass.accessible_by(current_ability) : klass.all
|
|
24
|
+
values = values.merge(klass.inline_forms_list) if klass.respond_to?(:inline_forms_list)
|
|
27
25
|
out = ''
|
|
28
26
|
values.each do | item |
|
|
29
27
|
out << "<div class='row #{cycle('odd', 'even')}'>"
|
data/lib/inline_forms/version.rb
CHANGED
|
@@ -36,6 +36,12 @@ class InlineFormsGeneratorTest < Minitest::Test
|
|
|
36
36
|
migration = read_single_migration_for("things")
|
|
37
37
|
|
|
38
38
|
assert_includes(model, "class Thing < ApplicationRecord")
|
|
39
|
+
refute_includes(model, "has_paper_trail")
|
|
40
|
+
refute_includes(model, "attr_reader :per_page")
|
|
41
|
+
refute_includes(model, 'def self.not_accessible_through_html?')
|
|
42
|
+
refute_includes(model, "def self.order_by_clause")
|
|
43
|
+
refute_includes(model, "scope :inline_forms_list")
|
|
44
|
+
refute_includes(model, "scope :inline_forms_search")
|
|
39
45
|
assert_includes(model, "belongs_to :category")
|
|
40
46
|
assert_includes(model, "has_many :photos")
|
|
41
47
|
assert_includes(model, "[ :name , \"name\", :text_field ]")
|
|
@@ -100,6 +106,61 @@ class InlineFormsGeneratorTest < Minitest::Test
|
|
|
100
106
|
refute_includes(migration, "t.text :content")
|
|
101
107
|
end
|
|
102
108
|
|
|
109
|
+
def test_not_accessible_and_list_order_emits_scope_and_spaceship
|
|
110
|
+
run_generator(
|
|
111
|
+
"Photo",
|
|
112
|
+
"name:string",
|
|
113
|
+
"album:belongs_to",
|
|
114
|
+
"_presentation:\\#{name}",
|
|
115
|
+
"_list_order:caption"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
model = read("app/models/photo.rb")
|
|
119
|
+
assert_includes(model, "def self.not_accessible_through_html?\n true")
|
|
120
|
+
assert_includes(model, "scope :inline_forms_list, -> { order(:caption, :id) }")
|
|
121
|
+
assert_includes(model, "def <=>(other)")
|
|
122
|
+
assert_includes(model, "self.caption <=> other.caption")
|
|
123
|
+
refute_includes(model, "def self.order_by_clause")
|
|
124
|
+
refute_includes(model, "has_paper_trail")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_legacy_order_alias_still_emits_scope_with_deprecation_warning
|
|
128
|
+
stdout, stderr = capture_io do
|
|
129
|
+
run_generator(
|
|
130
|
+
"Photo",
|
|
131
|
+
"name:string",
|
|
132
|
+
"_presentation:\\#{name}",
|
|
133
|
+
"_order:caption"
|
|
134
|
+
)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
output = "#{stdout}#{stderr}"
|
|
138
|
+
assert_includes(output, "_order:caption is deprecated")
|
|
139
|
+
assert_includes(output, "_list_order:caption")
|
|
140
|
+
|
|
141
|
+
model = read("app/models/photo.rb")
|
|
142
|
+
assert_includes(model, "scope :inline_forms_list, -> { order(:caption, :id) }")
|
|
143
|
+
refute_includes(model, "def self.order_by_clause")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_list_search_emits_search_scope
|
|
147
|
+
run_generator(
|
|
148
|
+
"Apartment",
|
|
149
|
+
"name:string",
|
|
150
|
+
"_enabled:yes",
|
|
151
|
+
"_list_order:name",
|
|
152
|
+
"_list_search:name",
|
|
153
|
+
"_presentation:\\#{name}"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
model = read("app/models/apartment.rb")
|
|
157
|
+
assert_includes(model, "scope :inline_forms_list, -> { order(:name, :id) }")
|
|
158
|
+
assert_includes(model, "scope :inline_forms_search, ->(q) { where(\"name LIKE ?\", \"%\#{q}%\") }")
|
|
159
|
+
migration = read_single_migration_for("apartments")
|
|
160
|
+
refute_includes(migration, "_list_order")
|
|
161
|
+
refute_includes(migration, "_list_search")
|
|
162
|
+
end
|
|
163
|
+
|
|
103
164
|
def test_plain_text_generates_text_column_and_plain_text_form_element
|
|
104
165
|
run_generator("Note", "title:string", "description:plain_text")
|
|
105
166
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inline_forms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ace Suares
|
|
@@ -17,7 +17,7 @@ dependencies:
|
|
|
17
17
|
requirements:
|
|
18
18
|
- - ">="
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
|
-
version: 8.0
|
|
20
|
+
version: 8.1.0
|
|
21
21
|
- - "<"
|
|
22
22
|
- !ruby/object:Gem::Version
|
|
23
23
|
version: '9.0'
|
|
@@ -27,7 +27,7 @@ dependencies:
|
|
|
27
27
|
requirements:
|
|
28
28
|
- - ">="
|
|
29
29
|
- !ruby/object:Gem::Version
|
|
30
|
-
version: 8.0
|
|
30
|
+
version: 8.1.0
|
|
31
31
|
- - "<"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '9.0'
|
|
@@ -492,18 +492,8 @@ files:
|
|
|
492
492
|
- archived/form_elements/tree/app/helpers/form_elements/move.rb
|
|
493
493
|
- archived/form_elements/tree/app/views/inline_forms/_show_tree.html.erb
|
|
494
494
|
- archived/form_elements/tree/app/views/inline_forms/_tree.html.erb
|
|
495
|
-
- docs/git-deps-assessment.md
|
|
496
|
-
- docs/jquery-widgets.md
|
|
497
|
-
- docs/prompt/.gitignore
|
|
498
|
-
- docs/prompt/test-the-example-app.md
|
|
499
|
-
- docs/rails-8-phase4-audit.md
|
|
500
|
-
- docs/rails-8-release.md
|
|
501
|
-
- docs/turbo-stream-audit.md
|
|
502
|
-
- docs/ujs-to-turbo.md
|
|
503
|
-
- docs/zeitwerk-and-load-paths.md
|
|
504
495
|
- inline_forms.gemspec
|
|
505
496
|
- lib/generators/USAGE
|
|
506
|
-
- lib/generators/assets/stylesheets/inline_forms.scss
|
|
507
497
|
- lib/generators/assets/stylesheets/inline_forms_devise.css
|
|
508
498
|
- lib/generators/inline_forms_generator.rb
|
|
509
499
|
- lib/generators/templates/_inline_forms_tabs.html.erb
|
data/docs/git-deps-assessment.md
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Git-sourced installer dependencies — assessment
|
|
2
|
-
|
|
3
|
-
**Date:** 2026-05-19
|
|
4
|
-
**Context:** Generated apps from `inline_forms create` used three non-RubyGems pins: `tabs_on_rails` (git + branch), `i18n-active_record` (git), and a commented `will_paginate` fork. This doc records why they existed and what replaced them.
|
|
5
|
-
|
|
6
|
-
**Related (risk callouts only):** `validation_hints/stuff/rails-7.2-zeitwerk-plan.md` (Track A3), `validation_hints/stuff/rails-8-checklist.md` (Phase 3).
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Summary (7.13.5+)
|
|
11
|
-
|
|
12
|
-
| Gem | Was | Now | Reason |
|
|
13
|
-
|-----|-----|-----|--------|
|
|
14
|
-
| `will_paginate` | RubyGems + commented acesuares fork | RubyGems only | Fork never active; comment removed |
|
|
15
|
-
| `tabs_on_rails` | `acesuares/tabs_on_rails` branch `update_remote_before_action` | `~> 3.0` (weppos, RubyGems) | Fork only added unused `:remote` on tab links; upstream 3.0.0 already uses `before_action` |
|
|
16
|
-
| `i18n-active_record` | `acesuares/i18n-active_record` (2012) | **Removed** (7.13.18: no DB translation tables) | Never configured `I18n.backend`; DB tables/view and `extract_translations` removed |
|
|
17
|
-
|
|
18
|
-
**No generated-app Gemfile should use `:git` for these anymore.**
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## `will_paginate`
|
|
23
|
-
|
|
24
|
-
- **Fork:** `https://github.com/acesuares/will_paginate.git` (commented out for years).
|
|
25
|
-
- **Usage:** Nested/top-level list pagination in `_list.html.erb`; Turbo Frame nav since 7.5.x (no `:remote => true`).
|
|
26
|
-
- **Verdict:** RubyGems `will_paginate` is sufficient. No acesuares-specific behavior required.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## `tabs_on_rails`
|
|
31
|
-
|
|
32
|
-
### Why the fork existed
|
|
33
|
-
|
|
34
|
-
Branch `update_remote_before_action` on `acesuares/tabs_on_rails` (2019) did two things:
|
|
35
|
-
|
|
36
|
-
1. `before_filter` → `before_action` (Rails 4+ rename).
|
|
37
|
-
2. Optional `:remote => true` on `tab_for` links (`tabs_builder.rb`).
|
|
38
|
-
|
|
39
|
-
### What inline_forms actually uses
|
|
40
|
-
|
|
41
|
-
- Controllers call **`set_tab :resource`** only (generator template + installer).
|
|
42
|
-
- Top bar is **not** built with `tabs_tag` / `tab_for`; `_inline_forms_tabs.html.erb` is a Foundation top-bar with search + new button.
|
|
43
|
-
- Turbo migration removed **`data-remote`** from inline UI; no code passes `:remote` into tabs.
|
|
44
|
-
|
|
45
|
-
### Upstream today
|
|
46
|
-
|
|
47
|
-
- **RubyGems:** `tabs_on_rails` **3.0.0** (weppos, 2017).
|
|
48
|
-
- **`set_tab`** already uses **`before_action`** in `lib/tabs_on_rails/action_controller.rb`.
|
|
49
|
-
- **Missing vs fork:** `:remote` on tab links only — **unused by inline_forms**.
|
|
50
|
-
|
|
51
|
-
### Verdict
|
|
52
|
-
|
|
53
|
-
**Use `gem 'tabs_on_rails', '~> 3.0'`.** No runtime dependency on the fork. Re-test on Rails 7.2+ / 8.0 when upgrading (gem is unmaintained but tiny).
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## `i18n-active_record`
|
|
58
|
-
|
|
59
|
-
### History
|
|
60
|
-
|
|
61
|
-
- Fork existed because MySQL reserves `KEY`; acesuares fork used **`thekey`**.
|
|
62
|
-
- **7.13.5–7.13.17:** gem removed from Gemfile; installer still generated locale/key/translation tables + `translations` view; **`InlineForms::TranslationRecord`** read the view; **`extract_translations`** exported YAML (never routed by default).
|
|
63
|
-
- **`I18n.backend` was never** `I18n::Backend::ActiveRecord` in generated apps.
|
|
64
|
-
|
|
65
|
-
### Verdict (7.13.18+)
|
|
66
|
-
|
|
67
|
-
**No DB translation layer.** Generated apps use Rails I18n YAML only (`config/locales/inline_forms_local.en.yml`, etc.). If **I18n::Backend::ActiveRecord** is needed later, add **`i18n-active_record ~> 1.4`** and migrations separately—not via inline_forms installer.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Previously removed forks (reference)
|
|
72
|
-
|
|
73
|
-
| Gem | Removed in | Replacement |
|
|
74
|
-
|-----|------------|-------------|
|
|
75
|
-
| `devise-i18n` | 7.3.4 / 7.10+ | RubyGems `~> 1.16` |
|
|
76
|
-
| `paper_trail` | 7.0.x | RubyGems `~> 16.0` |
|
|
77
|
-
| `switch_user` | 7.2.x | Removed from installer |
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## Verification
|
|
82
|
-
|
|
83
|
-
After changing `installer_core.rb`:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
cd /home/code/inline_forms && rvm use . && gem build inline_forms.gemspec && gem build inline_forms_installer.gemspec
|
|
87
|
-
cd /home/code/testInline && rvm use .
|
|
88
|
-
gem install /home/code/inline_forms/inline_forms-*.gem /home/code/inline_forms/inline_forms_installer-*.gem
|
|
89
|
-
rm -rf MyApp && inline_forms create MyApp -d sqlite --example
|
|
90
|
-
cd MyApp && rvm use . && bundle exec rails test
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Expect **0 failures**; `Gemfile.lock` should list `tabs_on_rails (3.0.0)` and **no** `i18n-active_record` git source.
|
data/docs/jquery-widgets.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# jQuery widget migration (Phase 4)
|
|
2
|
-
|
|
3
|
-
UJS removal (7.8.0) is complete. These jQuery-based widgets remain in the Sprockets bundle:
|
|
4
|
-
|
|
5
|
-
| Widget | Asset | Status |
|
|
6
|
-
|--------|-------|--------|
|
|
7
|
-
| Datepicker | `jquery.ui.all` | **Centralized** — `initInlineFormsWidgets` in `inline_forms.js`; helpers use `class="datepicker"` only |
|
|
8
|
-
| Month/year picker | jQuery UI datepicker | **Centralized** — `class="datepicker datepicker-month-year"` |
|
|
9
|
-
| Timepicker | `jquery.timepicker.js` | **Centralized** — `class="timepicker"` |
|
|
10
|
-
| Autocomplete | `autocomplete-rails` + inline scripts in `dropdown_with_other` | Still inline / jQuery UI |
|
|
11
|
-
| Foundation | `foundation` jQuery plugin | Required for layout chrome |
|
|
12
|
-
|
|
13
|
-
## Central init (7.9.8+)
|
|
14
|
-
|
|
15
|
-
`initInlineFormsWidgets(root)` runs on:
|
|
16
|
-
|
|
17
|
-
- DOM ready (after `$.datepicker.setDefaults`)
|
|
18
|
-
- `turbo:load`
|
|
19
|
-
- `turbo:frame-load`
|
|
20
|
-
|
|
21
|
-
Form element `_edit` helpers must **not** emit per-field `<script>` tags; class hooks only.
|
|
22
|
-
|
|
23
|
-
## Future removal (not started)
|
|
24
|
-
|
|
25
|
-
Replace with Stimulus or vanilla + `turbo:frame-load` one widget at a time; keep example-app tests green after each.
|
data/docs/prompt/.gitignore
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
You are in the inline_forms gem repo at /home/code/inline_forms.
|
|
2
|
-
|
|
3
|
-
Goal:
|
|
4
|
-
Build the current gem, install it into /home/code/testInline, recreate MyApp from scratch using --example, and verify it with Rails tests.
|
|
5
|
-
|
|
6
|
-
Do all steps end-to-end without asking for confirmation unless a command fails.
|
|
7
|
-
|
|
8
|
-
Steps:
|
|
9
|
-
1) In /home/code/inline_forms:
|
|
10
|
-
- Ensure latest code is used.
|
|
11
|
-
- Run: rvm use .
|
|
12
|
-
- Build gems: gem build inline_forms.gemspec && gem build inline_forms_installer.gemspec
|
|
13
|
-
- Confirm the built file names/versions (inline_forms-<version>.gem, inline_forms_installer-<version>.gem).
|
|
14
|
-
|
|
15
|
-
2) In /home/code/testInline:
|
|
16
|
-
- Remove old app if present: /home/code/testInline/MyApp
|
|
17
|
-
- Run: rvm use .
|
|
18
|
-
- Install the freshly built gems from /home/code/inline_forms/inline_forms-<version>.gem and inline_forms_installer-<version>.gem
|
|
19
|
-
|
|
20
|
-
3) Still in /home/code/testInline:
|
|
21
|
-
- Generate fresh example app:
|
|
22
|
-
inline_forms create MyApp -d sqlite --example
|
|
23
|
-
|
|
24
|
-
4) In /home/code/testInline/MyApp:
|
|
25
|
-
- Run: rvm use .
|
|
26
|
-
- Run verification: bundle exec rails test
|
|
27
|
-
|
|
28
|
-
Output requirements:
|
|
29
|
-
- Briefly report each phase result (build, install, app generation, test run).
|
|
30
|
-
- Include exact commands run.
|
|
31
|
-
- Include test summary (runs/assertions/failures/errors/skips).
|
|
32
|
-
- If anything fails, stop at the failing step and include the exact error and the next corrective command you recommend.
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Rails 8 — Phase 4 audit (framework defaults & cleanup)
|
|
2
|
-
|
|
3
|
-
**Date:** 2026-05-22
|
|
4
|
-
**Scope:** Post–Phase 3 (`inline_forms` 8.0.2 installer + example app gate).
|
|
5
|
-
|
|
6
|
-
## 4.1 Framework defaults (`rails new` 8.0.5)
|
|
7
|
-
|
|
8
|
-
Vanilla `rails _8.0.5_ new` (importmap, `--skip-bundle`):
|
|
9
|
-
|
|
10
|
-
- `config/application.rb`: `config.load_defaults 8.0`, `config.autoload_lib(ignore: %w[assets tasks])`
|
|
11
|
-
- Generator **removes** `config/initializers/new_framework_defaults_8_0.rb` (opt-in flags live only in the railties template until uncommented)
|
|
12
|
-
- Optional 8.0 toggles (all commented in upstream template): `active_support.to_time_preserves_timezone`, `action_dispatch.strict_freshness`, `Regexp.timeout`
|
|
13
|
-
|
|
14
|
-
**Installer decision:** Match vanilla Rails 8 — rely on `load_defaults 8.0` only; do **not** ship `new_framework_defaults_8_0.rb` in generated apps. Keep a belt-and-suspenders `gsub` to `load_defaults 8.0` if an older `rails new` left another minor.
|
|
15
|
-
|
|
16
|
-
## 4.2 Rails 8 API / deprecation grep
|
|
17
|
-
|
|
18
|
-
| Area | Result |
|
|
19
|
-
|------|--------|
|
|
20
|
-
| `form_with` / `model: nil` | No engine usage; inline fields use custom helpers / Turbo, not `form_with` |
|
|
21
|
-
| `form_for` | Devise templates only (upstream Devise 5) |
|
|
22
|
-
| `ActiveRecord::Base.connection` | Unicorn `before_fork` template updated → `connection_pool.disconnect!` |
|
|
23
|
-
| `ActionController` deprecated flags | None in `lib/` |
|
|
24
|
-
| Generator migrations | `ActiveRecord::Migration[8.0]` (tests assert) |
|
|
25
|
-
|
|
26
|
-
## 4.3 Dart Sass / SCSS
|
|
27
|
-
|
|
28
|
-
Foundation + engine SCSS still emit Dart Sass 1.x deprecation warnings during `dartsass:build`. Accepted for 8.0 ship; migrate to `@use` / `color.scale` before Dart Sass 3.0 (see `stuff/pipeline.md`).
|
|
29
|
-
|
|
30
|
-
## 4.4 bundler-audit
|
|
31
|
-
|
|
32
|
-
| Lockfile | Result (2026-05-22) |
|
|
33
|
-
|----------|---------------------|
|
|
34
|
-
| `validation_hints/Gemfile.lock` | No vulnerabilities found |
|
|
35
|
-
| Example app `MyApp/Gemfile.lock` | No vulnerabilities found (`bundler-audit` on default gemset) |
|
|
36
|
-
|
|
37
|
-
## 4.5 Example app gate (unchanged baseline)
|
|
38
|
-
|
|
39
|
-
`inline_forms create MyApp -d sqlite --example` → **88 runs, 502 assertions, 0 failures, 0 errors, 0 skips** (Phase 3, Rails 8.0.5 stack).
|