inline_forms 8.1.8 → 8.1.10

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: 6faae45fc3c25f20b57cc614e61e77a5264c1d866a5fde22a6e634c639fb54b9
4
- data.tar.gz: a30324d9cc1f598b4a9c5531f0b4fa45fe47186d2a07b8fc956e38c988a52872
3
+ metadata.gz: 03b05e4fb178ef02526d7fc573fa698dac22cb9061314ad84a03c70967b872f7
4
+ data.tar.gz: 8853ac3bfe3815ce88d9b1448e75176a500ff36c046b4d3fda974d2fe56fb194
5
5
  SHA512:
6
- metadata.gz: 9777058054bb9d8e1ff3213e0fd7bf420fd060f69a43005aef71e2fc9088aa58ccfb0e60aaa5ac4d57739aaa555bb01820bb1cc328d31543295ca8377c476eff
7
- data.tar.gz: 3f938ebcb879f72cecd60bd0c2e8eab47c1d01c410c7e32c137953e8f925cda614ce1b32e418bd887d0c833aaeecb0909fb9ba73c75911742473b22cfc9e186c
6
+ metadata.gz: 48459f5b60427af52f97574d7d1d8c774cf179f10dd7d0849e5c07a2a3e32243e46f0ccb9e09f4d7295513138e85105e929d22d68da1b14e4fd8771b9dce85d8
7
+ data.tar.gz: 7196bf92ee6c2357e6c11511a85254fdca7675cc715653f12f30d63dd212df8a1e409c69848428d4ac86fcfa088e019dce8f82678ecc8228994f94ddf5455d9a
data/CHANGELOG.md CHANGED
@@ -4,6 +4,45 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [8.1.10] - 2026-05-27
8
+
9
+ ### Changed
10
+
11
+ - **`:decimal_field` is now a real `decimal(p, s)` column instead of a `varchar`.** The FormElementRegistry mapping moves from `:decimal_field => :string` to `:decimal_field => :decimal`, so `rails g inline_forms Foo price:decimal_field` now emits `t.decimal :price, precision: 10, scale: 2` (the sensible default — invoice/balance up to 99,999,999.99). This closes a long-standing inconsistency: `decimal_field` was the only "numeric" Tier 1 helper that stored its value as text, so `"ace"` would happily round-trip and `Foo.sum(:price)` was a runtime cast error. Existing apps generated before 8.1.10 keep their varchar columns until they migrate; only newly-generated tables get `:decimal`.
12
+ - **New CLI syntax: `name:decimal_field{p,s}` overrides precision/scale.** Mirrors Rails' built-in `name:decimal{p,s}` grammar. Examples: `latitude:decimal_field{9,6}` -> `decimal(9, 6)` (~11 cm GPS accuracy), `longitude:decimal_field{10,6}` -> `decimal(10, 6)`, `dose:decimal_field{6,3}` -> `decimal(6, 3)`. Rails' own `Rails::Generators::GeneratedAttribute.parse` only honors `{…}` on a hardcoded list of built-in types and glues the braces onto custom types as part of the type symbol; `inline_forms_attribute_overrides.rb` now pre-processes the suffix off `:decimal_field` and stores precision/scale in `attr_options` for the migration emitter to read.
13
+ - **`decimal_field_show` / `_edit` render `BigDecimal` as fixed-point.** Once the column became a real `:decimal`, `object[attribute]` started returning `BigDecimal`, whose `to_s` defaults to scientific notation (`"0.1234e2"`). Both helpers now call `value.to_s("F")` for BigDecimal and fall through to the generic `to_s` for legacy varchar values, so existing apps display correctly with either column shape.
14
+
15
+ ### Added
16
+
17
+ - **`FormElementShowcase` demos the new `{p,s}` syntax.** Two new attributes (`latitude:decimal_field{9,6}`, `longitude:decimal_field{10,6}`) sit alongside `price:decimal_field` in the "Numbers" header, exercising both the default `(10, 2)` and explicit overrides. Seed values are Curaçao's Willemstad coordinates (`12.123456 / -68.987654`) — exactly representable in the chosen scale so the round-trip test is bit-identical rather than float-fuzzy.
18
+ - **`validates :price, latitude, longitude, numericality: …` in the showcase model.** Without an explicit validation, ActiveRecord silently casts `"ace"` to `BigDecimal("0")` on a `:decimal` column. The validation keeps the round-trip honest (the new integration test asserts a 422 on `"ace"`), and the `:latitude` / `:longitude` validations also pin the lat/lon ranges (±90, ±180).
19
+ - **Model + integration tests** cover the precision/scale schema (`columns_hash["latitude"].precision == 9`), the BigDecimal round-trip at full scale, the rejection of out-of-range GPS values, and the rejection of non-numeric input.
20
+
21
+ ### Lockstep
22
+
23
+ - `inline_forms`, `inline_forms_installer`, and `validation_hints` bumped from 8.1.9 to 8.1.10 in lockstep, even though `validation_hints` has no behavior change in this release.
24
+
25
+ ## [8.1.9] - 2026-05-27
26
+
27
+ ### Fixed
28
+
29
+ - **`dropdown_with_values_show` and `dropdown_with_values_info` double-translated their labels.** `attribute_values` already runs each label through `t()` (it has to, so the values hash can use translation keys). The two show/info helpers then ran `t()` again on the *already-translated* string, so a missing translation rendered a bizarre `<span class="translation_missing" title="Low&quot;&gt;Low&lt;/Span&gt;">Low"&gt;Low&lt;/Span&gt;</span>` blob inside the inline-edit link (visible on `priority` / `priority2` in the showcase). The second `t()` call has been removed and the helpers now nil-guard the lookup, matching the 8.1.7 fixes to `dropdown_with_integers_show` and the two scale helpers.
30
+ - **`money_field_show` dropped cents on whole-dollar amounts.** money-rails defaults `humanized_money_with_symbol` to `no_cents_if_whole: true`, so `Money.from_amount(124.00, "USD")` rendered as `$124` while `Money.from_amount(12.34, "USD")` rendered as `$12.34` — inconsistent, and indistinguishable from a precision bug on values that *rounded* to a whole dollar (e.g. `Money.from_amount(123.999, "USD")` rounds up to 12400 cents because cents are the smallest Money unit; the helper now shows that as `$124.00`). The helper now passes `no_cents_if_whole: false` so the displayed amount always has two decimals.
31
+
32
+ ### Changed
33
+
34
+ - **`FormElementShowcase` now demos `[:locales, :check_list]` + `[:locales_display, :info_list]` instead of `[:roles, :info_list]`.** Role is reserved for the auth Member/User model — reusing it on the showcase coincidentally shared rows with `roles_users` and obscured how the demo associations were coupled. The example app now seeds four locales (`en`/`nl`/`de`/`fr`, English is the default attached to the full demo) and a `has_and_belongs_to_many :locales` join, so the showcase exercises the editable HABTM editor (`check_list`) and the read-only mirror (`info_list`) side-by-side. The read-only row uses `alias_method :locales_display, :locales` because inline_forms keys turbo frames by attribute name, so two rows for the same association need two distinct names.
35
+ - **`start_month` label renamed to "Start month and year".** The widget is a month_year_picker; the old label hid the year half.
36
+ - **Full-demo seed now populates `attachment` / `jingle` / `cover`.** The installer ships `sample.txt`, `sample.wav` (440Hz / 0.5s mono PCM, generated with ffmpeg), and `sample_cover.png` under `lib/installer_templates/example_app_assets`, copies them into the generated app's `db/seed_uploads/`, and the seed migration hands File handles to CarrierWave so the three file-upload rows in the full demo render thumbnails / links instead of placeholders.
37
+
38
+ ### Added
39
+
40
+ - **`ExampleAppShowcaseLocalesAssociationsTest` integration test.** Covers `check_list` toggling the HABTM (`locale_ids` add + remove via two PUTs), `info_list` rendering the `_presentation` for attached records, and the `--` empty-state placeholder. Replaces the dropped `roles`-based assertions in `ExampleAppShowcasePageRenderTest`.
41
+
42
+ ### Lockstep
43
+
44
+ - `inline_forms`, `inline_forms_installer`, and `validation_hints` bumped from 8.1.8 to 8.1.9 in lockstep, even though `validation_hints` has no behavior change in this release.
45
+
7
46
  ## [8.1.8] - 2026-05-27
8
47
 
9
48
  ### Added
@@ -22,6 +22,37 @@ Rails::Generators::GeneratedAttribute.class_eval do
22
22
  true
23
23
  end
24
24
 
25
+ # Recognize `name:decimal_field{p,s}` on the command line and hoist the
26
+ # precision/scale into `attr_options`. Rails' own
27
+ # `Rails::Generators::GeneratedAttribute.parse` only honors the `{…}`
28
+ # suffix for a hardcoded list of built-in types (`:string`, `:integer`,
29
+ # `:primary_key`, `:decimal`, ...); for our custom `:decimal_field` it
30
+ # just glues the braces onto the type symbol (`:"decimal_field{10,2}"`)
31
+ # and `column_type` falls through to `:unknown`. Strip the braces here,
32
+ # delegate to the original parse with a clean `name:decimal_field`, and
33
+ # then attach the parsed numbers to attr_options so the migration
34
+ # emitter can render `t.decimal :name, precision: P, scale: S`.
35
+ #
36
+ # Bare `name:decimal_field` (no braces) parses unchanged — the
37
+ # migration emitter applies precision: 10, scale: 2 as the default.
38
+ class << self
39
+ unless method_defined?(:parse_with_inline_forms_decimal) || private_method_defined?(:parse_with_inline_forms_decimal)
40
+ alias_method :parse_without_inline_forms_decimal, :parse
41
+ end
42
+
43
+ def parse(column_definition)
44
+ if column_definition.is_a?(String) &&
45
+ (m = column_definition.match(/\A(\w+):decimal_field\{(\d+),(\d+)\}\z/))
46
+ attr = parse_without_inline_forms_decimal("#{m[1]}:decimal_field")
47
+ attr.attr_options[:precision] = m[2].to_i
48
+ attr.attr_options[:scale] = m[3].to_i
49
+ attr
50
+ else
51
+ parse_without_inline_forms_decimal(column_definition)
52
+ end
53
+ end
54
+ end
55
+
25
56
  # Deducts the column_type for migrations from the type.
26
57
  #
27
58
  # We first merge the Special Column Types with the Default Column Types,
@@ -164,11 +164,29 @@ module InlineForms
164
164
  else
165
165
  if attribute.migration?
166
166
  attribute.attribute_type == :unknown ? commenter = '#' : commenter = ' '
167
+ # Render precision/scale for real :decimal columns. The override
168
+ # in lib/generators/inline_forms_attribute_overrides.rb teaches
169
+ # `Rails::Generators::GeneratedAttribute.parse` to extract
170
+ # `{p,s}` off the type for :decimal_field (Rails' own parser
171
+ # only honors `{…}` for a hardcoded list of built-in types
172
+ # and otherwise glues the braces onto the type symbol).
173
+ # Apply sensible defaults — precision: 10, scale: 2 — so a
174
+ # bare `name:decimal_field` becomes a real decimal column
175
+ # instead of the legacy varchar that 8.1.9 and earlier
176
+ # emitted. Existing apps keep their varchar columns until
177
+ # they migrate; only newly-generated tables get :decimal.
178
+ column_opts = ""
179
+ if attribute.column_type == :decimal
180
+ precision = attribute.attr_options[:precision] || 10
181
+ scale = attribute.attr_options[:scale] || 2
182
+ column_opts = ", precision: #{precision}, scale: #{scale}"
183
+ end
167
184
  @columns << commenter +
168
185
  ' t.' +
169
186
  attribute.column_type.to_s +
170
187
  " :" +
171
188
  attribute.name +
189
+ column_opts +
172
190
  " \n"
173
191
  end
174
192
  end
@@ -8,7 +8,7 @@ module InlineForms
8
8
  :check_list => :no_migration,
9
9
  :ckeditor => :text,
10
10
  :date_select => :date,
11
- :decimal_field => :string,
11
+ :decimal_field => :decimal,
12
12
  :devise_password_field => :string,
13
13
  :dropdown => :belongs_to,
14
14
  :dropdown_with_integers => :integer,
@@ -6,13 +6,33 @@ module InlineForms
6
6
  # -*- encoding : utf-8 -*-
7
7
 
8
8
  def decimal_field_show(object, attribute)
9
- link_to_inline_edit object, attribute, object[attribute].nil? ? "<i class='fi-plus'></i>".html_safe : object[attribute], from_callee: __callee__
9
+ # `:decimal_field` columns are real `:decimal(p, s)` since 8.1.10,
10
+ # which means `object[attribute]` returns a `BigDecimal`. Calling
11
+ # `to_s` on a BigDecimal without arguments returns scientific
12
+ # notation (`"0.1234e2"`), not the `"12.34"` users expect — render
13
+ # fixed-point. Strings (legacy varchar columns on apps generated
14
+ # before 8.1.10) and integers/floats also work with `to_s("F")` via
15
+ # their generic `to_s` fallback.
16
+ value = object[attribute]
17
+ label = if value.nil?
18
+ "<i class='fi-plus'></i>".html_safe
19
+ elsif value.is_a?(BigDecimal)
20
+ value.to_s("F")
21
+ else
22
+ value.to_s
23
+ end
24
+ link_to_inline_edit object, attribute, label, from_callee: __callee__
10
25
  end
11
-
26
+
12
27
  def decimal_field_edit(object, attribute)
13
- text_field_tag attribute, (object.send attribute.to_sym), :class => 'input_decimal_field' # for abide: , :required => true
28
+ # Render with fixed-point in the edit textbox for the same reason
29
+ # decimal_field_show does — otherwise the user sees "0.1234e2" in
30
+ # the edit field on an existing value, and round-trips it back.
31
+ value = object.send(attribute.to_sym)
32
+ value = value.to_s("F") if value.is_a?(BigDecimal)
33
+ text_field_tag attribute, value, :class => 'input_decimal_field' # for abide: , :required => true
14
34
  end
15
-
35
+
16
36
  def decimal_field_update(object, attribute)
17
37
  object.send :write_attribute, attribute.to_sym, params[attribute.to_sym]
18
38
  end
@@ -7,8 +7,19 @@ module InlineForms
7
7
 
8
8
  # dropdown_with_values
9
9
  def dropdown_with_values_show(object, attribute)
10
+ # `attribute_values` already runs every label through `t()` (see
11
+ # InlineForms::Helpers#attribute_values). Calling `t()` again here on
12
+ # an already-translated (and possibly already-rendered as
13
+ # `<span class="translation_missing">...</span>`) string used the
14
+ # whole string as an I18n key, so a missing translation rendered the
15
+ # bizarre `<span class="translation_missing" title="Low&quot;&gt;Low&lt;/Span&gt;">…</span>`
16
+ # blob the user spotted on `priority`/`priority2`. Use the already-
17
+ # translated value as-is and fall back to the empty-state placeholder
18
+ # for nil (mirrors radio_button_show and the 8.1.7 scale fixes).
10
19
  values = attribute_values(object, attribute)
11
- link_to_inline_edit object, attribute, object.send(attribute) ? t(values.assoc(object.send(attribute))[1]) : "<i class='fi-plus'></i>".html_safe, from_callee: __callee__
20
+ pair = object.send(attribute) ? values.assoc(object.send(attribute)) : nil
21
+ label = pair ? pair[1] : "<i class='fi-plus'></i>".html_safe
22
+ link_to_inline_edit object, attribute, label, from_callee: __callee__
12
23
  end
13
24
 
14
25
  def dropdown_with_values_edit(object, attribute)
@@ -31,8 +42,11 @@ module InlineForms
31
42
  end
32
43
 
33
44
  def dropdown_with_values_info(object, attribute)
45
+ # `attribute_values` already translates; do not double-translate here
46
+ # (was the same double-`t()` bug as dropdown_with_values_show).
34
47
  values = attribute_values(object, attribute)
35
- t(values.assoc(object.send(attribute))[1]) rescue '-'
48
+ pair = values.assoc(object.send(attribute))
49
+ pair ? pair[1] : '-'
36
50
  end
37
51
  INLINE_FORMS_FORM_ELEMENT
38
52
  end
@@ -6,16 +6,22 @@ module InlineForms
6
6
  # -*- encoding : utf-8 -*-
7
7
 
8
8
  def money_field_show(object, attribute)
9
- # `humanized_money_with_symbol` (money-rails) returns "" for nil/blank
10
- # which renders as an empty anchor — show the empty-state placeholder
11
- # instead, matching the nil branch on dropdown/radio show helpers.
9
+ # Two money-rails-specific quirks the bare helper used to leak:
10
+ # 1. `humanized_money_with_symbol(nil)` returns "", which renders
11
+ # as an empty `<a>` tag. Fall back to the empty-state
12
+ # placeholder used by the other choice helpers instead.
13
+ # 2. `humanized_money_with_symbol` defaults `no_cents_if_whole: true`,
14
+ # so whole-dollar amounts show without cents ("$124" instead of
15
+ # "$124.00"). That's inconsistent with non-whole amounts ("$12.34")
16
+ # and looks like a precision bug on values that rounded up to a
17
+ # whole dollar (e.g. `Money.from_amount(123.999, "USD")` rounds
18
+ # to 12400 cents → "$124" by default; "$124.00" with the override).
19
+ # Always show cents.
12
20
  value = object.send(attribute)
13
- label = if defined?(humanized_money_with_symbol) && value.respond_to?(:zero?) && !value.zero?
14
- humanized_money_with_symbol(value)
15
- elsif value.blank?
21
+ label = if value.blank?
16
22
  "<i class='fi-plus'></i>".html_safe
17
23
  else
18
- humanized_money_with_symbol(value)
24
+ humanized_money_with_symbol(value, no_cents_if_whole: false)
19
25
  end
20
26
  link_to_inline_edit object, attribute, label, from_callee: __callee__
21
27
  end
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module InlineForms
3
- VERSION = "8.1.8"
3
+ VERSION = "8.1.10"
4
4
  end
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.8
4
+ version: 8.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Suares