inline_forms 8.1.59 → 8.1.60
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 +22 -0
- data/lib/generators/templates/application_record.rb +2 -1
- data/lib/inline_forms/dropdown_order.rb +10 -4
- data/lib/inline_forms/form_elements/check_list_helper.rb +3 -0
- data/lib/inline_forms/form_elements/dropdown_helper.rb +2 -1
- data/lib/inline_forms/version.rb +1 -1
- data/test/integration/dropdown_test.rb +42 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 51bf71fc0e838244f70a9a53db6cfe0a3515cda9e43086bfded9a08c9b56b144
|
|
4
|
+
data.tar.gz: 85796e1ea1d4dcc5d1afb094e67e045279ba862590e7bb25472e496eadd628ae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b674c30e72e0ac91aebe7cbe9c619cece169be0098faa9a1e50693831eb937ae4f572b363beb26678f9caa3d6c4ceb7f368aa9127ebd310f22a996b6d36fc4a
|
|
7
|
+
data.tar.gz: e08e0398a885ca964e6403f379e4d293da09d02b204728f709aaf728ed2ee873666899f87d1408843152d3e089aa8ff3c12a9fb028246194a0df8f0b64400b0e
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [8.1.60] - 2026-10-28
|
|
8
|
+
|
|
9
|
+
Fixes from a review of 8.1.58 and 8.1.59.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Dropdowns take only the order from `inline_forms_list`.** 8.1.59's rule 3 merged the whole `inline_forms_list` scope into `dropdown` and `dropdown_with_other`, so a `where` or `joins` there hid records from the dropdown. A record whose current value was hidden showed the first option instead, and saving the inline form silently changed it. Rule 3 now uses only the scope's ORDER BY (added to a `default_scope` order, as the merge did). The scope still filters `/index`.
|
|
14
|
+
- **`check_list` keeps the `inline_forms_list` filter.** Under rules 1 and 2 (a declared order or a `dropdown_order` column) 8.1.59 skipped the scope, so `check_list` listed records its `where` used to hide. It now applies the scope's filter under every rule, as before 8.1.59; the order is still `InlineForms::DropdownOrder`'s.
|
|
15
|
+
- **A `dropdown` whose lookup defines `disabled_for_dropdown?` loads the lookup once.** 8.1.59 loaded it to find the disabled options and again, ordered, for the options.
|
|
16
|
+
- **Installer: a gem path with a space no longer breaks the Dart Sass build.** 8.1.58's initializer put the gem's stylesheet dir first as a `build_options` entry, and dartsass-rails splits those on whitespace, so a gem installed under e.g. `/Users/John Doe/…` gave Sass two broken arguments. `config/initializers/inline_forms_dartsass_builds.rb` now prepends the dir to `Dartsass::Runner`'s own `--load-path` list as a separate argument, still ahead of `app/assets/builds`. Apps generated with 8.1.58 or 8.1.59 can copy the new initializer from the installer's `lib/installer_templates/dartsass/`.
|
|
17
|
+
- **Example app: rolling back the seed migration works.** Its `down` destroyed the seeded owners while the seeded apartments still pointed at them, and `apartments.owner_id` / `apartments.phase_id` have foreign keys, so `Owner#destroy` raised `ActiveRecord::InvalidForeignKey`. It now sets those columns to NULL on every apartment that points at a seeded owner or phase before destroying it.
|
|
18
|
+
- The installer's `ApplicationRecord` template says rule 3 is the ORDER BY of `inline_forms_list`.
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
|
|
22
|
+
- `dropdown_test`: a filtering `inline_forms_list` orders a dropdown without hiding records, `check_list` keeps that filter under a declared order, and `disabled_for_dropdown?` costs no second query.
|
|
23
|
+
- Example app: `example_app_dartsass_build_test` checks that the gem's stylesheet dir is the first `--load-path` and a separate argument.
|
|
24
|
+
|
|
25
|
+
### Lockstep
|
|
26
|
+
|
|
27
|
+
- validation_hints 8.1.60, inline_forms_installer 8.1.60, inline_forms_schema_edit 8.1.60.
|
|
28
|
+
|
|
7
29
|
## [8.1.59] - 2026-10-22
|
|
8
30
|
|
|
9
31
|
### Fixed
|
|
@@ -31,7 +31,8 @@ class ApplicationRecord < ActiveRecord::Base
|
|
|
31
31
|
# 1. inline_forms_dropdown_order :col # or :col, :desc
|
|
32
32
|
# 2. a `dropdown_order` integer column, ascending (e.g. '---' 0,
|
|
33
33
|
# 'helprequest' 10, 'decision' 20, 'admittance' 30)
|
|
34
|
-
# 3. inline_forms_list above
|
|
34
|
+
# 3. the order of inline_forms_list above (only its ORDER BY: a where
|
|
35
|
+
# there filters #index, not the dropdowns)
|
|
35
36
|
# 4. database order
|
|
36
37
|
# 1 and 2 put NULLs last and break ties on id.
|
|
37
38
|
|
|
@@ -7,11 +7,13 @@ module InlineForms
|
|
|
7
7
|
# 1. the model declares `inline_forms_dropdown_order :column, :asc|:desc`;
|
|
8
8
|
# 2. the table has a `dropdown_order` column (ascending), so a lookup can
|
|
9
9
|
# put '---' / 'onbekend' first and process phases in process order;
|
|
10
|
-
# 3. the model's `inline_forms_list` scope (its list order
|
|
10
|
+
# 3. the ORDER BY of the model's `inline_forms_list` scope (its list order;
|
|
11
|
+
# only the order: a where/joins in that scope does not hide records here);
|
|
11
12
|
# 4. database order (a default_scope order included).
|
|
12
13
|
#
|
|
13
14
|
# 1 and 2 replace any default_scope order, put NULLs last (a record nobody
|
|
14
|
-
# numbered yet goes to the end) and break ties on the primary key.
|
|
15
|
+
# numbered yet goes to the end) and break ties on the primary key. 3 adds to
|
|
16
|
+
# a default_scope order, as merging the scope did.
|
|
15
17
|
#
|
|
16
18
|
# The macro is on every Active Record model (engine initializer), so hosts
|
|
17
19
|
# need no ApplicationRecord change.
|
|
@@ -51,11 +53,15 @@ module InlineForms
|
|
|
51
53
|
keys = [ table[column].public_send(direction).nulls_last ]
|
|
52
54
|
keys << table[klass.primary_key].asc if klass.primary_key && klass.primary_key != column
|
|
53
55
|
relation.reorder(*keys)
|
|
54
|
-
elsif klass.
|
|
55
|
-
relation.
|
|
56
|
+
elsif (list_order = list_order_values(klass)).any?
|
|
57
|
+
relation.order(*list_order)
|
|
56
58
|
else
|
|
57
59
|
relation
|
|
58
60
|
end
|
|
59
61
|
end
|
|
62
|
+
|
|
63
|
+
def self.list_order_values(klass)
|
|
64
|
+
klass.respond_to?(:inline_forms_list) ? klass.inline_forms_list.order_values : []
|
|
65
|
+
end
|
|
60
66
|
end
|
|
61
67
|
end
|
|
@@ -21,6 +21,9 @@ module InlineForms
|
|
|
21
21
|
object.send(attribute).build if object.send(attribute).empty?
|
|
22
22
|
klass = object.send(attribute).first.class
|
|
23
23
|
values = cancan_enabled? ? klass.accessible_by(current_ability) : klass.all
|
|
24
|
+
# check_list has always applied the list scope's filter (a where in
|
|
25
|
+
# inline_forms_list hides records here); the order is DropdownOrder's.
|
|
26
|
+
values = values.merge(klass.inline_forms_list.unscope(:order)) if klass.respond_to?(:inline_forms_list)
|
|
24
27
|
values = InlineForms::DropdownOrder.apply(values)
|
|
25
28
|
out = ''
|
|
26
29
|
values.each do | item |
|
|
@@ -25,11 +25,12 @@ module InlineForms
|
|
|
25
25
|
else
|
|
26
26
|
values = klass.all
|
|
27
27
|
end
|
|
28
|
+
values = InlineForms::DropdownOrder.apply(values)
|
|
28
29
|
options_disabled = nil
|
|
29
30
|
if klass.method_defined? :disabled_for_dropdown?
|
|
31
|
+
# loads values; collection_select below reuses the loaded records
|
|
30
32
|
options_disabled = values.map{|v| v.id if v.disabled_for_dropdown?}.compact
|
|
31
33
|
end
|
|
32
|
-
values = InlineForms::DropdownOrder.apply(values)
|
|
33
34
|
# the leading underscore is to avoid name conflicts, like 'email' and 'email_type' will result in 'email' and 'email[email_type_id]' in the form!
|
|
34
35
|
collection_select( ('_' + object.class.to_s.underscore).to_sym,
|
|
35
36
|
attribute.to_s.foreign_key.to_sym,
|
data/lib/inline_forms/version.rb
CHANGED
|
@@ -10,6 +10,11 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
10
10
|
[ Phase, Machine, Kind, Part ].each do |klass|
|
|
11
11
|
klass.remove_instance_variable(:@inline_forms_dropdown_order) if klass.instance_variable_defined?(:@inline_forms_dropdown_order)
|
|
12
12
|
end
|
|
13
|
+
# Back to ApplicationRecord's `inline_forms_list -> { all }`.
|
|
14
|
+
[ Kind, Part ].each do |klass|
|
|
15
|
+
klass.singleton_class.remove_method(:inline_forms_list) if klass.singleton_class.method_defined?(:inline_forms_list, false)
|
|
16
|
+
end
|
|
17
|
+
Phase.remove_method(:disabled_for_dropdown?) if Phase.method_defined?(:disabled_for_dropdown?, false)
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
def view
|
|
@@ -76,6 +81,32 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
76
81
|
assert_equal %w[Zeta Alpha], InlineForms::DropdownOrder.apply(Kind.all).map(&:name)
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
test "a filtering inline_forms_list only orders a dropdown, it hides no records" do
|
|
85
|
+
%w[Zeta Hidden Alpha].each { |name| Kind.create!(name: name) }
|
|
86
|
+
Kind.define_singleton_method(:inline_forms_list) { where.not(name: "Hidden").order(:name, :id) }
|
|
87
|
+
|
|
88
|
+
html = view.dropdown_with_other_edit(Widget.create!(name: "W"), :kind)
|
|
89
|
+
|
|
90
|
+
assert_equal %w[Alpha Hidden Zeta], html.scan(/<option value="([^"]*)">/).flatten
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
test "disabled_for_dropdown? and the options come from one query" do
|
|
94
|
+
create_phases
|
|
95
|
+
Phase.define_method(:disabled_for_dropdown?) { name == "decision" }
|
|
96
|
+
selects = []
|
|
97
|
+
counter = ->(*, payload) { selects << payload[:sql] if payload[:sql].match?(/\ASELECT .*FROM "phases"/) }
|
|
98
|
+
|
|
99
|
+
view_context, part = view, Part.create!(name: "Gear")
|
|
100
|
+
|
|
101
|
+
html = ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
|
102
|
+
view_context.dropdown_edit(part, :phase)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
assert_equal 1, selects.size, selects.join("\n")
|
|
106
|
+
assert_match(/<option disabled="disabled" value="\d+">decision</, html)
|
|
107
|
+
assert_equal [ "---", "helprequest", "decision", "admittance", "nieuw" ], option_texts(html)
|
|
108
|
+
end
|
|
109
|
+
|
|
79
110
|
test "dropdown_with_other offers its datalist in the dropdown order" do
|
|
80
111
|
%w[Zeta Alpha Mu].each { |name| Kind.create!(name: name) }
|
|
81
112
|
Kind.inline_forms_dropdown_order :name
|
|
@@ -95,6 +126,17 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
95
126
|
assert_equal %w[Nut Bolt Axle], html.scan(%r{<label for=[^>]*>([^<]*)</label>}).flatten.reject(&:empty?)
|
|
96
127
|
end
|
|
97
128
|
|
|
129
|
+
test "check_list keeps the inline_forms_list filter under a declared order" do
|
|
130
|
+
machine = Machine.create!(name: "Press")
|
|
131
|
+
%w[Bolt Hidden Nut Axle].each { |name| Part.create!(name: name) }
|
|
132
|
+
Part.define_singleton_method(:inline_forms_list) { where.not(name: "Hidden").order(:name) }
|
|
133
|
+
Part.inline_forms_dropdown_order :name, :desc
|
|
134
|
+
|
|
135
|
+
html = view.check_list_edit(machine, :parts)
|
|
136
|
+
|
|
137
|
+
assert_equal %w[Nut Bolt Axle], html.scan(%r{<label for=[^>]*>([^<]*)</label>}).flatten.reject(&:empty?)
|
|
138
|
+
end
|
|
139
|
+
|
|
98
140
|
test "an unknown direction or column is refused" do
|
|
99
141
|
assert_raises(ArgumentError) { Phase.inline_forms_dropdown_order :name, :up }
|
|
100
142
|
|