inline_forms_installer 8.1.6 → 8.1.9
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/lib/inline_forms_installer/installer_core.rb +130 -20
- data/lib/inline_forms_installer/version.rb +1 -1
- data/lib/installer_templates/example_app_assets/sample.txt +1 -0
- data/lib/installer_templates/example_app_assets/sample.wav +0 -0
- data/lib/installer_templates/example_app_assets/sample_cover.png +0 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_choice_scale_fields_test.rb +29 -3
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_locales_associations_test.rb +86 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_numeric_fields_test.rb +28 -8
- data/lib/installer_templates/example_app_tests/test/integration/example_app_showcase_page_render_test.rb +19 -12
- data/lib/installer_templates/example_app_tests/test/models/example_app_form_element_showcase_test.rb +5 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f4163e5ce8733e5d7f2226ce39f9a475a75860497da6d6d0ddf12575deaa661f
|
|
4
|
+
data.tar.gz: 42640181a8f3927a9e70ea3b536dfa3507eb21b0997b1fd5a4a5409668422002
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7034b106b0c14b639fff1385ef6827f5e3431fe9209e978ea932a65e28a58c97ef8a45e9c66b6cac1bbd8a1c906d8628611127714716f954d75df28ac1c232aa
|
|
7
|
+
data.tar.gz: 70ac2e021ba10ffb43fbae4f7608134b1f25ad0583d6f92658166a963aadcc8a9d7deb25b8d3389cbd575224e95f0698ba470f3b7f26f016d0dc8a03e79542f8
|
|
@@ -105,6 +105,13 @@ gem 'jquery-ui-rails', '4.0.3'
|
|
|
105
105
|
# Foundation Icons SCSS + fonts are vendored in the inline_forms engine (Dart Sass;
|
|
106
106
|
# foundation-icons-sass-rails depended on sass-rails).
|
|
107
107
|
gem 'mini_magick'
|
|
108
|
+
# money-rails powers the `money_field` Tier 1 helper:
|
|
109
|
+
# * adds the `humanized_money_with_symbol` view helper used by
|
|
110
|
+
# money_field_show
|
|
111
|
+
# * exposes `monetize :foo_cents` so an integer `_cents` column is
|
|
112
|
+
# read/written as a Money instance through `obj.foo`
|
|
113
|
+
# Used by FormElementShowcase#amount in the --example app.
|
|
114
|
+
gem 'money-rails', '~> 3.0'
|
|
108
115
|
gem 'mysql2'
|
|
109
116
|
gem 'paper_trail', '~> 17.0'
|
|
110
117
|
gem 'rails-i18n', '~> 8.1'
|
|
@@ -424,7 +431,16 @@ END_INITIALIZER
|
|
|
424
431
|
# Create Locales
|
|
425
432
|
say "- Create locales"
|
|
426
433
|
generate "inline_forms", "Locale name:string title:string #{user_cfg.table_name}:has_many _enabled:yes _list_order:title _presentation:\#{title}"
|
|
427
|
-
|
|
434
|
+
# Seed four locales so the FormElementShowcase HABTM :locales demo
|
|
435
|
+
# (added under --example) has something to check on/off. `id: 1` (en) is
|
|
436
|
+
# the default the admin user is bound to in the line below; the other
|
|
437
|
+
# three are inert until selected by the showcase rows.
|
|
438
|
+
append_to_file "db/seeds.rb", <<~LOCALE_SEED
|
|
439
|
+
Locale.create({ id: 1, name: 'en', title: 'English' })
|
|
440
|
+
Locale.create({ id: 2, name: 'nl', title: 'Nederlands' })
|
|
441
|
+
Locale.create({ id: 3, name: 'de', title: 'Deutsch' })
|
|
442
|
+
Locale.create({ id: 4, name: 'fr', title: 'Français' })
|
|
443
|
+
LOCALE_SEED
|
|
428
444
|
|
|
429
445
|
# Create Roles
|
|
430
446
|
say "- Create roles"
|
|
@@ -1049,7 +1065,7 @@ if ENV['install_example'] == 'true'
|
|
|
1049
1065
|
# ---------------------------------------------------------------------
|
|
1050
1066
|
say "- Generating FormElementShowcase (one resource per kept Tier 1 form_element)..."
|
|
1051
1067
|
sleep 1
|
|
1052
|
-
run %q{bundle exec rails g inline_forms FormElementShowcase title:string body_plain_area:plain_text_area count:integer_field price:decimal_field meeting_date:date_select meeting_time:time_select birth_month:month_select start_month:month_year_picker is_active:check_box gender:radio_button rating_int:dropdown_with_integers priority:dropdown_with_values priority2:dropdown_with_values stars:dropdown_with_values_with_stars attachment:file_field jingle:audio_field cover:image_field description:rich_text
|
|
1068
|
+
run %q{bundle exec rails g inline_forms FormElementShowcase title:string body_plain_area:plain_text_area count:integer_field price:decimal_field amount:money_field meeting_date:date_select meeting_time:time_select birth_month:month_select start_month:month_year_picker is_active:check_box gender:radio_button rating_int:dropdown_with_integers priority:dropdown_with_values priority2:dropdown_with_values stars:dropdown_with_values_with_stars scale_int:scale_with_integers scale_val:scale_with_values attachment:file_field jingle:audio_field cover:image_field description:rich_text locales:has_and_belongs_to_many _enabled:yes _list_order:title _list_search:title _presentation:'#{title}'}
|
|
1053
1069
|
|
|
1054
1070
|
say "- Generating Attachment + Jingle uploaders (Cover reuses ImageUploader)..."
|
|
1055
1071
|
run "bundle exec rails generate uploader Attachment"
|
|
@@ -1063,12 +1079,55 @@ if ENV['install_example'] == 'true'
|
|
|
1063
1079
|
"mount_uploader :cover, CoverUploader",
|
|
1064
1080
|
"mount_uploader :cover, ImageUploader"
|
|
1065
1081
|
|
|
1082
|
+
# money-rails wiring for the `amount:money_field` showcase column.
|
|
1083
|
+
#
|
|
1084
|
+
# * The inline_forms generator emits a plain `t.integer :amount`
|
|
1085
|
+
# (FormElementRegistry maps `:money_field` to `:integer`), but
|
|
1086
|
+
# money-rails' `monetize` reader/writer convention is `_cents`-
|
|
1087
|
+
# suffixed: declare `monetize :amount_cents`, store cents in
|
|
1088
|
+
# `amount_cents`, and money-rails defines `obj.amount`/`obj.amount=`
|
|
1089
|
+
# returning/parsing Money objects. That keeps the inline_forms
|
|
1090
|
+
# attribute list entry `[:amount, :money_field]` semantically
|
|
1091
|
+
# correct (`obj.amount` => Money) without a custom helper.
|
|
1092
|
+
# * Rename the column in the generated create-table migration from
|
|
1093
|
+
# `:amount` to `:amount_cents` *before* `rake db:migrate` runs.
|
|
1094
|
+
# * Add a small initializer pinning the default currency so the
|
|
1095
|
+
# showcase renders predictably under any host locale.
|
|
1096
|
+
showcase_migration = Dir.glob("db/migrate/*_inline_forms_create_form_element_showcases.rb").first
|
|
1097
|
+
if showcase_migration
|
|
1098
|
+
gsub_file showcase_migration, /t\.integer :amount\b/, "t.integer :amount_cents, default: 0, null: false"
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
create_file "config/initializers/money.rb", <<-MONEY_INIT.strip_heredoc
|
|
1102
|
+
# Generated by inline_forms (money-rails defaults for the
|
|
1103
|
+
# FormElementShowcase `amount:money_field` demo column).
|
|
1104
|
+
MoneyRails.configure do |config|
|
|
1105
|
+
config.default_currency = :usd
|
|
1106
|
+
end
|
|
1107
|
+
MONEY_INIT
|
|
1108
|
+
|
|
1066
1109
|
# First field-level validation in the example app. `allow_blank: true`
|
|
1067
1110
|
# keeps PaperTrail revert paths (and the seeded second row, which leaves
|
|
1068
1111
|
# count nil) valid. The integration test covers the explicit error
|
|
1069
1112
|
# path by POSTing `count: "abc"` to /form_element_showcases.
|
|
1113
|
+
#
|
|
1114
|
+
# `locales_display` is a virtual alias for the HABTM :locales association
|
|
1115
|
+
# so the same association can render twice in the attribute list: once
|
|
1116
|
+
# editable (`[:locales, :check_list]`) and once read-only
|
|
1117
|
+
# (`[:locales_display, :info_list]`). Inline-forms keys turbo frames by
|
|
1118
|
+
# attribute name, so we need a distinct name for the second row — info_list
|
|
1119
|
+
# has no `_update` method, hence the wrapper rather than a separate column.
|
|
1120
|
+
#
|
|
1121
|
+
# NOTE: this has to be `def locales_display; locales; end`, not
|
|
1122
|
+
# `alias_method :locales_display, :locales`. `alias_method` resolves the
|
|
1123
|
+
# source method at class-load time, but the `has_and_belongs_to_many
|
|
1124
|
+
# :locales` declaration that defines `#locales` is injected lower in the
|
|
1125
|
+
# file (line ~12), so an alias_method here raises
|
|
1126
|
+
# `NameError: undefined method 'locales' for class 'FormElementShowcase'`.
|
|
1127
|
+
# A `def` body is parsed but only resolved at call time, side-stepping
|
|
1128
|
+
# the ordering hazard.
|
|
1070
1129
|
inject_into_file "app/models/form_element_showcase.rb",
|
|
1071
|
-
"\n validates :count, numericality: { only_integer: true }, allow_blank: true\n mount_uploader :attachment, AttachmentUploader\n",
|
|
1130
|
+
"\n validates :count, numericality: { only_integer: true }, allow_blank: true\n mount_uploader :attachment, AttachmentUploader\n monetize :amount_cents\n\n def locales_display\n locales\n end\n",
|
|
1072
1131
|
after: "class FormElementShowcase < ApplicationRecord\n"
|
|
1073
1132
|
|
|
1074
1133
|
# Value-bearing rows for every form_element that needs a values hash
|
|
@@ -1082,6 +1141,8 @@ if ENV['install_example'] == 'true'
|
|
|
1082
1141
|
"[ :priority, :dropdown_with_values ]" => "[ :priority, :dropdown_with_values, { 1 => 'low', 2 => 'mid', 3 => 'high' } ]",
|
|
1083
1142
|
"[ :priority2, :dropdown_with_values ]" => "[ :priority2, :dropdown_with_values, { 1 => 'low', 2 => 'mid', 3 => 'high' }, [ 2 ] ]",
|
|
1084
1143
|
"[ :stars, :dropdown_with_values_with_stars ]" => "[ :stars, :dropdown_with_values_with_stars, { 1 => '1stars', 2 => '2stars', 3 => '3stars', 4 => '4stars', 5 => '5stars' } ]",
|
|
1144
|
+
"[ :scale_int, :scale_with_integers ]" => "[ :scale_int, :scale_with_integers, { 1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' } ]",
|
|
1145
|
+
"[ :scale_val, :scale_with_values ]" => "[ :scale_val, :scale_with_values, { 1 => 'red', 2 => 'green', 3 => 'blue' } ]",
|
|
1085
1146
|
}
|
|
1086
1147
|
showcase_value_rows.each do |from, to|
|
|
1087
1148
|
gsub_file "app/models/form_element_showcase.rb", from, to
|
|
@@ -1103,13 +1164,18 @@ if ENV['install_example'] == 'true'
|
|
|
1103
1164
|
gsub_file "app/models/form_element_showcase.rb", from, to
|
|
1104
1165
|
end
|
|
1105
1166
|
|
|
1106
|
-
# Insert :
|
|
1107
|
-
#
|
|
1108
|
-
#
|
|
1109
|
-
#
|
|
1167
|
+
# Insert :locales (editable check_list), :locales_display (read-only
|
|
1168
|
+
# info_list mirror of the same association — see the alias_method
|
|
1169
|
+
# above), :header_meta, and the timestamps after the rich_text row.
|
|
1170
|
+
# The generator does not emit a row for `locales:has_and_belongs_to_many`
|
|
1171
|
+
# (relation? is true), so we add the rows manually here. Locale (not
|
|
1172
|
+
# Role) was chosen because Role is reserved for the user/Member model
|
|
1173
|
+
# in the inline_forms example app (the join sits under roles_users);
|
|
1174
|
+
# Locale already has a `_presentation` returning `title`, which is
|
|
1175
|
+
# exactly what `info_list_show` renders per row.
|
|
1110
1176
|
gsub_file "app/models/form_element_showcase.rb",
|
|
1111
1177
|
"[ :description, :rich_text ], \n",
|
|
1112
|
-
"[ :description, :rich_text ], \n [ :
|
|
1178
|
+
"[ :description, :rich_text ], \n [ :locales, :check_list ], \n [ :locales_display, :info_list ], \n [ :header_meta, :header ], \n [ :created_at, :info ], \n [ :updated_at, :info ], \n"
|
|
1113
1179
|
|
|
1114
1180
|
# Locale keys for the showcase attributes. Headers + the timestamps
|
|
1115
1181
|
# need explicit labels so `human_attribute_name` does not fall back to
|
|
@@ -1130,21 +1196,25 @@ if ENV['install_example'] == 'true'
|
|
|
1130
1196
|
body_plain_area: Plain text area
|
|
1131
1197
|
count: Count
|
|
1132
1198
|
price: Price
|
|
1199
|
+
amount: Amount
|
|
1133
1200
|
meeting_date: Meeting date
|
|
1134
1201
|
meeting_time: Meeting time
|
|
1135
1202
|
birth_month: Birth month
|
|
1136
|
-
start_month: Start month
|
|
1203
|
+
start_month: Start month and year
|
|
1137
1204
|
is_active: Is active
|
|
1138
1205
|
gender: Gender
|
|
1139
1206
|
rating_int: Rating
|
|
1140
1207
|
priority: Priority
|
|
1141
1208
|
priority2: Priority (with disabled option)
|
|
1142
1209
|
stars: Stars
|
|
1210
|
+
scale_int: Scale (integers)
|
|
1211
|
+
scale_val: Scale (values)
|
|
1143
1212
|
attachment: Attachment
|
|
1144
1213
|
jingle: Jingle
|
|
1145
1214
|
cover: Cover
|
|
1146
1215
|
description: Description
|
|
1147
|
-
|
|
1216
|
+
locales: Locales (editable)
|
|
1217
|
+
locales_display: Locales (read-only)
|
|
1148
1218
|
created_at: Created at
|
|
1149
1219
|
updated_at: Updated at
|
|
1150
1220
|
END_SHOWCASE_LOCALE
|
|
@@ -1160,22 +1230,36 @@ if ENV['install_example'] == 'true'
|
|
|
1160
1230
|
copy_file src, File.join("app/assets/images", "#{n}stars.png") if File.exist?(src)
|
|
1161
1231
|
end
|
|
1162
1232
|
|
|
1163
|
-
#
|
|
1164
|
-
#
|
|
1165
|
-
|
|
1233
|
+
# File/audio/image upload sample assets for the full-demo seed. Copied
|
|
1234
|
+
# under db/seed_uploads so the seed migration can read them at
|
|
1235
|
+
# db:migrate time and store them through CarrierWave. Mirrors the
|
|
1236
|
+
# db/seed_images convention used for the Photo gallery seed above.
|
|
1237
|
+
%w[sample.txt sample.wav sample_cover.png].each do |basename|
|
|
1238
|
+
src = File.join(showcase_assets_root, basename)
|
|
1239
|
+
copy_file src, File.join("db/seed_uploads", basename) if File.exist?(src)
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
# Join table for has_and_belongs_to_many :locales. Mirrors the
|
|
1243
|
+
# roles_users join migration created for the user model above. Locale
|
|
1244
|
+
# (not Role) was chosen because Role is reserved for the Member/User
|
|
1245
|
+
# auth model; using it here would coincidentally share the same join
|
|
1246
|
+
# row pool as roles_users which is confusing for the demo. The four
|
|
1247
|
+
# locales seeded above (en/nl/de/fr) give the editable check_list
|
|
1248
|
+
# something interesting to toggle.
|
|
1249
|
+
say "- Creating form_element_showcases_locales join migration..."
|
|
1166
1250
|
sleep 1
|
|
1167
1251
|
habtm_ts = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
|
1168
|
-
create_file "db/migrate/#{habtm_ts}
|
|
1169
|
-
class
|
|
1252
|
+
create_file "db/migrate/#{habtm_ts}_create_join_table_form_element_showcases_locales.rb", <<-HABTM_MIGRATION.strip_heredoc
|
|
1253
|
+
class CreateJoinTableFormElementShowcasesLocales < ActiveRecord::Migration[8.1]
|
|
1170
1254
|
def self.up
|
|
1171
|
-
create_table :
|
|
1255
|
+
create_table :form_element_showcases_locales, id: false, force: true do |t|
|
|
1172
1256
|
t.integer :form_element_showcase_id
|
|
1173
|
-
t.integer :
|
|
1257
|
+
t.integer :locale_id
|
|
1174
1258
|
end
|
|
1175
1259
|
end
|
|
1176
1260
|
|
|
1177
1261
|
def self.down
|
|
1178
|
-
drop_table :
|
|
1262
|
+
drop_table :form_element_showcases_locales
|
|
1179
1263
|
end
|
|
1180
1264
|
end
|
|
1181
1265
|
HABTM_MIGRATION
|
|
@@ -1195,6 +1279,7 @@ if ENV['install_example'] == 'true'
|
|
|
1195
1279
|
s.body_plain_area = "A short plain-text paragraph."
|
|
1196
1280
|
s.count = 7
|
|
1197
1281
|
s.price = "12.34"
|
|
1282
|
+
s.amount = Money.from_amount(99.95, "USD") if s.respond_to?(:amount=)
|
|
1198
1283
|
s.meeting_date = Date.new(2026, 6, 1)
|
|
1199
1284
|
s.meeting_time = Time.utc(2000, 1, 1, 14, 30)
|
|
1200
1285
|
s.birth_month = 7
|
|
@@ -1205,11 +1290,34 @@ if ENV['install_example'] == 'true'
|
|
|
1205
1290
|
s.priority = 2
|
|
1206
1291
|
s.priority2 = 3
|
|
1207
1292
|
s.stars = 4
|
|
1293
|
+
s.scale_int = 3
|
|
1294
|
+
s.scale_val = 2
|
|
1208
1295
|
s.description = "<p>A rich-text paragraph for the showcase.</p>"
|
|
1209
1296
|
end
|
|
1210
|
-
|
|
1211
|
-
|
|
1297
|
+
# Attach the default locale (en) so the editable check_list and the
|
|
1298
|
+
# paired read-only info_list both have something to show. The other
|
|
1299
|
+
# seeded locales (nl/de/fr) stay unchecked so the toggle UX is
|
|
1300
|
+
# exercised when the user opens the check_list.
|
|
1301
|
+
if defined?(Locale) && Locale.exists?(1) && full.locales.empty?
|
|
1302
|
+
full.locales << Locale.find(1)
|
|
1303
|
+
end
|
|
1304
|
+
|
|
1305
|
+
# File/audio/image uploads for the full demo. The asset files are
|
|
1306
|
+
# copied into db/seed_uploads/ from lib/installer_templates/example_app_assets/
|
|
1307
|
+
# at install time (see the asset-copy block above), so this
|
|
1308
|
+
# migration can open them at db:migrate time and hand File handles
|
|
1309
|
+
# to CarrierWave for storage in public/uploads/.
|
|
1310
|
+
seed_uploads = Rails.root.join("db", "seed_uploads")
|
|
1311
|
+
{
|
|
1312
|
+
attachment: seed_uploads.join("sample.txt"),
|
|
1313
|
+
jingle: seed_uploads.join("sample.wav"),
|
|
1314
|
+
cover: seed_uploads.join("sample_cover.png"),
|
|
1315
|
+
}.each do |attr, path|
|
|
1316
|
+
next unless path.file?
|
|
1317
|
+
next if full.public_send(attr).present?
|
|
1318
|
+
File.open(path, "rb") { |io| full.public_send("\#{attr}=", io) }
|
|
1212
1319
|
end
|
|
1320
|
+
full.save! if full.changed?
|
|
1213
1321
|
|
|
1214
1322
|
# "Empty" refers to the role and uploader fields (their empty
|
|
1215
1323
|
# branches need to render). The other fields keep valid values
|
|
@@ -1222,6 +1330,8 @@ if ENV['install_example'] == 'true'
|
|
|
1222
1330
|
s.priority = 1
|
|
1223
1331
|
s.priority2 = 1
|
|
1224
1332
|
s.stars = 1
|
|
1333
|
+
s.scale_int = 1
|
|
1334
|
+
s.scale_val = 1
|
|
1225
1335
|
end
|
|
1226
1336
|
end
|
|
1227
1337
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Sample attachment file generated by inline_forms_installer for the FormElementShowcase demo. You can replace this with any file.
|
|
Binary file
|
|
Binary file
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../example_app/example_integration_test_case"
|
|
4
4
|
|
|
5
|
-
# Choice helpers on FormElementShowcase:
|
|
5
|
+
# Choice/scale helpers on FormElementShowcase:
|
|
6
6
|
# check_box (is_active, 0|1)
|
|
7
7
|
# radio_button (gender, hash)
|
|
8
8
|
# dropdown_with_integers (rating_int)
|
|
9
9
|
# dropdown_with_values (priority normal + priority2 options_disabled)
|
|
10
10
|
# dropdown_with_values_with_stars (stars)
|
|
11
|
-
#
|
|
12
|
-
#
|
|
11
|
+
# scale_with_integers (scale_int)
|
|
12
|
+
# scale_with_values (scale_val)
|
|
13
13
|
class ExampleAppShowcaseChoiceScaleFieldsTest < ExampleAppIntegrationTestCase
|
|
14
14
|
setup do
|
|
15
15
|
@showcase = FormElementShowcase.find_or_create_by!(title: "Choice/scale demo")
|
|
@@ -123,4 +123,30 @@ class ExampleAppShowcaseChoiceScaleFieldsTest < ExampleAppIntegrationTestCase
|
|
|
123
123
|
assert_equal 5, @showcase.reload.stars
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
test "scale_with_integers scale_int round-trips" do
|
|
127
|
+
frame = field_frame(:scale_int)
|
|
128
|
+
put form_element_showcase_path(
|
|
129
|
+
@showcase,
|
|
130
|
+
attribute: "scale_int",
|
|
131
|
+
form_element: "scale_with_integers",
|
|
132
|
+
update: frame
|
|
133
|
+
), params: { underscored_param_root => { scale_int: 4 } }, headers: field_headers(:scale_int)
|
|
134
|
+
|
|
135
|
+
assert_response :success
|
|
136
|
+
assert_equal 4, @showcase.reload.scale_int
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
test "scale_with_values scale_val round-trips" do
|
|
140
|
+
frame = field_frame(:scale_val)
|
|
141
|
+
put form_element_showcase_path(
|
|
142
|
+
@showcase,
|
|
143
|
+
attribute: "scale_val",
|
|
144
|
+
form_element: "scale_with_values",
|
|
145
|
+
update: frame
|
|
146
|
+
), params: { underscored_param_root => { scale_val: 3 } }, headers: field_headers(:scale_val)
|
|
147
|
+
|
|
148
|
+
assert_response :success
|
|
149
|
+
assert_equal 3, @showcase.reload.scale_val
|
|
150
|
+
end
|
|
151
|
+
|
|
126
152
|
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# HABTM helpers on FormElementShowcase:
|
|
6
|
+
# check_list (locales) -- editable multi-select
|
|
7
|
+
# info_list (locales_display) -- read-only mirror of the same association
|
|
8
|
+
# via `alias_method :locales_display, :locales`
|
|
9
|
+
#
|
|
10
|
+
# Locale (not Role) is the showcase association because Role is reserved
|
|
11
|
+
# for the auth Member/User model in this example app; reusing it on
|
|
12
|
+
# FormElementShowcase would coincidentally share rows with roles_users
|
|
13
|
+
# which is confusing.
|
|
14
|
+
class ExampleAppShowcaseLocalesAssociationsTest < ExampleAppIntegrationTestCase
|
|
15
|
+
setup do
|
|
16
|
+
@en = Locale.find_or_create_by!(name: "en") { |l| l.title = "English" }
|
|
17
|
+
@nl = Locale.find_or_create_by!(name: "nl") { |l| l.title = "Nederlands" }
|
|
18
|
+
@de = Locale.find_or_create_by!(name: "de") { |l| l.title = "Deutsch" }
|
|
19
|
+
|
|
20
|
+
@showcase = FormElementShowcase.find_or_create_by!(title: "Locales demo")
|
|
21
|
+
@showcase.locales.clear
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def field_frame(attr)
|
|
25
|
+
"form_element_showcase_#{@showcase.id}_#{attr}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def field_headers(attr)
|
|
29
|
+
{ "Turbo-Frame" => field_frame(attr), "Accept" => "text/html" }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "check_list locales toggles the HABTM association" do
|
|
33
|
+
frame = field_frame(:locales)
|
|
34
|
+
|
|
35
|
+
# Initially empty; PUT with two locales checked.
|
|
36
|
+
put form_element_showcase_path(
|
|
37
|
+
@showcase,
|
|
38
|
+
attribute: "locales",
|
|
39
|
+
form_element: "check_list",
|
|
40
|
+
update: frame
|
|
41
|
+
), params: { locales: { @en.id.to_s => 1, @de.id.to_s => 1 } }, headers: field_headers(:locales)
|
|
42
|
+
|
|
43
|
+
assert_response :success
|
|
44
|
+
assert_equal [@en.id, @de.id].sort, @showcase.reload.locale_ids.sort
|
|
45
|
+
|
|
46
|
+
# PUT again with only one locale; the missing one is uncoupled.
|
|
47
|
+
put form_element_showcase_path(
|
|
48
|
+
@showcase,
|
|
49
|
+
attribute: "locales",
|
|
50
|
+
form_element: "check_list",
|
|
51
|
+
update: frame
|
|
52
|
+
), params: { locales: { @nl.id.to_s => 1 } }, headers: field_headers(:locales)
|
|
53
|
+
|
|
54
|
+
assert_response :success
|
|
55
|
+
assert_equal [@nl.id], @showcase.reload.locale_ids
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
test "info_list locales_display mirrors the locales association read-only" do
|
|
59
|
+
@showcase.locales << @en unless @showcase.locales.where(id: @en.id).exists?
|
|
60
|
+
|
|
61
|
+
row_frame = "form_element_showcase_#{@showcase.id}"
|
|
62
|
+
get form_element_showcase_path(@showcase, update: row_frame),
|
|
63
|
+
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
64
|
+
|
|
65
|
+
assert_response :success
|
|
66
|
+
info_frame = field_frame(:locales_display)
|
|
67
|
+
assert_includes @response.body, %(<turbo-frame id="#{info_frame}">),
|
|
68
|
+
"expected info_list frame for :locales_display"
|
|
69
|
+
# info_list_show renders each item's `_presentation`. Locale's is `title`.
|
|
70
|
+
assert_match(/<turbo-frame id="#{info_frame}">.*#{Regexp.escape(@en.title)}/m, @response.body,
|
|
71
|
+
"expected #{@en.title.inspect} inside the locales_display info_list frame")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
test "info_list locales_display empty-state renders the -- placeholder" do
|
|
75
|
+
@showcase.locales.clear
|
|
76
|
+
|
|
77
|
+
row_frame = "form_element_showcase_#{@showcase.id}"
|
|
78
|
+
get form_element_showcase_path(@showcase, update: row_frame),
|
|
79
|
+
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
80
|
+
|
|
81
|
+
assert_response :success
|
|
82
|
+
info_frame = field_frame(:locales_display)
|
|
83
|
+
assert_match(/<turbo-frame id="#{info_frame}">[^<]*<div class='row [^']+'>--<\/div>/m, @response.body,
|
|
84
|
+
"expected empty `--` placeholder inside the locales_display frame")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -5,9 +5,7 @@ require_relative "../example_app/example_integration_test_case"
|
|
|
5
5
|
# Numeric Tier 1 helpers on FormElementShowcase:
|
|
6
6
|
# integer_field (count) + numericality validation regression
|
|
7
7
|
# decimal_field (price)
|
|
8
|
-
#
|
|
9
|
-
# money-rails' `humanized_money_with_symbol`, which is not in the installer
|
|
10
|
-
# Gemfile. See CHANGELOG 8.1.6 "Dropped" section.)
|
|
8
|
+
# money_field (amount, money-rails `monetize :amount_cents`)
|
|
11
9
|
class ExampleAppShowcaseNumericFieldsTest < ExampleAppIntegrationTestCase
|
|
12
10
|
setup do
|
|
13
11
|
@showcase = FormElementShowcase.find_or_create_by!(title: "Numeric demo")
|
|
@@ -49,24 +47,46 @@ class ExampleAppShowcaseNumericFieldsTest < ExampleAppIntegrationTestCase
|
|
|
49
47
|
assert_equal "99.95", @showcase.reload.price
|
|
50
48
|
end
|
|
51
49
|
|
|
50
|
+
test "money_field amount round-trips through monetize :amount_cents" do
|
|
51
|
+
skip "money-rails monetize not configured" unless FormElementShowcase.respond_to?(:monetized_attributes) &&
|
|
52
|
+
FormElementShowcase.monetized_attributes.key?("amount")
|
|
53
|
+
|
|
54
|
+
frame = "form_element_showcase_#{@showcase.id}_amount"
|
|
55
|
+
headers = { "Turbo-Frame" => frame, "Accept" => "text/html" }
|
|
56
|
+
|
|
57
|
+
put form_element_showcase_path(
|
|
58
|
+
@showcase,
|
|
59
|
+
attribute: "amount",
|
|
60
|
+
form_element: "money_field",
|
|
61
|
+
update: frame
|
|
62
|
+
), params: { amount: "12.34" }, headers: headers
|
|
63
|
+
|
|
64
|
+
assert_response :success
|
|
65
|
+
assert_includes @response.body, %(<turbo-frame id="#{frame}">)
|
|
66
|
+
reloaded = @showcase.reload
|
|
67
|
+
assert_equal 1234, reloaded.amount_cents,
|
|
68
|
+
"expected monetize to parse '12.34' into 1234 cents, got #{reloaded.amount_cents.inspect}"
|
|
69
|
+
end
|
|
70
|
+
|
|
52
71
|
test "integer_field count rejects non-integer via top-level create" do
|
|
53
72
|
# The controller's create iterates every attribute and calls each
|
|
54
|
-
# form_element's update method. Several helpers crash on nil
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# -> params[:_form_element_showcase][:attr] dereferences nil
|
|
58
|
-
# We supply just enough to let the create walk reach the validation step.
|
|
73
|
+
# form_element's update method. Several helpers used to crash on nil
|
|
74
|
+
# params (month_year_picker_update, scale_*_update, dropdown_*_update)
|
|
75
|
+
# so we supply just enough to let the create walk reach validation.
|
|
59
76
|
assert_no_difference "FormElementShowcase.count" do
|
|
60
77
|
post form_element_showcases_path(update: @list_frame),
|
|
61
78
|
params: {
|
|
62
79
|
title: "Bad Count",
|
|
63
80
|
count: "abc",
|
|
81
|
+
amount: "0.00",
|
|
64
82
|
start_month: "September 2026",
|
|
65
83
|
_form_element_showcase: {
|
|
66
84
|
rating_int: 1,
|
|
67
85
|
priority: 1,
|
|
68
86
|
priority2: 1,
|
|
69
87
|
stars: 1,
|
|
88
|
+
scale_int: 1,
|
|
89
|
+
scale_val: 1,
|
|
70
90
|
},
|
|
71
91
|
},
|
|
72
92
|
headers: @list_headers
|
|
@@ -13,6 +13,7 @@ class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
|
13
13
|
body_plain_area
|
|
14
14
|
count
|
|
15
15
|
price
|
|
16
|
+
amount
|
|
16
17
|
meeting_date
|
|
17
18
|
meeting_time
|
|
18
19
|
birth_month
|
|
@@ -23,11 +24,14 @@ class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
|
23
24
|
priority
|
|
24
25
|
priority2
|
|
25
26
|
stars
|
|
27
|
+
scale_int
|
|
28
|
+
scale_val
|
|
26
29
|
attachment
|
|
27
30
|
jingle
|
|
28
31
|
cover
|
|
29
32
|
description
|
|
30
|
-
|
|
33
|
+
locales
|
|
34
|
+
locales_display
|
|
31
35
|
created_at
|
|
32
36
|
updated_at
|
|
33
37
|
].freeze
|
|
@@ -43,8 +47,7 @@ class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
|
43
47
|
].freeze
|
|
44
48
|
|
|
45
49
|
setup do
|
|
46
|
-
locale = Locale.find_or_create_by!(name: "en") { |l| l.title = "English" }
|
|
47
|
-
@role = Role.find_or_create_by!(name: "superadmin") { |r| r.description = "Super Admin" }
|
|
50
|
+
@locale = Locale.find_or_create_by!(name: "en") { |l| l.title = "English" }
|
|
48
51
|
|
|
49
52
|
@full = FormElementShowcase.find_or_create_by!(title: "Full demo") do |s|
|
|
50
53
|
s.body_plain_area = "Plain text body"
|
|
@@ -60,19 +63,24 @@ class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
|
60
63
|
s.priority = 2
|
|
61
64
|
s.priority2 = 3
|
|
62
65
|
s.stars = 4
|
|
66
|
+
s.scale_int = 3
|
|
67
|
+
s.scale_val = 2
|
|
68
|
+
s.amount = Money.from_amount(99.95, "USD") if s.respond_to?(:amount=) && defined?(Money)
|
|
63
69
|
s.description = "<p>A rich-text body.</p>"
|
|
64
70
|
end
|
|
65
|
-
@full.
|
|
71
|
+
@full.locales << @locale unless @full.locales.where(id: @locale.id).exists?
|
|
66
72
|
|
|
67
73
|
@empty = FormElementShowcase.find_or_create_by!(title: "Empty demo") do |s|
|
|
68
74
|
# Keep dropdown/scale integers at valid indices so the show helpers
|
|
69
|
-
# do not crash on nil. The point of "empty demo" is that
|
|
70
|
-
# uploads are blank, not every integer attribute.
|
|
75
|
+
# do not crash on nil. The point of "empty demo" is that locales
|
|
76
|
+
# and uploads are blank, not every integer attribute.
|
|
71
77
|
s.gender = 1
|
|
72
78
|
s.rating_int = 1
|
|
73
79
|
s.priority = 1
|
|
74
80
|
s.priority2 = 1
|
|
75
81
|
s.stars = 1
|
|
82
|
+
s.scale_int = 1
|
|
83
|
+
s.scale_val = 1
|
|
76
84
|
end
|
|
77
85
|
end
|
|
78
86
|
|
|
@@ -95,22 +103,21 @@ class ExampleAppShowcasePageRenderTest < ExampleAppIntegrationTestCase
|
|
|
95
103
|
"expected header label for #{attr} (#{label.inspect})"
|
|
96
104
|
end
|
|
97
105
|
|
|
98
|
-
assert_includes @response.body, @
|
|
99
|
-
"expected info_list to render the
|
|
106
|
+
assert_includes @response.body, @locale.title,
|
|
107
|
+
"expected info_list to render the locale's _presentation"
|
|
100
108
|
end
|
|
101
109
|
|
|
102
|
-
test "empty showcase info_list renders the no-
|
|
110
|
+
test "empty showcase info_list renders the no-locales placeholder" do
|
|
103
111
|
row_frame = "form_element_showcase_#{@empty.id}"
|
|
104
112
|
get form_element_showcase_path(@empty, update: row_frame),
|
|
105
113
|
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
106
114
|
|
|
107
115
|
assert_response :success
|
|
108
|
-
frame = "form_element_showcase_#{@empty.id}
|
|
116
|
+
frame = "form_element_showcase_#{@empty.id}_locales_display"
|
|
109
117
|
body = @response.body
|
|
110
118
|
assert_includes body, %(<turbo-frame id="#{frame}">)
|
|
111
|
-
frame_block = body[body.index(%(<turbo-frame id="#{frame}">"))..-1] rescue nil
|
|
112
119
|
# info_list_show emits a `--` placeholder for empty associations.
|
|
113
120
|
assert_match(/<turbo-frame id="#{frame}">[^<]*<div class='row [^']+'>--<\/div>/m, body,
|
|
114
|
-
"expected info_list empty placeholder `--` inside
|
|
121
|
+
"expected info_list empty placeholder `--` inside locales_display frame")
|
|
115
122
|
end
|
|
116
123
|
end
|
data/lib/installer_templates/example_app_tests/test/models/example_app_form_element_showcase_test.rb
CHANGED
|
@@ -15,6 +15,7 @@ class ExampleAppFormElementShowcaseTest < ActiveSupport::TestCase
|
|
|
15
15
|
header_numbers
|
|
16
16
|
count
|
|
17
17
|
price
|
|
18
|
+
amount
|
|
18
19
|
header_dates
|
|
19
20
|
meeting_date
|
|
20
21
|
meeting_time
|
|
@@ -27,13 +28,16 @@ class ExampleAppFormElementShowcaseTest < ActiveSupport::TestCase
|
|
|
27
28
|
priority
|
|
28
29
|
priority2
|
|
29
30
|
stars
|
|
31
|
+
scale_int
|
|
32
|
+
scale_val
|
|
30
33
|
header_files
|
|
31
34
|
attachment
|
|
32
35
|
jingle
|
|
33
36
|
cover
|
|
34
37
|
header_rich
|
|
35
38
|
description
|
|
36
|
-
|
|
39
|
+
locales
|
|
40
|
+
locales_display
|
|
37
41
|
header_meta
|
|
38
42
|
created_at
|
|
39
43
|
updated_at
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inline_forms_installer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.1.
|
|
4
|
+
version: 8.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ace Suares
|
|
@@ -94,6 +94,9 @@ files:
|
|
|
94
94
|
- lib/installer_templates/example_app_assets/3stars.png
|
|
95
95
|
- lib/installer_templates/example_app_assets/4stars.png
|
|
96
96
|
- lib/installer_templates/example_app_assets/5stars.png
|
|
97
|
+
- lib/installer_templates/example_app_assets/sample.txt
|
|
98
|
+
- lib/installer_templates/example_app_assets/sample.wav
|
|
99
|
+
- lib/installer_templates/example_app_assets/sample_cover.png
|
|
97
100
|
- lib/installer_templates/example_app_tests/test/example_app/example_integration_test_case.rb
|
|
98
101
|
- lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb
|
|
99
102
|
- lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_list_test.rb
|
|
@@ -111,6 +114,7 @@ files:
|
|
|
111
114
|
- lib/installer_templates/example_app_tests/test/integration/example_app_routing_test.rb
|
|
112
115
|
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_choice_scale_fields_test.rb
|
|
113
116
|
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_date_time_fields_test.rb
|
|
117
|
+
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_locales_associations_test.rb
|
|
114
118
|
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_numeric_fields_test.rb
|
|
115
119
|
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_page_render_test.rb
|
|
116
120
|
- lib/installer_templates/example_app_tests/test/integration/example_app_showcase_text_fields_test.rb
|