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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 122426ec8aafea8e48c9693153e155891b9f97cb73a40983a0bdcf21051acc26
4
- data.tar.gz: bbf2a4dacbfa14d9cf84cab79de9356f5623542e28029aa18f000fe25c21b432
3
+ metadata.gz: 51bf71fc0e838244f70a9a53db6cfe0a3515cda9e43086bfded9a08c9b56b144
4
+ data.tar.gz: 85796e1ea1d4dcc5d1afb094e67e045279ba862590e7bb25472e496eadd628ae
5
5
  SHA512:
6
- metadata.gz: 043a09c0faaedf4d13ecc8ea20cf6b772709fc20237c7a6e87da188a2392045fab619a7b589a2966ae7f9fa49bc27e5f1caa37778b86605842595ccd74c4f56d
7
- data.tar.gz: eaa601424c02655fdec7721a81f5f48af2674d58077e2325f2c1ccab49375d60f1dea794891a86dd7d85e7e3c3b2cebb8fad26fedaa2cded1fe2326f65fd9a27
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.respond_to?(:inline_forms_list)
55
- relation.merge(klass.inline_forms_list)
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,
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  module InlineForms
4
- VERSION = "8.1.59"
4
+ VERSION = "8.1.60"
5
5
  end
@@ -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
 
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.1.59
4
+ version: 8.1.60
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Suares