inline_forms 6.2.14 → 7.0.4

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +174 -0
  3. data/README.rdoc +13 -1
  4. data/Rakefile +12 -1
  5. data/app/helpers/form_elements/audio_field.rb +1 -1
  6. data/app/helpers/form_elements/check_box.rb +1 -1
  7. data/app/helpers/form_elements/check_list.rb +2 -2
  8. data/app/helpers/form_elements/chicas_dropdown_with_family_members.rb +1 -1
  9. data/app/helpers/form_elements/ckeditor.rb +2 -1
  10. data/app/helpers/form_elements/date.rb +1 -1
  11. data/app/helpers/form_elements/decimal_field.rb +1 -1
  12. data/app/helpers/form_elements/devise_password_field.rb +1 -1
  13. data/app/helpers/form_elements/dropdown.rb +1 -1
  14. data/app/helpers/form_elements/dropdown_with_integers.rb +1 -1
  15. data/app/helpers/form_elements/dropdown_with_other.rb +1 -1
  16. data/app/helpers/form_elements/dropdown_with_values.rb +1 -1
  17. data/app/helpers/form_elements/dropdown_with_values_with_stars.rb +1 -1
  18. data/app/helpers/form_elements/file_field.rb +1 -1
  19. data/app/helpers/form_elements/geo_code_curacao.rb +1 -1
  20. data/app/helpers/form_elements/image_field.rb +1 -1
  21. data/app/helpers/form_elements/integer_field.rb +1 -1
  22. data/app/helpers/form_elements/kansen_slider.rb +1 -1
  23. data/app/helpers/form_elements/money_field.rb +1 -1
  24. data/app/helpers/form_elements/month_select.rb +1 -1
  25. data/app/helpers/form_elements/month_year_picker.rb +1 -1
  26. data/app/helpers/form_elements/move.rb +1 -1
  27. data/app/helpers/form_elements/multi_image_field.rb +1 -1
  28. data/app/helpers/form_elements/plain_text_area.rb +1 -1
  29. data/app/helpers/form_elements/question_list.rb +2 -2
  30. data/app/helpers/form_elements/radio_button.rb +1 -1
  31. data/app/helpers/form_elements/rich_text.rb +36 -0
  32. data/app/helpers/form_elements/scale_with_integers.rb +1 -1
  33. data/app/helpers/form_elements/scale_with_values.rb +1 -1
  34. data/app/helpers/form_elements/simple_file_field.rb +1 -1
  35. data/app/helpers/form_elements/slider_with_values.rb +1 -1
  36. data/app/helpers/form_elements/text_area.rb +4 -3
  37. data/app/helpers/form_elements/text_area_without_ckeditor.rb +1 -1
  38. data/app/helpers/form_elements/text_field.rb +1 -1
  39. data/app/helpers/form_elements/time.rb +1 -1
  40. data/app/helpers/inline_forms_helper.rb +56 -29
  41. data/app/views/inline_forms/_close.html.erb +2 -2
  42. data/app/views/inline_forms/_edit.html.erb +5 -4
  43. data/app/views/inline_forms/_new.html.erb +2 -2
  44. data/app/views/inline_forms/_versions_list.html.erb +30 -14
  45. data/app/views/layouts/application.html.erb +3 -1
  46. data/app/views/layouts/inline_forms.html.erb +3 -1
  47. data/bin/inline_forms +1 -1
  48. data/bin/inline_forms_installer_core.rb +99 -27
  49. data/docs/prompt/.gitignore +5 -0
  50. data/docs/prompt/test-the-example-app.md +32 -0
  51. data/inline_forms.gemspec +3 -1
  52. data/lib/generators/inline_forms_generator.rb +30 -0
  53. data/lib/generators/templates/migration.erb +1 -1
  54. data/lib/generators/templates/model.erb +1 -0
  55. data/lib/inline_forms/form_element_from_callee.rb +10 -0
  56. data/lib/inline_forms/version.rb +1 -1
  57. data/lib/inline_forms.rb +1 -13
  58. data/lib/installer_templates/example_app_tests/test/example_app/example_integration_test_case.rb +36 -0
  59. data/lib/installer_templates/example_app_tests/test/integration/example_app_guest_access_test.rb +21 -0
  60. data/lib/installer_templates/example_app_tests/test/integration/example_app_photos_test.rb +22 -0
  61. data/lib/installer_templates/example_app_tests/test/integration/example_app_routing_test.rb +15 -0
  62. data/lib/installer_templates/example_app_tests/test/models/example_app_apartment_photo_test.rb +26 -0
  63. data/lib/installer_templates/example_app_tests/test/models/example_app_paper_trail_changeset_test.rb +78 -0
  64. data/test/form_element_from_callee_test.rb +73 -0
  65. data/test/inline_edit_polymorphic_path_test.rb +81 -0
  66. data/test/inline_forms_generator_test.rb +155 -0
  67. data/test/test_helper.rb +6 -0
  68. metadata +42 -11
  69. data/app/helpers/form_elements/absence_list.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47c91a53a6fffc56db106874c00571182582ea6791690a8aa6817d3b297d8a2c
4
- data.tar.gz: ab879feabb9a8104ed11f8d7a3fbf7feffddc8860f13d9e52075b07eb496a24b
3
+ metadata.gz: 46c8d9d11975c43765ea29ed896933ac0dc63b64d1b23ae97d7239e2005c1190
4
+ data.tar.gz: 531398598e0d12f391f3f61a95c445cc2d9bc9ff9b507c1eaead1c48bb871f19
5
5
  SHA512:
6
- metadata.gz: d4b6061360a62fbce0eaed156a1ff23645fa927b7e5a82b0065b95ff8a262991dfb21a013b6e0e5816ad4ef8f11617347af5cd9da20ed45ebaf11d8647477f68
7
- data.tar.gz: 73f93169d282fade1c1ac0cd16dbd83fb582b4c13e5fcea0e9f0b15424880e126cef58ab6d8e2eb3bf6d99f33971f8b3becd2d31d0bf4caa5aef406447b48430
6
+ metadata.gz: fb3d95164a8a6ac18e1362d18be11e66a264f7038f9d229f3e5bd4abe38ea46fade6d619932c01e1eea91dbd794bfe54c5f255e110125d38851c0a0c48f72b93
7
+ data.tar.gz: 1c58dda2e716ae74e4e2dc3d737bf17ad1e8af168e7eb0625bd410217d37a6f1ac7591825b851ddc5cae9d204f9aaeeabd1aeb89bacdfcd3d3824989f947d18d
data/CHANGELOG.md ADDED
@@ -0,0 +1,174 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [7.0.4] - 2026-05-05
8
+
9
+ ### Changed
10
+
11
+ - **Pin CarrierWave in generated apps (`bin/inline_forms_installer_core.rb`)**: `gem 'carrierwave'` → `gem 'carrierwave', '~> 3.1'`. CarrierWave 3.1 (released Dec 2024, latest 3.1.2 from Apr 2025) supports Rails 6.0–8.0, matches the gem's existing local-disk uploader pattern, and locks generated apps out of a hypothetical 4.x with breaking changes. No code/API change for uploaders themselves.
12
+
13
+ ### Added
14
+
15
+ - **README section "File uploads (CarrierWave)"** documenting the upload story (CarrierWave 3.1, local filesystem under `public/uploads/`, default uploader from `rails generate uploader`), pointing at `carrierwave-aws` / fog for S3, and noting that generated apps also pull in ActiveStorage transitively to back ActionText embeds (`:rich_text` form element) — image uploads still use CarrierWave; ActiveStorage is only there for ActionText.
16
+
17
+ ## [7.0.3] - 2026-05-05
18
+
19
+ ### Fixed
20
+
21
+ - **PaperTrail did not record ActionText (`rich_text`) edits.** `has_rich_text :foo` stores its body in the polymorphic `action_text_rich_texts` table, not on the parent model, so `has_paper_trail` on (e.g.) `Apartment` could never see body edits. Recommended by paper_trail's maintainer in [stackoverflow #55544935](https://stackoverflow.com/questions/55544935/how-to-get-paper-trail-to-work-with-action-text); also applies to PaperTrail >= 13 and Rails 7.
22
+
23
+ ### Added
24
+
25
+ - **`config/initializers/rich_text_paper_trail.rb` in generated apps (`bin/inline_forms_installer_core.rb`)**: declares `has_paper_trail` on `ActionText::RichText` via `ActiveSupport.on_load(:action_text_rich_text)`, so each rich-text save creates a `PaperTrail::Version` row whose `item_type` is `ActionText::RichText`.
26
+ - **`InlineFormsHelper#inline_forms_versions_for(object)` (`app/helpers/inline_forms_helper.rb`)**: returns the parent model's PaperTrail versions merged with versions of every associated `ActionText::RichText` record, sorted by `created_at`. Each entry carries its `:kind` (`:primary` or `:rich_text`) and, for rich-text entries, the attribute name (e.g. `"description"`).
27
+ - **Versions panel now surfaces rich-text edits (`app/views/inline_forms/_versions_list.html.erb`)**: iterates `inline_forms_versions_for(@object)` instead of `@object.versions`, labels rich-text rows as `update (rich text)`, renders body diffs under the rich-text attribute name (so a `description` edit shows up as `description`, not `body`), and omits noise columns (`record_id`, `record_type`, `name`) from the rich-text changeset display. Restore links remain on the parent rows only (the existing revert path doesn't know how to roll back a rich-text version).
28
+ - **Regression test extension** in `test/models/example_app_paper_trail_changeset_test.rb`: updates an `Apartment#description` (a `rich_text`) and asserts `inline_forms_versions_for` returns a rich-text entry whose `body` changeset moves between the old and new HTML.
29
+
30
+ ## [7.0.2] - 2026-05-05
31
+
32
+ ### Fixed
33
+
34
+ - **PaperTrail `version.changeset` was always empty in generated apps** (long-standing bug, predates the 7.0.1 PaperTrail upgrade). The inline_forms versions panel (`app/views/inline_forms/_versions_list.html.erb`) iterates `version.changeset`; under Rails 7 + PaperTrail >= 13 (and the older `acesuares/paper_trail` v12 fork) that call routes through `YAML.safe_load` with `ActiveRecord.yaml_column_permitted_classes` as the allow-list. Rails 7's default is `[Symbol]`, so the very first attribute in any update's `object_changes` (`updated_at`, an `ActiveSupport::TimeWithZone`) raised `Psych::DisallowedClass`; PaperTrail rescued that and returned `{}`, so every row in the versions list rendered as **`empty`**.
35
+
36
+ ### Added
37
+
38
+ - **`config/initializers/paper_trail_yaml_safe_load.rb` in generated apps (`bin/inline_forms_installer_core.rb`)**: extends `ActiveRecord.yaml_column_permitted_classes` (and the matching `Rails.application.config.active_record.yaml_column_permitted_classes`) with `Symbol, Date, Time, BigDecimal, ActiveSupport::TimeWithZone, ActiveSupport::TimeZone, ActiveSupport::HashWithIndifferentAccess`. With this in place, `version.changeset` round-trips and the inline versions panel shows real diffs for `update` events.
39
+ - **Regression test** `test/models/example_app_paper_trail_changeset_test.rb` (added to the `--example` test bundle): creates and updates an `Apartment`, then asserts `version.changeset` is non-empty and contains the expected old/new tuples. Runs under `bundle exec rails test` in any new example app and would have caught this bug.
40
+
41
+ ## [7.0.1] - 2026-05-05
42
+
43
+ ### Changed
44
+
45
+ - **Generated app Gemfile (`bin/inline_forms_installer_core.rb`)**: depend on the canonical `paper_trail` gem from RubyGems (`gem 'paper_trail', '~> 16.0'`) instead of the long-frozen `acesuares/paper_trail` git fork. PaperTrail 16 supports ActiveRecord `>= 6.1, < 8.1` and Ruby `>= 3.0`, which matches this gem's Rails 7.0 / Ruby 3.2 target. Removes the "not compatible with ActiveRecord 7.0" boot warning that PaperTrail 12 (the fork's base) emitted.
46
+ - **Installer paper_trail step (`bin/inline_forms_installer_core.rb`)**: drop the `--with-mysql` flag. That option only exists on the `acesuares` fork (it is the fork's sole behavioral patch on top of upstream PaperTrail) and is not recognized by upstream PaperTrail. The generator now runs `paper_trail:install --with-changes` for both sqlite and mysql apps; PaperTrail detects MySQL via the live ActiveRecord connection, which is fine because the installer documents creating the mysql development database before this step (sqlite needs no pre-existing DB).
47
+
48
+ ## [7.0.0] - 2026-05-05
49
+
50
+ ### Changed
51
+
52
+ - **Target Rails 7.0.x**. `inline_forms.gemspec` now requires `rails >= 7.0.0, < 7.1`. Upgrades the gem from the Rails 6.1 / Webpacker era to the Rails 7.0 / importmap era.
53
+ - **Generated app Gemfile (`bin/inline_forms_installer_core.rb`)**: `gem 'rails', '~> 7.0.0'` (was `'6.1.3.1'`); add explicit `gem 'sprockets-rails'` (no longer in the default Rails 7 Gemfile but required by the gem's own `app/assets`); add `gem 'importmap-rails'` for the new default JS pipeline; drop `gem 'coffee-rails'` (unused by the gem itself, dead default in Rails 7).
54
+ - **`bin/inline_forms`**: `rails new` invocation drops `--skip-gemfile` (Rails 7 removed it) and `--skip-test-unit` (renamed in Rails 5; we let the default test scaffolding run in Rails 7 so `test/test_helper.rb` exists for the example app's regression tests). Adds `--javascript=importmap` so the generated app explicitly opts into Hotwire/importmap-rails (default in Rails 7, made explicit for clarity).
55
+ - **Generator migration template (`lib/generators/templates/migration.erb`)**: emits `ActiveRecord::Migration[7.0]`.
56
+ - **Installer migrations (`bin/inline_forms_installer_core.rb`)**: `DeviseCreateUsers`, `InlineFormsCreateJoinTableUserRole` and `InlineFormsCreateViewForTranslations` now use `ActiveRecord::Migration[7.0]`.
57
+ - **Generator unit tests (`test/inline_forms_generator_test.rb`)**: assert against `ActiveRecord::Migration[7.0]`.
58
+
59
+ ### Fixed
60
+
61
+ - **Gemfile conflict on Rails 7 (`bin/inline_forms_installer_core.rb`)**: explicit `remove_file 'Gemfile'` before `create_file 'Gemfile'` so the installer template no longer prompts to overwrite the Gemfile that `rails new` (Rails 7) always creates.
62
+ - **Custom field types under Rails 7 (`lib/generators/inline_forms_generator.rb`)**: override `Rails::Generators::GeneratedAttribute.valid_type?` to always accept incoming types. Rails 7 removed the rescue around `ActiveRecord::Base.connection.valid_type?`, so the parser raised `NameError`/`Could not generate field` for our custom types (`:dropdown`, `:check_list`, `:image_field`, `:rich_text`, ...) and broke generator unit tests that don't load Active Record. Unknown-type detection still happens later via Thor::Error + `--allow-unknown`.
63
+
64
+ ### Notes / known issues
65
+
66
+ - PaperTrail (currently sourced from the `acesuares/paper_trail` fork at v12.0.0) prints a "not compatible with ActiveRecord 7.0" warning on boot. Tests pass and the example app works end-to-end. A follow-up bump to PaperTrail 13+ is recommended but not required.
67
+
68
+ ## [6.4.1] - 2026-05-05
69
+
70
+ ### Fixed
71
+
72
+ - **`rich_text` form element (`app/helpers/form_elements/rich_text.rb`)**: `rich_text_edit` no longer relies on the non-existent `rich_text_area_tag` (Rails 6.1) which produced an empty cell on new and existing records. It now renders a hidden input + `<trix-editor>` pair tied by `input=` so the editor actually shows up inline.
73
+ - **`rich_text_show`**: more defensive handling of nil/blank ActionText values (uses `to_plain_text` when available) so the `+` placeholder shows on empty values and the rendered HTML shows on populated ones.
74
+
75
+ ### Changed
76
+
77
+ - **Inline edit layout (`app/views/inline_forms/_edit.html.erb`)**: added `rich_text` to `@BUTTONS_UNDER` so the editor gets a full-width row with OK/Cancel below it (matching `text_area`).
78
+ - **Layouts (`app/views/layouts/{application,inline_forms}.html.erb`)**: include Trix 1.3.1 CSS+JS from unpkg so generated apps render the editor without bundling JS, and keep the existing CKEditor guard.
79
+
80
+ ## [6.4.0] - 2026-05-05
81
+
82
+ ### Added
83
+
84
+ - **New `rich_text` form element** (`app/helpers/form_elements/rich_text.rb`) for ActionText-backed attributes, including show/edit/update/info handlers compatible with inline editing.
85
+ - **Generator coverage** for ActionText declarations in `test/inline_forms_generator_test.rb` (`content:rich_text` emits `has_rich_text` and skips migration column generation).
86
+ - **Reusable workflow prompt docs** in `docs/prompt/test-the-example-app.md` with a local `docs/prompt/.gitignore`.
87
+
88
+ ### Changed
89
+
90
+ - **Inline forms generator** now emits `has_rich_text :attribute` in generated models when the field type is `:rich_text` (`lib/generators/inline_forms_generator.rb`, `lib/generators/templates/model.erb`).
91
+ - **Installer template** moved generated apps from CKEditor setup to ActionText migrations (`active_storage:install` + `action_text:install:migrations`) and updates example resources to use `description:rich_text`.
92
+ - **Generated app Gemfile wiring** now points `inline_forms` to the local gem path during scaffold/install flow, so iteration testing uses current local code.
93
+
94
+ ### Fixed
95
+
96
+ - **Layouts** no longer raise `uninitialized constant Ckeditor` when CKEditor is absent: CKEditor CDN script tags are now conditional in `app/views/layouts/application.html.erb` and `app/views/layouts/inline_forms.html.erb`.
97
+
98
+ ## [6.3.4] - 2026-05-05
99
+
100
+ ### Added
101
+
102
+ - **Generator regression harness** in `test/inline_forms_generator_test.rb` that runs `InlineForms::InlineFormsGenerator` against a temporary destination and asserts generated model/controller/route/migration output plus `_no_model` behavior.
103
+ - **Same:** coverage for unknown-type handling, including default strict mode and the explicit legacy opt-out via `--allow-unknown`.
104
+
105
+ ### Changed
106
+
107
+ - **Generator hardening (`lib/generators/inline_forms_generator.rb`):** unknown field types now fail fast by default with a clear message listing the offending `name:type` pairs and how to opt into legacy behavior.
108
+
109
+ ### Fixed
110
+
111
+ - **Same:** internal control attributes prefixed with `_` (such as `_no_model`, `_enabled`, `_no_migration`, `_id`) are excluded from unknown-type checks, so generator flags keep working under strict validation.
112
+ - **Generator tests (`test/inline_forms_generator_test.rb`):** require `logger` before `rails` so Bundler-based test runs are stable on Rails 6.1 / Ruby 3.2.
113
+
114
+ ## [6.3.3] - 2026-05-03
115
+
116
+ ### Added
117
+
118
+ - **`--example` installs regression tests** under `test/example_app/` and `test/integration/example_app_*_test.rb`, plus model coverage for the generated Photo/Apartment resources. Run them with **`bundle exec rails test`** in the new app.
119
+
120
+ ### Changed
121
+
122
+ - **Example installer** no longer runs **`bundle exec rails s`** at the end (it blocked the shell). Start the server manually when you want to use the browser.
123
+
124
+ ### Fixed
125
+
126
+ - **Sqlite `database.yml`** now includes a **`test`** database (`db/test.sqlite3`) so **`bundle exec rails test`** works in generated sqlite apps.
127
+ - Generated apps add a **`test`** Bundler group with **`minitest ~> 5.25`** so Rails 6.1’s test runner stays compatible (avoids Minitest 6 / **`railties`** **`line_filtering`** and parallelization API mismatches).
128
+
129
+ ## [6.3.2] - 2026-05-03
130
+
131
+ ### Fixed
132
+
133
+ - **Application template (`bin/inline_forms_installer_core.rb`):** generated apps use **`rails-i18n ~> 7.0`** from RubyGems instead of the **`svenfuchs/rails-i18n`** git default branch, which targets Rails 8+ and could not be resolved with pinned **`rails` 6.1.3.1**.
134
+ - **Same:** development **`sqlite3`** is pinned to **`~> 1.4`** so it matches ActiveRecord 6.1’s adapter expectation (avoids **`sqlite3` 2.x** activation errors during generators and boot).
135
+ - **Same:** **`sleep 1`** after **`paper_trail:install`** (two migrations in one second) and between translation **`inline_forms`** generators so migration version numbers stay unique.
136
+ - **Same:** when **`using_sqlite`** is true, run **`paper_trail:install --with-changes`** only (omit **`--with-mysql`**). The MySQL/InnoDB table options in the PaperTrail migration are invalid on SQLite and broke **`db:migrate`** for the sqlite example app.
137
+
138
+ ## [6.3.1] - 2026-05-03
139
+
140
+ ### Changed
141
+
142
+ - `**InlineFormsHelper#link_to_inline_edit**` uses `**edit_polymorphic_path**` instead of `**send('edit_' + object.class.to_s.underscore + '_path', …)**`.
143
+ - `**InlineFormsHelper#close_link**` and `**#link_to_destroy**` use `**polymorphic_path(object, …)**` instead of `**send(object.class.to_s.underscore + '_path', …)**`.
144
+ - Partial templates `**_close.html.erb**`, `**_edit.html.erb**`, and `**_new.html.erb**` use `**polymorphic_path**` for member and collection URLs instead of building helper names with `**send**`.
145
+ - `**_edit.html.erb**` form and cancel links now pass the record into `**polymorphic_path(@object, …)**` so the member path includes the resource id (required for conventional `**resources**` routes).
146
+
147
+ ### Compatibility
148
+
149
+ - Intended to be **non-breaking** for typical ActiveRecord models with standard `**resources :model**` routing: URLs match Rails’ named helpers (`**edit_*_path**`, `**article_path**`, `**articles_path**`, etc.). Paths are derived from `**model_name**` / `**singular_route_key**` instead of `**class.name.underscore**`, which can differ only in unusual setups (e.g. a custom `**model_name**` that does not match the previous string).
150
+
151
+ ### Development
152
+
153
+ - `**test/inline_edit_polymorphic_path_test.rb**` asserts parity between polymorphic helpers and named `**edit_article_path**`, `**article_path**`, and `**articles_path**` for a minimal `**resources :articles**` route set (no full app boot).
154
+
155
+ ## [6.3.0] - 2026-05-03
156
+
157
+ ### Removed
158
+
159
+ - Project-specific `absence_list` form element (`app/helpers/form_elements/absence_list.rb`). Applications that still need it should copy the old implementation into their own codebase.
160
+
161
+ ### Changed
162
+
163
+ - `**InlineFormsHelper#link_to_inline_edit**` now requires keyword argument `**from_callee:**` (pass `**__callee__**` from the enclosing `*_show` method). The form element name for the edit request is derived with `String#delete_suffix('_show')` after stripping a leading `block in` prefix when present. This replaces stack inspection via `Kernel#calling_method` / `caller` parsing.
164
+ - `**Kernel` patches** for `this_method` and `calling_method` were removed from `lib/inline_forms.rb` and `app/helpers/inline_forms_helper.rb`.
165
+
166
+ ### Upgrade notes
167
+
168
+ - **Breaking:** Any custom code that called `link_to_inline_edit` with a fourth positional `form_element` argument must switch to `from_callee: __callee__` when the call is made from a `*_show` helper, or pass the appropriate callee symbol for your naming convention.
169
+ - **Breaking:** Models or apps that referenced the `absence_list` form element from this gem must drop that reference or vendor the removed helper.
170
+
171
+ ### Development
172
+
173
+ - Run `bundle install` then `rake` (or `rake test`) to execute Minitest for `InlineForms.form_element_string_from_callee` (no Rails boot). The Rake task uses verbose mode so each test prints on its own line; failed assertions show the explanatory message from the test file.
174
+ - For end-to-end checks, generate a disposable app with `**bin/inline_forms create MyApp -d sqlite`** (uses RVM unless `--no-rvm`), or add the gem with `**gem "inline_forms", path: "/path/to/inline_forms"**` in a Rails app’s Gemfile, run `**rails g inline_forms …**`, migrate, and exercise the UI in the browser.
data/README.rdoc CHANGED
@@ -18,7 +18,7 @@ If you want to install the example application:
18
18
 
19
19
  inline_forms create MyApp -d sqlite --example
20
20
 
21
- Then point your browser to http://localhost:3000/apartments and log in with admin@example.com / admin999
21
+ Then point your browser to http://localhost:3000/apartments and log in with admin@example.com / admin999. The example also adds integration and model tests; run +bundle exec rails test+ in +MyApp+, then start the server with +bundle exec rails s+ when you want the UI.
22
22
 
23
23
  You can install the example application manually if you like:
24
24
 
@@ -32,6 +32,18 @@ You can install the example application manually if you like:
32
32
 
33
33
  Then point your browser to http://localhost:3000/apartments and log in with admin@example.com / admin999
34
34
 
35
+ == Generated application +rails-i18n+
36
+
37
+ New apps get +rails-i18n+ from RubyGems (+ '~> 7.0'+), not from the +svenfuchs/rails-i18n+ Git repository. Release line 7.0.x declares +railties+ between 6 and 8, which matches the template’s Rails 6.1.3.1. The upstream repository’s default branch is aimed at newer Rails and would pull in +railties+ 8+, which cannot be resolved together with Rails 6.1.
38
+
39
+ == File uploads (CarrierWave)
40
+
41
+ The +:image_field+ form element uses CarrierWave. Generated apps depend on +carrierwave '~> 3.1'+ from RubyGems, store uploads on the local filesystem under +public/uploads/+, and use the default uploader produced by +rails generate uploader Image+. CarrierWave 3.1 supports Rails 6.0 through 8.0 and is the upstream maintenance line.
42
+
43
+ To switch to S3, add +carrierwave-aws+ (or use the bundled fog backend) and configure a +CarrierWave.configure+ block in +config/initializers/carrierwave.rb+; nothing in inline_forms hard-codes local storage.
44
+
45
+ Note: generated apps also depend on ActiveStorage transitively because the +:rich_text+ form element uses ActionText (+active_storage:install+ runs during +inline_forms create+). Image uploads still go through CarrierWave; ActiveStorage is only there to back ActionText embeds.
46
+
35
47
  = Build a vagrant virtualbox box for easier development
36
48
 
37
49
  Go ahead and unzip lib/vagrant/vagrantbox-inline_forms.zip. Enter the created directory with
data/Rakefile CHANGED
@@ -1,2 +1,13 @@
1
- require 'bundler'
1
+ require "bundler"
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList["test/**/*_test.rb"]
9
+ t.verbose = true
10
+ t.warning = true
11
+ end
12
+
13
+ task default: :test
@@ -11,7 +11,7 @@ def audio_field_show(object, attribute)
11
11
  audio_html = audio_tag(o.send(:url), autoplay: false, controls: true)
12
12
  end
13
13
  end
14
- link_to_edit = link_to_inline_edit object, attribute, msg
14
+ link_to_edit = link_to_inline_edit object, attribute, msg, from_callee: __callee__
15
15
  if cancan_disabled? || ( can? :update, object, attribute )
16
16
  "#{audio_html} #{link_to_edit}".html_safe
17
17
  else
@@ -3,7 +3,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:check_box]=:boolean
3
3
  # boolean, bit unaptly named check_box
4
4
  def check_box_show(object, attribute)
5
5
  values = attribute_values(object, attribute)
6
- link_to_inline_edit object, attribute, values[object.send(attribute) ? 1 : 0 ][1]
6
+ link_to_inline_edit object, attribute, values[object.send(attribute) ? 1 : 0 ][1], from_callee: __callee__
7
7
  end
8
8
 
9
9
  def check_box_edit(object, attribute)
@@ -4,10 +4,10 @@ InlineForms::SPECIAL_COLUMN_TYPES[:check_list]=:no_migration
4
4
  # checklist
5
5
  def check_list_show(object, attribute)
6
6
  out = ''
7
- out = link_to_inline_edit(object, attribute, "<i class='fi-plus'></i>".html_safe) if object.send(attribute).empty?
7
+ out = link_to_inline_edit(object, attribute, "<i class='fi-plus'></i>".html_safe, from_callee: __callee__) if object.send(attribute).empty?
8
8
  object.send(attribute).sort.each do | item |
9
9
  out << "<div class='row #{cycle('odd', 'even')}'>"
10
- out << link_to_inline_edit(object, attribute, item._presentation )
10
+ out << link_to_inline_edit(object, attribute, item._presentation, from_callee: __callee__ )
11
11
  out << '</div>'
12
12
  end
13
13
  out.html_safe
@@ -4,7 +4,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:dropdown]=:belongs_to
4
4
  # dropdown
5
5
  def chicas_dropdown_with_family_members_show(object, attribute)
6
6
  attribute_value = object.send(attribute)._dropdown_presentation rescue "<i class='fi-plus'></i>".html_safe
7
- link_to_inline_edit object, attribute, attribute_value
7
+ link_to_inline_edit object, attribute, attribute_value, from_callee: __callee__
8
8
  end
9
9
 
10
10
  def chicas_dropdown_with_family_members_edit(object, attribute)
@@ -21,7 +21,8 @@ def ckeditor_show(object, attribute)
21
21
  :class => "glass_plate",
22
22
  :title => '' ) +
23
23
  "<script>delete CKEDITOR.instances['textarea_#{object.class.name.underscore}_#{object.id}_#{attribute.to_s}']</script>".html_safe +
24
- '</div>'.html_safe
24
+ '</div>'.html_safe,
25
+ from_callee: __callee__
25
26
  end
26
27
 
27
28
  def ckeditor_edit(object, attribute)
@@ -3,7 +3,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:date_select]=:date
3
3
 
4
4
  # date
5
5
  def date_select_show(object, attribute)
6
- link_to_inline_edit object, attribute, object.send(attribute).nil? ? "<i class='fi-plus'></i>".html_safe : object.send(attribute).to_date.strftime("%d-%m-%Y")
6
+ link_to_inline_edit object, attribute, object.send(attribute).nil? ? "<i class='fi-plus'></i>".html_safe : object.send(attribute).to_date.strftime("%d-%m-%Y"), from_callee: __callee__
7
7
  end
8
8
 
9
9
  def date_select_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  InlineForms::SPECIAL_COLUMN_TYPES[:decimal_field]=:string
3
3
 
4
4
  def decimal_field_show(object, attribute)
5
- link_to_inline_edit object, attribute, object[attribute].nil? ? "<i class='fi-plus'></i>".html_safe : object[attribute]
5
+ link_to_inline_edit object, attribute, object[attribute].nil? ? "<i class='fi-plus'></i>".html_safe : object[attribute], from_callee: __callee__
6
6
  end
7
7
 
8
8
  def decimal_field_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  InlineForms::SPECIAL_COLUMN_TYPES[:devise_password_field]=:string
3
3
 
4
4
  def devise_password_field_show(object, attribute)
5
- link_to_inline_edit object, attribute, ''
5
+ link_to_inline_edit object, attribute, '', from_callee: __callee__
6
6
  end
7
7
 
8
8
  def devise_password_field_edit(object, attribute)
@@ -7,7 +7,7 @@ def dropdown_show(object, attribute)
7
7
  presentation = "_presentation"
8
8
  presentation = "_dropdown_presentation" if attr.respond_to? "_dropdown_presentation"
9
9
  attribute_value = object.send(attribute).send(presentation) rescue "<i class='fi-plus'></i>".html_safe
10
- link_to_inline_edit object, attribute, attribute_value
10
+ link_to_inline_edit object, attribute, attribute_value, from_callee: __callee__
11
11
  end
12
12
 
13
13
  def dropdown_edit(object, attribute)
@@ -7,7 +7,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:dropdown_with_integers]=:integer
7
7
  # values must be a Range or a one-dimensional array of Integers
8
8
  def dropdown_with_integers_show(object, attribute)
9
9
  values = attribute_values(object, attribute)
10
- link_to_inline_edit object, attribute, values[object.send(attribute)][1]
10
+ link_to_inline_edit object, attribute, values[object.send(attribute)][1], from_callee: __callee__
11
11
  end
12
12
 
13
13
  def dropdown_with_integers_edit(object, attribute)
@@ -12,7 +12,7 @@ def dropdown_with_other_show(object, attribute)
12
12
  else
13
13
  attribute_value = object.send(attribute)._presentation rescue "<i class='fi-plus'></i>".html_safe
14
14
  end
15
- link_to_inline_edit object, attribute, attribute_value
15
+ link_to_inline_edit object, attribute, attribute_value, from_callee: __callee__
16
16
  end
17
17
 
18
18
  def dropdown_with_other_edit(object, attribute)
@@ -4,7 +4,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:dropdown_with_values]=:integer
4
4
  # dropdown_with_values
5
5
  def dropdown_with_values_show(object, attribute)
6
6
  values = attribute_values(object, attribute)
7
- link_to_inline_edit object, attribute, object.send(attribute) ? t(values.assoc(object.send(attribute))[1]) : "<i class='fi-plus'></i>".html_safe
7
+ 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__
8
8
  end
9
9
 
10
10
  def dropdown_with_values_edit(object, attribute)
@@ -4,7 +4,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:dropdown_with_values_with_stars]=:integer
4
4
  # dropdown_with_values_with_stars
5
5
  def dropdown_with_values_with_stars_show(object, attribute)
6
6
  values = attribute_values(object, attribute)
7
- link_to_inline_edit object, attribute, (object[attribute].nil? || object[attribute] == 0) ? "<i class='fi-plus'></i>".html_safe : image_tag(object[attribute].to_s + 'stars.png')
7
+ link_to_inline_edit object, attribute, (object[attribute].nil? || object[attribute] == 0) ? "<i class='fi-plus'></i>".html_safe : image_tag(object[attribute].to_s + 'stars.png'), from_callee: __callee__
8
8
  end
9
9
  def dropdown_with_values_with_stars_edit(object, attribute)
10
10
  # 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!
@@ -7,7 +7,7 @@ def file_field_show(object, attribute)
7
7
  if o.send(:present?)
8
8
  msg = "replace | <a href='#{o.send(:url)}'>#{o.send(:path).gsub(/^.*\//,'')}</a>".html_safe
9
9
  end
10
- link_to_inline_edit object, attribute, msg
10
+ link_to_inline_edit object, attribute, msg, from_callee: __callee__
11
11
  end
12
12
 
13
13
  def file_field_edit(object, attribute)
@@ -4,7 +4,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:geo_code_curacao]=:string
4
4
  # geo_code_curacao
5
5
  def geo_code_curacao_show(object, attribute)
6
6
  attribute_value = GeoCodeCuracao.new(object.send(attribute)).presentation rescue nil
7
- link_to_inline_edit object, attribute, attribute_value
7
+ link_to_inline_edit object, attribute, attribute_value, from_callee: __callee__
8
8
  end
9
9
  def geo_code_curacao_edit(object, attribute)
10
10
  attribute_value = object.send(attribute).presentation rescue nil
@@ -11,7 +11,7 @@ def image_field_show(object, attribute)
11
11
  msg = image_tag(o.send(:url))
12
12
  end
13
13
  end
14
- link_to_inline_edit object, attribute, msg
14
+ link_to_inline_edit object, attribute, msg, from_callee: __callee__
15
15
  end
16
16
 
17
17
  def image_field_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  InlineForms::SPECIAL_COLUMN_TYPES[:integer_field]=:integer
3
3
 
4
4
  def integer_field_show(object, attribute)
5
- link_to_inline_edit object, attribute, object[attribute].nil? ? "<i class='fi-plus'></i>".html_safe : object[attribute]
5
+ link_to_inline_edit object, attribute, object[attribute].nil? ? "<i class='fi-plus'></i>".html_safe : object[attribute], from_callee: __callee__
6
6
  end
7
7
 
8
8
  def integer_field_edit(object, attribute)
@@ -30,7 +30,7 @@ def kansen_slider_show(object, attribute)
30
30
  </script>').html_safe
31
31
  out << "</div>".html_safe
32
32
  end
33
- link_to_inline_edit object, attribute, out
33
+ link_to_inline_edit object, attribute, out, from_callee: __callee__
34
34
  end
35
35
 
36
36
  def kansen_slider_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  InlineForms::SPECIAL_COLUMN_TYPES[:money_field]=:integer
3
3
 
4
4
  def money_field_show(object, attribute)
5
- link_to_inline_edit object, attribute, humanized_money_with_symbol(object.send attribute)
5
+ link_to_inline_edit object, attribute, humanized_money_with_symbol(object.send attribute), from_callee: __callee__
6
6
  end
7
7
 
8
8
  def money_field_edit(object, attribute)
@@ -3,7 +3,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:month_select]=:integer
3
3
 
4
4
  # date
5
5
  def month_select_show(object, attribute)
6
- link_to_inline_edit object, attribute, (1..12).include?(object[attribute]) ? I18n.localize(Date.new(1970,object[attribute],1), :format => '%B') : "<i class='fi-plus'></i>".html_safe
6
+ link_to_inline_edit object, attribute, (1..12).include?(object[attribute]) ? I18n.localize(Date.new(1970,object[attribute],1), :format => '%B') : "<i class='fi-plus'></i>".html_safe, from_callee: __callee__
7
7
  end
8
8
 
9
9
  def month_select_edit(object, attribute)
@@ -3,7 +3,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:month_year_picker]=:date
3
3
 
4
4
  # date
5
5
  def month_year_picker_show(object, attribute)
6
- link_to_inline_edit object, attribute, object.send(attribute).nil? ? "<i class='fi-plus'></i>".html_safe : object.send(attribute).strftime("%B %Y")
6
+ link_to_inline_edit object, attribute, object.send(attribute).nil? ? "<i class='fi-plus'></i>".html_safe : object.send(attribute).strftime("%B %Y"), from_callee: __callee__
7
7
  end
8
8
 
9
9
  def month_year_picker_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  #InlineForms::SPECIAL_COLUMN_TYPES[:text_field]=:string
3
3
 
4
4
  def move_show(object, attribute)
5
- link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe
5
+ link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe, from_callee: __callee__
6
6
  end
7
7
 
8
8
  def move_edit(object, attribute)
@@ -11,7 +11,7 @@ def multi_image_field_show(object, attribute)
11
11
  msg = image_tag(o.send(:url))
12
12
  end
13
13
  end
14
- link_to_inline_edit object, attribute, msg
14
+ link_to_inline_edit object, attribute, msg, from_callee: __callee__
15
15
  end
16
16
 
17
17
  def multi_image_field_edit(object, attribute)
@@ -2,7 +2,7 @@
2
2
  InlineForms::SPECIAL_COLUMN_TYPES[:plain_text_area]=:text
3
3
 
4
4
  def plain_text_area_show(object, attribute)
5
- link_to_inline_edit object, attribute, (object[attribute].nil? || object[attribute].empty?) ? "<i class='fi-plus'></i>".html_safe : object[attribute]
5
+ link_to_inline_edit object, attribute, (object[attribute].nil? || object[attribute].empty?) ? "<i class='fi-plus'></i>".html_safe : object[attribute], from_callee: __callee__
6
6
  end
7
7
 
8
8
  def plain_text_area_edit(object, attribute)
@@ -4,10 +4,10 @@
4
4
  # checklist
5
5
  def question_list_show(object, attribute)
6
6
  out = '<ul class="question_list">'
7
- out << link_to_inline_edit(object, attribute) if object.send(attribute).empty?
7
+ out << link_to_inline_edit(object, attribute, from_callee: __callee__) if object.send(attribute).empty?
8
8
  object.send(attribute).sort.each do | item |
9
9
  out << '<li>'
10
- out << link_to_inline_edit(object, attribute, item._presentation )
10
+ out << link_to_inline_edit(object, attribute, item._presentation, from_callee: __callee__ )
11
11
  out << '</li>'
12
12
  end
13
13
  out << '</ul>'
@@ -6,7 +6,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:radio_button]=:integer
6
6
 
7
7
  def radio_button_show(object, attribute)
8
8
  values = attribute_values(object, attribute)
9
- link_to_inline_edit object, attribute, object.send(attribute) ? values.assoc(object.send(attribute))[1] : ""
9
+ link_to_inline_edit object, attribute, object.send(attribute) ? values.assoc(object.send(attribute))[1] : "", from_callee: __callee__
10
10
  end
11
11
 
12
12
  def radio_button_edit(object, attribute)
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+ InlineForms::SPECIAL_COLUMN_TYPES[:rich_text]=:no_migration
3
+
4
+ def rich_text_show(object, attribute)
5
+ rich = object.respond_to?(attribute) ? object.public_send(attribute) : nil
6
+ is_blank =
7
+ rich.nil? ||
8
+ (rich.respond_to?(:blank?) && rich.blank?) ||
9
+ (rich.respond_to?(:to_plain_text) && rich.to_plain_text.to_s.strip.empty?)
10
+ display_value = is_blank ? "<i class='fi-plus'></i>".html_safe : rich.to_s.html_safe
11
+ link_to_inline_edit object, attribute, display_value, from_callee: __callee__
12
+ end
13
+
14
+ def rich_text_edit(object, attribute)
15
+ rich = object.respond_to?(attribute) ? object.public_send(attribute) : nil
16
+ body =
17
+ if rich.respond_to?(:body) && !rich.body.nil?
18
+ rich.body.to_s
19
+ elsif rich.respond_to?(:to_s)
20
+ rich.to_s
21
+ else
22
+ ''
23
+ end
24
+ input_id = "trix_input_#{object.class.name.underscore}_#{object.id || 'new'}_#{attribute}"
25
+ hidden_field_tag(attribute, body, id: input_id) +
26
+ content_tag(:'trix-editor', ''.html_safe, input: input_id, class: 'trix-content attribute_rich_text_area')
27
+ end
28
+
29
+ def rich_text_update(object, attribute)
30
+ object.public_send("#{attribute}=", params[attribute.to_sym])
31
+ end
32
+
33
+ def rich_text_info(object, attribute)
34
+ value = object.respond_to?(attribute) ? object.public_send(attribute) : nil
35
+ value.to_s
36
+ end
@@ -8,7 +8,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:scale_with_integers]=:integer
8
8
  #
9
9
  def scale_with_integers_show(object, attribute)
10
10
  values = attribute_values(object, attribute)
11
- link_to_inline_edit object, attribute, values[object.send(attribute).to_s]
11
+ link_to_inline_edit object, attribute, values[object.send(attribute).to_s], from_callee: __callee__
12
12
  end
13
13
 
14
14
  def scale_with_integers_edit(object, attribute)
@@ -7,7 +7,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:scale_with_values]=:integer
7
7
  # values must be a hash { integer => string, ... } or an one-dimensional array of strings
8
8
  def scale_with_values_show(object, attribute)
9
9
  values = attribute_values(object, attribute)
10
- link_to_inline_edit object, attribute, values[object.send(attribute)][1]
10
+ link_to_inline_edit object, attribute, values[object.send(attribute)][1], from_callee: __callee__
11
11
  end
12
12
 
13
13
  def scale_with_values_edit(object, attribute)
@@ -9,7 +9,7 @@ def simple_file_field_show(object, attribute)
9
9
  model = object.class.to_s.pluralize.underscore
10
10
  link_to filename, "/#{model}/#{method}/#{object.id}" # route must exist!!
11
11
  else
12
- link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe
12
+ link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe, from_callee: __callee__
13
13
  end
14
14
  end
15
15
 
@@ -31,7 +31,7 @@ def slider_with_values_show(object, attribute)
31
31
  });
32
32
  </script>').html_safe
33
33
  end
34
- link_to_inline_edit object, attribute, out
34
+ link_to_inline_edit object, attribute, out, from_callee: __callee__
35
35
  end
36
36
 
37
37
  def slider_with_values_edit(object, attribute)
@@ -3,7 +3,7 @@ InlineForms::SPECIAL_COLUMN_TYPES[:text_area]=:text
3
3
 
4
4
  def text_area_show(object, attribute)
5
5
  if object.send(attribute).blank?
6
- link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe
6
+ link_to_inline_edit object, attribute, "<i class='fi-plus'></i>".html_safe, from_callee: __callee__
7
7
  else
8
8
  if defined? Ckeditor
9
9
  link_to_inline_edit object,
@@ -25,9 +25,10 @@ def text_area_show(object, attribute)
25
25
  :class => "glass_plate",
26
26
  :title => '' ) +
27
27
  "<script>delete CKEDITOR.instances['textarea_#{object.class.name.underscore}_#{object.id}_#{attribute.to_s}']</script>".html_safe +
28
- '</div>'.html_safe
28
+ '</div>'.html_safe,
29
+ from_callee: __callee__
29
30
  else
30
- link_to_inline_edit object, attribute, object[attribute]
31
+ link_to_inline_edit object, attribute, object[attribute], from_callee: __callee__
31
32
  end
32
33
  end
33
34
  end