inline_forms 6.3.3 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +107 -0
- data/README.rdoc +8 -0
- data/app/helpers/form_elements/rich_text.rb +36 -0
- data/app/helpers/inline_forms_helper.rb +40 -0
- data/app/views/inline_forms/_edit.html.erb +1 -1
- data/app/views/inline_forms/_versions_list.html.erb +30 -14
- data/app/views/layouts/application.html.erb +3 -1
- data/app/views/layouts/inline_forms.html.erb +3 -1
- data/bin/inline_forms +1 -1
- data/bin/inline_forms_installer_core.rb +71 -31
- data/docs/prompt/.gitignore +5 -0
- data/docs/prompt/test-the-example-app.md +32 -0
- data/inline_forms.gemspec +1 -1
- data/lib/generators/inline_forms_generator.rb +30 -0
- data/lib/generators/templates/migration.erb +1 -1
- data/lib/generators/templates/model.erb +1 -0
- data/lib/inline_forms/version.rb +1 -1
- data/lib/installer_templates/example_app_tests/test/models/example_app_paper_trail_changeset_test.rb +78 -0
- data/test/inline_forms_generator_test.rb +155 -0
- metadata +10 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 46c8d9d11975c43765ea29ed896933ac0dc63b64d1b23ae97d7239e2005c1190
|
|
4
|
+
data.tar.gz: 531398598e0d12f391f3f61a95c445cc2d9bc9ff9b507c1eaead1c48bb871f19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb3d95164a8a6ac18e1362d18be11e66a264f7038f9d229f3e5bd4abe38ea46fade6d619932c01e1eea91dbd794bfe54c5f255e110125d38851c0a0c48f72b93
|
|
7
|
+
data.tar.gz: 1c58dda2e716ae74e4e2dc3d737bf17ad1e8af168e7eb0625bd410217d37a6f1ac7591825b851ddc5cae9d204f9aaeeabd1aeb89bacdfcd3d3824989f947d18d
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,113 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
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
|
+
|
|
7
114
|
## [6.3.3] - 2026-05-03
|
|
8
115
|
|
|
9
116
|
### Added
|
data/README.rdoc
CHANGED
|
@@ -36,6 +36,14 @@ Then point your browser to http://localhost:3000/apartments and log in with admi
|
|
|
36
36
|
|
|
37
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
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
|
+
|
|
39
47
|
= Build a vagrant virtualbox box for easier development
|
|
40
48
|
|
|
41
49
|
Go ahead and unzip lib/vagrant/vagrantbox-inline_forms.zip. Enter the created directory with
|
|
@@ -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
|
|
@@ -12,6 +12,46 @@ module InlineFormsHelper
|
|
|
12
12
|
InlineForms::VERSION
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# Returns versions for `object`, merged with versions of any associated
|
|
16
|
+
# `ActionText::RichText` records (Rails `has_rich_text :foo` declarations).
|
|
17
|
+
#
|
|
18
|
+
# Rich-text bodies live in the polymorphic `action_text_rich_texts` table,
|
|
19
|
+
# so `has_paper_trail` on the parent model (e.g. Apartment) never sees
|
|
20
|
+
# rich-text edits. The generated app installs an initializer
|
|
21
|
+
# (`config/initializers/rich_text_paper_trail.rb`) that declares
|
|
22
|
+
# `has_paper_trail` on `ActionText::RichText` itself; this helper is what
|
|
23
|
+
# surfaces those versions inside the parent's versions list view
|
|
24
|
+
# (`app/views/inline_forms/_versions_list.html.erb`).
|
|
25
|
+
#
|
|
26
|
+
# Each entry is a Hash:
|
|
27
|
+
# :version => the PaperTrail::Version
|
|
28
|
+
# :kind => :primary (parent model) or :rich_text
|
|
29
|
+
# :rich_text_name => for :rich_text entries, the attribute name
|
|
30
|
+
# (e.g. "description"); nil for :primary
|
|
31
|
+
#
|
|
32
|
+
# Sorted oldest-first (callers can `.reverse` for newest-first display).
|
|
33
|
+
def inline_forms_versions_for(object)
|
|
34
|
+
entries = object.versions.map do |v|
|
|
35
|
+
{ version: v, kind: :primary, rich_text_name: nil }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if defined?(ActionText::RichText)
|
|
39
|
+
ActionText::RichText
|
|
40
|
+
.where(record_type: object.class.base_class.name, record_id: object.id)
|
|
41
|
+
.each do |rich_text|
|
|
42
|
+
rich_text.versions.each do |v|
|
|
43
|
+
entries << {
|
|
44
|
+
version: v,
|
|
45
|
+
kind: :rich_text,
|
|
46
|
+
rich_text_name: rich_text.name
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
entries.sort_by { |entry| entry[:version].created_at }
|
|
53
|
+
end
|
|
54
|
+
|
|
15
55
|
private
|
|
16
56
|
|
|
17
57
|
def validation_hints_as_list_for(object, attribute)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<% path_to_object = @object.class.to_s.underscore + '_path' %>
|
|
2
2
|
<% css_class_id = "#{@object.class.name.underscore}_#{@object.id}_versions" -%>
|
|
3
|
+
<% entries = inline_forms_versions_for(@object) -%>
|
|
3
4
|
<div class="row form_element_header associated_auto_header callout">
|
|
4
5
|
<div class='medium-11 large-11 column' >
|
|
5
|
-
<%= "Versions (#{
|
|
6
|
+
<%= "Versions (#{entries.length})" %>
|
|
6
7
|
</div>
|
|
7
8
|
<div class='medium-1 large-1 column'>
|
|
8
9
|
<%= close_versions_list_link(
|
|
@@ -29,20 +30,26 @@
|
|
|
29
30
|
</div>
|
|
30
31
|
</div>
|
|
31
32
|
<div class="row <%= cycle('odd', 'even') %>">
|
|
32
|
-
<%
|
|
33
|
+
<% entries.reverse.each do |entry| %>
|
|
34
|
+
<% version = entry[:version] -%>
|
|
35
|
+
<% rich_text_name = entry[:rich_text_name] -%>
|
|
33
36
|
<div class='small-12 column'>
|
|
34
37
|
<div class="small-1 column">
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
<% if entry[:kind] == :primary %>
|
|
39
|
+
<%= link_to t('inline_forms.view.restore'),
|
|
40
|
+
send('revert_' + @object.class.to_s.underscore + "_path",
|
|
41
|
+
version,
|
|
42
|
+
:update => "#{@object.class.name.underscore}_#{@object.id}"
|
|
43
|
+
),
|
|
44
|
+
:remote => true,
|
|
45
|
+
:method => :post
|
|
46
|
+
%>
|
|
47
|
+
<% else %>
|
|
48
|
+
|
|
49
|
+
<% end %>
|
|
43
50
|
</div>
|
|
44
51
|
<div class="small-1 column">
|
|
45
|
-
<%= version.event
|
|
52
|
+
<%= version.event -%><% if entry[:kind] == :rich_text %> <em>(rich text)</em><% end %>
|
|
46
53
|
</div>
|
|
47
54
|
<div class="small-2 column">
|
|
48
55
|
<%= version.created_at -%>
|
|
@@ -56,9 +63,13 @@
|
|
|
56
63
|
<% else %>
|
|
57
64
|
<% version.changeset.each do |attribute, value| %>
|
|
58
65
|
<% next if attribute == 'updated_at' %>
|
|
66
|
+
<% next if entry[:kind] == :rich_text && attribute == 'record_id' %>
|
|
67
|
+
<% next if entry[:kind] == :rich_text && attribute == 'record_type' %>
|
|
68
|
+
<% next if entry[:kind] == :rich_text && attribute == 'name' %>
|
|
69
|
+
<% display_attribute = entry[:kind] == :rich_text && attribute == 'body' ? rich_text_name : attribute -%>
|
|
59
70
|
<table>
|
|
60
71
|
<tr>
|
|
61
|
-
<th colspan="2" class="text-center"><%=
|
|
72
|
+
<th colspan="2" class="text-center"><%= display_attribute %></th>
|
|
62
73
|
<th></th>
|
|
63
74
|
</tr>
|
|
64
75
|
<tr>
|
|
@@ -66,8 +77,13 @@
|
|
|
66
77
|
<td>new value</td>
|
|
67
78
|
</tr>
|
|
68
79
|
<tr>
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
<% if entry[:kind] == :rich_text && attribute == 'body' %>
|
|
81
|
+
<td><%= raw value[0] %></td>
|
|
82
|
+
<td><%= raw value[1] %></td>
|
|
83
|
+
<% else %>
|
|
84
|
+
<td><%= value[0] %></td>
|
|
85
|
+
<td><%= value[1] %></td>
|
|
86
|
+
<% end %>
|
|
71
87
|
</tr>
|
|
72
88
|
</table>
|
|
73
89
|
<% end %>
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
<%= t('inline_forms.general.application_title') %> v<%= InlineForms::VERSION %>
|
|
8
8
|
</title>
|
|
9
9
|
<%= stylesheet_link_tag "application" %>
|
|
10
|
+
<%= stylesheet_link_tag "https://unpkg.com/trix@1.3.1/dist/trix.css" %>
|
|
10
11
|
<%= csrf_meta_tags %>
|
|
11
12
|
</head>
|
|
12
13
|
|
|
13
14
|
<body>
|
|
14
15
|
<%= yield %>
|
|
15
16
|
<%= javascript_include_tag "application", 'data-turbolinks-track' => true %>
|
|
16
|
-
<%= javascript_include_tag
|
|
17
|
+
<%= javascript_include_tag "https://unpkg.com/trix@1.3.1/dist/trix.js" %>
|
|
18
|
+
<%= javascript_include_tag Ckeditor.cdn_url if defined?(Ckeditor) %>
|
|
17
19
|
</body>
|
|
18
20
|
</html>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<title><%= t('application_name') + " v" + InlineForms::VERSION -%></title>
|
|
7
7
|
<%= stylesheet_link_tag "application" %>
|
|
8
8
|
<%= stylesheet_link_tag "inline_forms/inline_forms" %>
|
|
9
|
+
<%= stylesheet_link_tag "https://unpkg.com/trix@1.3.1/dist/trix.css" %>
|
|
9
10
|
<%= csrf_meta_tags %>
|
|
10
11
|
</head>
|
|
11
12
|
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
<%= yield %>
|
|
17
18
|
</div>
|
|
18
19
|
<%= javascript_include_tag 'inline_forms/inline_forms', 'data-turbolinks-track' => true %>
|
|
19
|
-
<%= javascript_include_tag
|
|
20
|
+
<%= javascript_include_tag "https://unpkg.com/trix@1.3.1/dist/trix.js" %>
|
|
21
|
+
<%= javascript_include_tag Ckeditor.cdn_url if defined?(Ckeditor) %>
|
|
20
22
|
</body>
|
|
21
23
|
</html>
|
data/bin/inline_forms
CHANGED
|
@@ -110,7 +110,7 @@ module InlineForms
|
|
|
110
110
|
|
|
111
111
|
app_template_file = File.join(File.dirname(__FILE__), 'inline_forms_app_template.rb')
|
|
112
112
|
|
|
113
|
-
if ! run("rails new #{app_name} -m #{app_template_file} --skip-bundle --skip-
|
|
113
|
+
if ! run("rails new #{app_name} -m #{app_template_file} --skip-bundle --skip-bootsnap --javascript=importmap")
|
|
114
114
|
say "Rails could not create the app '#{app_name}', maybe because it is a reserved word...", :red # TODO ROYTJE MAKE ERROR MESSAGE MORE RELEVANT # Rails could not create the app 'MyApp', maybe because it is a reserved word..
|
|
115
115
|
exit 1
|
|
116
116
|
end
|
|
@@ -1,42 +1,46 @@
|
|
|
1
1
|
GENERATOR_PATH = File.dirname(File.expand_path(__FILE__)) + '/../'
|
|
2
2
|
|
|
3
|
+
# Rails 7 dropped --skip-gemfile, so `rails new` always writes its own Gemfile.
|
|
4
|
+
# Remove it so our `create_file` below does not prompt for overwrite.
|
|
5
|
+
remove_file 'Gemfile' if File.exist?('Gemfile')
|
|
3
6
|
create_file 'Gemfile', "# created by inline_forms #{ENV['inline_forms_version']} on #{Date.today}\n"
|
|
4
7
|
|
|
5
8
|
add_source 'https://rubygems.org'
|
|
6
9
|
|
|
7
10
|
gem 'cancancan'
|
|
8
|
-
gem 'carrierwave'
|
|
9
|
-
gem 'ckeditor', github: 'galetahub/ckeditor'
|
|
10
|
-
gem 'coffee-rails'
|
|
11
|
+
gem 'carrierwave', '~> 3.1'
|
|
11
12
|
gem 'devise-i18n', :git => 'https://github.com/acesuares/devise-i18n.git'
|
|
12
13
|
gem 'devise'
|
|
13
14
|
gem 'foundation-icons-sass-rails'
|
|
14
15
|
gem 'foundation-rails', '~> 5.5'
|
|
15
16
|
gem 'i18n-active_record', :git => 'https://github.com/acesuares/i18n-active_record.git'
|
|
16
|
-
gem 'inline_forms',
|
|
17
|
+
gem 'inline_forms', path: "#{File.expand_path(GENERATOR_PATH)}"
|
|
17
18
|
gem 'jquery-rails'
|
|
18
19
|
gem 'jquery-timepicker-rails'
|
|
19
20
|
gem 'jquery-ui-sass-rails'
|
|
20
21
|
gem 'mini_magick'
|
|
21
22
|
gem 'mysql2'
|
|
22
|
-
gem 'paper_trail',
|
|
23
|
-
# RubyGems 7.0.x requires railties >= 6, < 8 (works with Rails 6.1). The default branch of
|
|
24
|
-
# https://github.com/svenfuchs/rails-i18n.git targets Rails 8+ (railties >= 8) and breaks bundle
|
|
25
|
-
# resolution next to rails 6.1.3.1. Same approach as the Papiamentu app.
|
|
23
|
+
gem 'paper_trail', '~> 16.0'
|
|
26
24
|
gem 'rails-i18n', '~> 7.0'
|
|
27
25
|
gem 'rails-jquery-autocomplete'
|
|
28
|
-
gem 'rails', '
|
|
26
|
+
gem 'rails', '~> 7.0.0'
|
|
29
27
|
gem 'rake'
|
|
30
28
|
gem 'remotipart', '~> 1.0'
|
|
31
29
|
gem 'rvm'
|
|
32
30
|
gem 'sass-rails'
|
|
31
|
+
# Rails 7 no longer adds sprockets-rails to the default Gemfile; declare it
|
|
32
|
+
# explicitly because the gem's own assets (foundation, jquery, etc.) live in
|
|
33
|
+
# app/assets and rely on the Sprockets pipeline.
|
|
34
|
+
gem 'sprockets-rails'
|
|
35
|
+
# Rails 7 default JavaScript tooling: importmap-rails replaces Webpacker.
|
|
36
|
+
gem 'importmap-rails'
|
|
33
37
|
gem 'tabs_on_rails', :git => 'https://github.com/acesuares/tabs_on_rails.git', :branch => 'update_remote_before_action'
|
|
34
38
|
gem 'unicorn'
|
|
35
39
|
gem 'validation_hints'
|
|
36
40
|
gem 'will_paginate' #, git: 'https://github.com/acesuares/will_paginate.git'
|
|
37
41
|
|
|
38
42
|
gem_group :test do
|
|
39
|
-
# Rails
|
|
43
|
+
# Rails 7 still expects Minitest 5; 6.x breaks the railties test runner.
|
|
40
44
|
gem 'minitest', '~> 5.25'
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -157,7 +161,7 @@ create_file "db/migrate/" +
|
|
|
157
161
|
Time.now.utc.strftime("%Y%m%d%H%M%S") +
|
|
158
162
|
"_" +
|
|
159
163
|
"devise_create_users.rb", <<-DEVISE_MIGRATION.strip_heredoc
|
|
160
|
-
class DeviseCreateUsers < ActiveRecord::Migration[
|
|
164
|
+
class DeviseCreateUsers < ActiveRecord::Migration[7.0]
|
|
161
165
|
|
|
162
166
|
def change
|
|
163
167
|
create_table(:users) do |t|
|
|
@@ -310,7 +314,7 @@ create_file "db/migrate/" +
|
|
|
310
314
|
Time.now.utc.strftime("%Y%m%d%H%M%S") +
|
|
311
315
|
"_" +
|
|
312
316
|
"inline_forms_create_join_table_user_role.rb", <<-ROLES_MIGRATION.strip_heredoc
|
|
313
|
-
class InlineFormsCreateJoinTableUserRole < ActiveRecord::Migration[
|
|
317
|
+
class InlineFormsCreateJoinTableUserRole < ActiveRecord::Migration[7.0]
|
|
314
318
|
def self.up
|
|
315
319
|
create_table :roles_users, :id => false, :force => true do |t|
|
|
316
320
|
t.integer :role_id
|
|
@@ -336,27 +340,63 @@ say "- Add human_attribute_name in app/models/application_record.rb"
|
|
|
336
340
|
remove_file 'app/models/application_record.rb' # the one that 'rails new' created
|
|
337
341
|
copy_file File.join(GENERATOR_PATH, 'lib/generators/templates/application_record.rb'), "app/models/application_record.rb"
|
|
338
342
|
|
|
339
|
-
say "- Install
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
empty_directory "app/assets/javascripts/ckeditor"
|
|
344
|
-
copy_file File.join(GENERATOR_PATH,'lib/generators/assets/javascripts/ckeditor/config.js'), "app/assets/javascripts/ckeditor/config.js"
|
|
345
|
-
|
|
346
|
-
say "- Add ckeditor/config.js to precompile assets..."
|
|
347
|
-
append_to_file 'config/initializers/assets.rb',
|
|
348
|
-
'Rails.application.config.assets.precompile += %w[ckeditor/config.js]'
|
|
343
|
+
say "- Install ActionText..."
|
|
344
|
+
run "bundle exec rails active_storage:install"
|
|
345
|
+
run "bundle exec rails action_text:install:migrations"
|
|
346
|
+
run "bundle install"
|
|
349
347
|
|
|
350
348
|
say "- Paper_trail install..."
|
|
351
|
-
#
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
end
|
|
349
|
+
# Upstream paper_trail (>= 13) detects MySQL via the live ActiveRecord connection,
|
|
350
|
+
# so the migration's InnoDB options are added only when the dev DB is mysql.
|
|
351
|
+
# For mysql installs the user has been instructed above to create the development
|
|
352
|
+
# database before continuing; for sqlite the file is created on first connection.
|
|
353
|
+
generate "paper_trail:install --with-changes"
|
|
357
354
|
# paper_trail emits two migrations in one second; the next generator would reuse that timestamp.
|
|
358
355
|
sleep 1
|
|
359
356
|
|
|
357
|
+
say "- Track ActionText (rich_text) edits with PaperTrail..."
|
|
358
|
+
# `has_rich_text :foo` stores the body in the separate `action_text_rich_texts`
|
|
359
|
+
# table, not on the parent model, so `has_paper_trail` on the parent never
|
|
360
|
+
# sees rich_text edits. The standard fix (recommended by paper_trail's
|
|
361
|
+
# maintainer in https://stackoverflow.com/q/55544935) is to declare
|
|
362
|
+
# `has_paper_trail` directly on `ActionText::RichText`. We surface those
|
|
363
|
+
# versions in the parent's versions panel from `inline_forms_versions_for`.
|
|
364
|
+
#
|
|
365
|
+
# Note: PaperTrail >= 16 raises if `has_paper_trail` is called twice on the
|
|
366
|
+
# same model, so this initializer must be the only place it's added to
|
|
367
|
+
# `ActionText::RichText` in the generated app.
|
|
368
|
+
create_file 'config/initializers/rich_text_paper_trail.rb', <<-PT_RICH_TEXT.strip_heredoc
|
|
369
|
+
# Generated by inline_forms.
|
|
370
|
+
ActiveSupport.on_load(:action_text_rich_text) do
|
|
371
|
+
has_paper_trail
|
|
372
|
+
end
|
|
373
|
+
PT_RICH_TEXT
|
|
374
|
+
|
|
375
|
+
say "- Configure ActiveRecord YAML permitted classes for PaperTrail changesets..."
|
|
376
|
+
# PaperTrail's YAML serializer (>= 13) uses `YAML.safe_load` and reads its
|
|
377
|
+
# allow-list from `ActiveRecord.yaml_column_permitted_classes`. Rails 7's
|
|
378
|
+
# default is `[Symbol]`, so any update that touches `updated_at`
|
|
379
|
+
# (an `ActiveSupport::TimeWithZone`) raises `Psych::DisallowedClass` inside
|
|
380
|
+
# `version.changeset`; PaperTrail rescues that and returns `{}`, which is why
|
|
381
|
+
# the inline_forms versions list rendered every changeset as `empty`. Permit
|
|
382
|
+
# the classes PT actually emits so `version.changeset` round-trips.
|
|
383
|
+
create_file 'config/initializers/paper_trail_yaml_safe_load.rb', <<-PT_YAML.strip_heredoc
|
|
384
|
+
# Generated by inline_forms.
|
|
385
|
+
# See https://github.com/paper-trail-gem/paper_trail and
|
|
386
|
+
# ActiveRecord::Coders::YAMLColumn safe-loading rules.
|
|
387
|
+
Rails.application.config.active_record.yaml_column_permitted_classes ||= []
|
|
388
|
+
Rails.application.config.active_record.yaml_column_permitted_classes |= [
|
|
389
|
+
Symbol,
|
|
390
|
+
Date,
|
|
391
|
+
Time,
|
|
392
|
+
BigDecimal,
|
|
393
|
+
ActiveSupport::TimeWithZone,
|
|
394
|
+
ActiveSupport::TimeZone,
|
|
395
|
+
ActiveSupport::HashWithIndifferentAccess
|
|
396
|
+
]
|
|
397
|
+
ActiveRecord.yaml_column_permitted_classes |= Rails.application.config.active_record.yaml_column_permitted_classes
|
|
398
|
+
PT_YAML
|
|
399
|
+
|
|
360
400
|
# Create Translations
|
|
361
401
|
say "- Generate models and tables and views for translations..." # TODO Translations need to be done in inline_forms, and then generate a yml file, perhaps
|
|
362
402
|
generate "inline_forms", "InlineFormsLocale name:string inline_forms_translations:belongs_to _enabled:yes _presentation:\#{name}"
|
|
@@ -370,7 +410,7 @@ create_file "db/migrate/" +
|
|
|
370
410
|
Time.now.utc.strftime("%Y%m%d%H%M%S") +
|
|
371
411
|
"_" +
|
|
372
412
|
"inline_forms_create_view_for_translations.rb", <<-VIEW_MIGRATION.strip_heredoc
|
|
373
|
-
class InlineFormsCreateViewForTranslations < ActiveRecord::Migration[
|
|
413
|
+
class InlineFormsCreateViewForTranslations < ActiveRecord::Migration[7.0]
|
|
374
414
|
def self.up
|
|
375
415
|
execute 'CREATE VIEW translations
|
|
376
416
|
AS
|
|
@@ -578,9 +618,9 @@ git commit: " -a -m 'Initial Commit'"
|
|
|
578
618
|
# example
|
|
579
619
|
if ENV['install_example'] == 'true'
|
|
580
620
|
say "\nInstalling example application..."
|
|
581
|
-
run 'bundle exec rails g inline_forms Photo name:string caption:string image:image_field description:
|
|
621
|
+
run 'bundle exec rails g inline_forms Photo name:string caption:string image:image_field description:rich_text apartment:belongs_to _presentation:\'#{name}\''
|
|
582
622
|
run 'bundle exec rails generate uploader Image'
|
|
583
|
-
run 'bundle exec rails g inline_forms Apartment name:string title:string description:
|
|
623
|
+
run 'bundle exec rails g inline_forms Apartment name:string title:string description:rich_text photos:has_many photos:associated _enabled:yes _presentation:\'#{name}\''
|
|
584
624
|
run 'bundle exec rake db:migrate'
|
|
585
625
|
|
|
586
626
|
remove_file 'public/index.html'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
You are in the inline_forms gem repo at /home/code/inline_forms.
|
|
2
|
+
|
|
3
|
+
Goal:
|
|
4
|
+
Build the current gem, install it into /home/code/testInline, recreate MyApp from scratch using --example, and verify it with Rails tests.
|
|
5
|
+
|
|
6
|
+
Do all steps end-to-end without asking for confirmation unless a command fails.
|
|
7
|
+
|
|
8
|
+
Steps:
|
|
9
|
+
1) In /home/code/inline_forms:
|
|
10
|
+
- Ensure latest code is used.
|
|
11
|
+
- Run: rvm use .
|
|
12
|
+
- Build gem: gem build inline_forms.gemspec
|
|
13
|
+
- Confirm the built file name/version (inline_forms-<version>.gem).
|
|
14
|
+
|
|
15
|
+
2) In /home/code/testInline:
|
|
16
|
+
- Remove old app if present: /home/code/testInline/MyApp
|
|
17
|
+
- Run: rvm use .
|
|
18
|
+
- Install the freshly built gem from /home/code/inline_forms/inline_forms-<version>.gem
|
|
19
|
+
|
|
20
|
+
3) Still in /home/code/testInline:
|
|
21
|
+
- Generate fresh example app:
|
|
22
|
+
inline_forms create MyApp -d sqlite --example
|
|
23
|
+
|
|
24
|
+
4) In /home/code/testInline/MyApp:
|
|
25
|
+
- Run: rvm use .
|
|
26
|
+
- Run verification: bundle exec rails test
|
|
27
|
+
|
|
28
|
+
Output requirements:
|
|
29
|
+
- Briefly report each phase result (build, install, app generation, test run).
|
|
30
|
+
- Include exact commands run.
|
|
31
|
+
- Include test summary (runs/assertions/failures/errors/skips).
|
|
32
|
+
- If anything fails, stop at the failing step and include the exact error and the next corrective command you recommend.
|
data/inline_forms.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
s.add_dependency('rvm')
|
|
24
24
|
s.add_dependency('thor')
|
|
25
25
|
s.add_dependency('validation_hints')
|
|
26
|
-
s.add_dependency('rails', '>=
|
|
26
|
+
s.add_dependency('rails', '>= 7.0.0', '< 7.1')
|
|
27
27
|
s.add_dependency('rails-i18n')
|
|
28
28
|
|
|
29
29
|
s.add_development_dependency("minitest", "~> 5.0")
|
|
@@ -19,6 +19,18 @@ module InlineForms
|
|
|
19
19
|
#
|
|
20
20
|
class InlineFormsGenerator < Rails::Generators::NamedBase
|
|
21
21
|
Rails::Generators::GeneratedAttribute.class_eval do #:doc:
|
|
22
|
+
# Override Rails::Generators::GeneratedAttribute.valid_type? so that our
|
|
23
|
+
# custom field types (dropdown, check_list, image_field, rich_text, ...)
|
|
24
|
+
# pass through parsing. We do our own unknown-type detection later (with
|
|
25
|
+
# Thor::Error + --allow-unknown), so it is safe to accept everything here.
|
|
26
|
+
#
|
|
27
|
+
# Rails 6.1 used to rescue ActiveRecord::Base.connection failures, which
|
|
28
|
+
# masked the issue; Rails 7+ raises NameError when ActiveRecord is not
|
|
29
|
+
# loaded yet, breaking generator unit tests.
|
|
30
|
+
def self.valid_type?(_type)
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
22
34
|
# Deducts the column_type for migrations from the type.
|
|
23
35
|
#
|
|
24
36
|
# We first merge the Special Column Types with the Default Column Types,
|
|
@@ -71,6 +83,7 @@ module InlineForms
|
|
|
71
83
|
|
|
72
84
|
end
|
|
73
85
|
argument :attributes, :type => :array, :banner => "[name:form_element]..."
|
|
86
|
+
class_option :allow_unknown, :type => :boolean, :default => false, :desc => "Allow unknown field types (legacy behavior: comment generated lines instead of failing)."
|
|
74
87
|
|
|
75
88
|
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
|
76
89
|
|
|
@@ -80,11 +93,24 @@ module InlineForms
|
|
|
80
93
|
@flag_create_migration = true
|
|
81
94
|
@flag_create_model = true
|
|
82
95
|
@create_id = true
|
|
96
|
+
@unknown_attributes = []
|
|
83
97
|
for attribute in attributes
|
|
84
98
|
@flag_not_accessible_through_html = false if attribute.name == '_enabled'
|
|
85
99
|
@flag_create_migration = false if attribute.name == '_no_migration'
|
|
86
100
|
@flag_create_model = false if attribute.name == '_no_model'
|
|
87
101
|
@create_id = false if attribute.name == "_id" && attribute.type == :false
|
|
102
|
+
if !attribute.name.start_with?('_') && (
|
|
103
|
+
(attribute.attribute? && attribute.attribute_type == :unknown) ||
|
|
104
|
+
(attribute.migration? && attribute.column_type == :unknown)
|
|
105
|
+
)
|
|
106
|
+
@unknown_attributes << "#{attribute.name}:#{attribute.type}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
allow_unknown = options[:allow_unknown].to_s == 'true'
|
|
110
|
+
if !allow_unknown && !@unknown_attributes.empty?
|
|
111
|
+
raise Thor::Error,
|
|
112
|
+
"Unknown field type(s): #{@unknown_attributes.uniq.join(', ')}. " +
|
|
113
|
+
"Add a valid form element type or pass --allow-unknown to keep legacy commented output."
|
|
88
114
|
end
|
|
89
115
|
@flag_create_controller = @flag_create_model
|
|
90
116
|
@flag_create_resource_route = @flag_create_model
|
|
@@ -96,6 +122,7 @@ module InlineForms
|
|
|
96
122
|
@has_many = "\n"
|
|
97
123
|
@has_one = "\n"
|
|
98
124
|
@habtm = "\n"
|
|
125
|
+
@has_rich_text = "\n"
|
|
99
126
|
@has_attached_files = "\n"
|
|
100
127
|
@presentation = "\n"
|
|
101
128
|
@order = "\n"
|
|
@@ -129,6 +156,9 @@ module InlineForms
|
|
|
129
156
|
attribute.type == :check_list
|
|
130
157
|
@habtm << ' has_and_belongs_to_many :' + attribute.name + "\n"
|
|
131
158
|
end
|
|
159
|
+
if attribute.type == :rich_text
|
|
160
|
+
@has_rich_text << ' has_rich_text :' + attribute.name + "\n"
|
|
161
|
+
end
|
|
132
162
|
if attribute.name == '_presentation'
|
|
133
163
|
@presentation << " def _presentation\n" +
|
|
134
164
|
" \"#{attribute.type.to_s}\"\n" +
|
|
@@ -8,6 +8,7 @@ class <%= name %> < ApplicationRecord
|
|
|
8
8
|
<%= @has_many if @has_many.length > 1 -%>
|
|
9
9
|
<%= @has_one if @has_one.length > 1 -%>
|
|
10
10
|
<%= @habtm if @habtm.length > 1 -%>
|
|
11
|
+
<%= @has_rich_text if @has_rich_text.length > 1 -%>
|
|
11
12
|
<%= @has_attached_files if @has_attached_files.length > 1 -%>
|
|
12
13
|
<%= @presentation if @presentation.length > 1 -%>
|
|
13
14
|
<%= @inline_forms_attribute_list -%>
|
data/lib/inline_forms/version.rb
CHANGED
data/lib/installer_templates/example_app_tests/test/models/example_app_paper_trail_changeset_test.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
# Regression: PaperTrail (>= 13) deserializes `versions.object_changes` via
|
|
6
|
+
# `YAML.safe_load`, using `ActiveRecord.yaml_column_permitted_classes` as the
|
|
7
|
+
# allow-list. Rails 7's default is `[Symbol]`, so any update that touches
|
|
8
|
+
# `updated_at` (an `ActiveSupport::TimeWithZone`) raises `Psych::DisallowedClass`
|
|
9
|
+
# inside `version.changeset`, and PaperTrail rescues that into `{}`. The
|
|
10
|
+
# inline_forms versions list then renders every changeset as `empty`.
|
|
11
|
+
#
|
|
12
|
+
# The installer ships `config/initializers/paper_trail_yaml_safe_load.rb`,
|
|
13
|
+
# which extends the allow-list. This test fails if that initializer is
|
|
14
|
+
# missing or insufficient.
|
|
15
|
+
class ExampleAppPaperTrailChangesetTest < ActiveSupport::TestCase
|
|
16
|
+
test "version.changeset round-trips a normal update" do
|
|
17
|
+
PaperTrail.request.whodunnit = "test"
|
|
18
|
+
|
|
19
|
+
apartment = Apartment.create!(name: "Original", title: "Old Title")
|
|
20
|
+
apartment.update!(name: "Renamed", title: "New Title")
|
|
21
|
+
|
|
22
|
+
version = apartment.versions.last
|
|
23
|
+
assert_equal "update", version.event,
|
|
24
|
+
"expected an update version to be recorded by paper_trail"
|
|
25
|
+
|
|
26
|
+
changeset = version.changeset
|
|
27
|
+
assert_kind_of Hash, changeset
|
|
28
|
+
refute_empty changeset,
|
|
29
|
+
"version.changeset is empty; PaperTrail's YAML.safe_load probably hit a " \
|
|
30
|
+
"DisallowedClass and returned {}. Check " \
|
|
31
|
+
"config/initializers/paper_trail_yaml_safe_load.rb and the Rails " \
|
|
32
|
+
"ActiveRecord.yaml_column_permitted_classes setting."
|
|
33
|
+
|
|
34
|
+
assert_equal ["Original", "Renamed"], changeset["name"]
|
|
35
|
+
assert_equal ["Old Title", "New Title"], changeset["title"]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# `has_rich_text :description` lives in the `action_text_rich_texts` table,
|
|
39
|
+
# so `has_paper_trail` on Apartment cannot see body edits. The installer adds
|
|
40
|
+
# `config/initializers/rich_text_paper_trail.rb` (which declares
|
|
41
|
+
# `has_paper_trail` on `ActionText::RichText`), and `inline_forms_versions_for`
|
|
42
|
+
# merges rich-text versions into the parent's history. This test fails if
|
|
43
|
+
# either piece regresses.
|
|
44
|
+
test "rich_text edits surface in the merged versions list for the parent" do
|
|
45
|
+
PaperTrail.request.whodunnit = "test"
|
|
46
|
+
|
|
47
|
+
apartment = Apartment.create!(name: "RT", title: "RT", description: "v1 body")
|
|
48
|
+
apartment.update!(description: "v2 body")
|
|
49
|
+
|
|
50
|
+
rich_text = ActionText::RichText.find_by!(
|
|
51
|
+
record_type: Apartment.name, record_id: apartment.id, name: "description"
|
|
52
|
+
)
|
|
53
|
+
assert rich_text.respond_to?(:versions),
|
|
54
|
+
"ActionText::RichText is missing has_paper_trail; check " \
|
|
55
|
+
"config/initializers/rich_text_paper_trail.rb"
|
|
56
|
+
refute_empty rich_text.versions,
|
|
57
|
+
"no PaperTrail versions on ActionText::RichText; the on_load hook " \
|
|
58
|
+
"in config/initializers/rich_text_paper_trail.rb did not fire or " \
|
|
59
|
+
"has_paper_trail was not applied"
|
|
60
|
+
|
|
61
|
+
helper = Class.new { include InlineFormsHelper }.new
|
|
62
|
+
entries = helper.inline_forms_versions_for(apartment)
|
|
63
|
+
|
|
64
|
+
rich_text_entries = entries.select { |e| e[:kind] == :rich_text }
|
|
65
|
+
refute_empty rich_text_entries,
|
|
66
|
+
"inline_forms_versions_for did not return any rich_text entries"
|
|
67
|
+
|
|
68
|
+
body_changes = rich_text_entries
|
|
69
|
+
.map { |e| e[:version].changeset }
|
|
70
|
+
.select { |cs| cs && cs["body"].is_a?(Array) }
|
|
71
|
+
.map { |cs| cs["body"] }
|
|
72
|
+
|
|
73
|
+
refute_empty body_changes,
|
|
74
|
+
"no body changesets recorded for ActionText::RichText"
|
|
75
|
+
assert body_changes.any? { |old, new_| old.to_s.include?("v1 body") && new_.to_s.include?("v2 body") },
|
|
76
|
+
"expected an entry whose body change moves from 'v1 body' to 'v2 body'; got #{body_changes.inspect}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
require "logger"
|
|
7
|
+
require "rails"
|
|
8
|
+
require "rails/generators"
|
|
9
|
+
require "inline_forms"
|
|
10
|
+
require_relative "../lib/generators/inline_forms_generator"
|
|
11
|
+
|
|
12
|
+
class InlineFormsGeneratorTest < Minitest::Test
|
|
13
|
+
def setup
|
|
14
|
+
@destination_root = Dir.mktmpdir("inline_forms_generator_test")
|
|
15
|
+
build_destination_skeleton!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def teardown
|
|
19
|
+
FileUtils.remove_entry(@destination_root) if @destination_root && Dir.exist?(@destination_root)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_generates_model_controller_route_migration_and_tab_injection
|
|
23
|
+
run_generator(
|
|
24
|
+
"Thing",
|
|
25
|
+
"name:string",
|
|
26
|
+
"category:dropdown",
|
|
27
|
+
"photos:has_many",
|
|
28
|
+
"_enabled:yes",
|
|
29
|
+
"_presentation:\\#{name}"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
model = read("app/models/thing.rb")
|
|
33
|
+
controller = read("app/controllers/things_controller.rb")
|
|
34
|
+
routes = read("config/routes.rb")
|
|
35
|
+
application_controller = read("app/controllers/application_controller.rb")
|
|
36
|
+
migration = read_single_migration_for("things")
|
|
37
|
+
|
|
38
|
+
assert_includes(model, "class Thing < ApplicationRecord")
|
|
39
|
+
assert_includes(model, "belongs_to :category")
|
|
40
|
+
assert_includes(model, "has_many :photos")
|
|
41
|
+
assert_includes(model, "[ :name , \"name\", :text_field ]")
|
|
42
|
+
assert_includes(model, "[ :category , \"category\", :dropdown ]")
|
|
43
|
+
|
|
44
|
+
assert_includes(controller, "class ThingsController < InlineFormsController")
|
|
45
|
+
assert_includes(controller, "set_tab :thing")
|
|
46
|
+
|
|
47
|
+
assert_includes(routes, "resources :things do")
|
|
48
|
+
assert_includes(routes, "post 'revert', :on => :member")
|
|
49
|
+
assert_includes(routes, "get 'list_versions', :on => :member")
|
|
50
|
+
|
|
51
|
+
assert_includes(application_controller, "MODEL_TABS = %w(things ")
|
|
52
|
+
|
|
53
|
+
assert_includes(migration, "class InlineFormsCreateThings < ActiveRecord::Migration[7.0]")
|
|
54
|
+
assert_includes(migration, "create_table :things do |t|")
|
|
55
|
+
assert_includes(migration, "t.string :name")
|
|
56
|
+
assert_includes(migration, "t.belongs_to :category")
|
|
57
|
+
refute_includes(migration, "photos")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_skips_model_controller_and_routes_when_no_model_flag_is_present
|
|
61
|
+
run_generator("AuditLog", "message:string", "_no_model:yes")
|
|
62
|
+
|
|
63
|
+
refute_exist("app/models/audit_log.rb")
|
|
64
|
+
refute_exist("app/controllers/audit_logs_controller.rb")
|
|
65
|
+
|
|
66
|
+
routes = read("config/routes.rb")
|
|
67
|
+
refute_includes(routes, "resources :audit_logs")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_fails_fast_for_unknown_types_by_default
|
|
71
|
+
stdout, stderr = capture_io do
|
|
72
|
+
run_generator("Mystery", "payload:not_a_real_type", "--no-allow-unknown")
|
|
73
|
+
end
|
|
74
|
+
output = "#{stdout}#{stderr}"
|
|
75
|
+
|
|
76
|
+
assert_includes(output, "Unknown field type(s): payload:not_a_real_type")
|
|
77
|
+
assert_includes(output, "--allow-unknown")
|
|
78
|
+
refute_exist("app/models/mystery.rb")
|
|
79
|
+
assert_equal([], Dir.glob(File.join(@destination_root, "db/migrate/*_inline_forms_create_mysteries.rb")))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_allow_unknown_keeps_legacy_commented_output
|
|
83
|
+
run_generator("Mystery", "payload:not_a_real_type", "--allow-unknown")
|
|
84
|
+
|
|
85
|
+
model = read("app/models/mystery.rb")
|
|
86
|
+
migration = read_single_migration_for("mysteries")
|
|
87
|
+
|
|
88
|
+
assert_includes(model, "# [ :payload , \"payload\", :unknown ]")
|
|
89
|
+
assert_includes(migration, "# t.unknown :payload")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_rich_text_adds_has_rich_text_without_migration_column
|
|
93
|
+
run_generator("Article", "title:string", "content:rich_text")
|
|
94
|
+
|
|
95
|
+
model = read("app/models/article.rb")
|
|
96
|
+
migration = read_single_migration_for("articles")
|
|
97
|
+
|
|
98
|
+
assert_includes(model, "has_rich_text :content")
|
|
99
|
+
refute_includes(migration, "t.no_migration :content")
|
|
100
|
+
refute_includes(migration, "t.text :content")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def build_destination_skeleton!
|
|
106
|
+
mkdir_p("config")
|
|
107
|
+
mkdir_p("app/controllers")
|
|
108
|
+
mkdir_p("app/models")
|
|
109
|
+
mkdir_p("db/migrate")
|
|
110
|
+
mkdir_p("test/unit")
|
|
111
|
+
|
|
112
|
+
write(
|
|
113
|
+
"config/routes.rb",
|
|
114
|
+
<<~RUBY
|
|
115
|
+
Rails.application.routes.draw do
|
|
116
|
+
end
|
|
117
|
+
RUBY
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
write(
|
|
121
|
+
"app/controllers/application_controller.rb",
|
|
122
|
+
<<~RUBY
|
|
123
|
+
class ApplicationController < ActionController::Base
|
|
124
|
+
ActionView::CompiledTemplates::MODEL_TABS = %w()
|
|
125
|
+
end
|
|
126
|
+
RUBY
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def run_generator(*args)
|
|
131
|
+
InlineForms::InlineFormsGenerator.start(args, destination_root: @destination_root)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def read(relative_path)
|
|
135
|
+
File.read(File.join(@destination_root, relative_path))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def read_single_migration_for(table_name)
|
|
139
|
+
migration_files = Dir.glob(File.join(@destination_root, "db/migrate/*_inline_forms_create_#{table_name}.rb"))
|
|
140
|
+
assert_equal(1, migration_files.size, "Expected one migration for #{table_name}, got #{migration_files.inspect}")
|
|
141
|
+
File.read(migration_files.first)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def refute_exist(relative_path)
|
|
145
|
+
refute(File.exist?(File.join(@destination_root, relative_path)), "Expected #{relative_path} to not exist")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def mkdir_p(relative_path)
|
|
149
|
+
FileUtils.mkdir_p(File.join(@destination_root, relative_path))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def write(relative_path, content)
|
|
153
|
+
File.write(File.join(@destination_root, relative_path), content)
|
|
154
|
+
end
|
|
155
|
+
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:
|
|
4
|
+
version: 7.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ace Suares
|
|
@@ -59,20 +59,20 @@ dependencies:
|
|
|
59
59
|
requirements:
|
|
60
60
|
- - ">="
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version:
|
|
62
|
+
version: 7.0.0
|
|
63
63
|
- - "<"
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '7'
|
|
65
|
+
version: '7.1'
|
|
66
66
|
type: :runtime
|
|
67
67
|
prerelease: false
|
|
68
68
|
version_requirements: !ruby/object:Gem::Requirement
|
|
69
69
|
requirements:
|
|
70
70
|
- - ">="
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version:
|
|
72
|
+
version: 7.0.0
|
|
73
73
|
- - "<"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '7'
|
|
75
|
+
version: '7.1'
|
|
76
76
|
- !ruby/object:Gem::Dependency
|
|
77
77
|
name: rails-i18n
|
|
78
78
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -163,6 +163,7 @@ files:
|
|
|
163
163
|
- app/helpers/form_elements/plain_text_area.rb
|
|
164
164
|
- app/helpers/form_elements/question_list.rb
|
|
165
165
|
- app/helpers/form_elements/radio_button.rb
|
|
166
|
+
- app/helpers/form_elements/rich_text.rb
|
|
166
167
|
- app/helpers/form_elements/scale_with_integers.rb
|
|
167
168
|
- app/helpers/form_elements/scale_with_values.rb
|
|
168
169
|
- app/helpers/form_elements/simple_file_field.rb
|
|
@@ -222,6 +223,8 @@ files:
|
|
|
222
223
|
- bin/inline_forms
|
|
223
224
|
- bin/inline_forms_app_template.rb
|
|
224
225
|
- bin/inline_forms_installer_core.rb
|
|
226
|
+
- docs/prompt/.gitignore
|
|
227
|
+
- docs/prompt/test-the-example-app.md
|
|
225
228
|
- inline_forms.gemspec
|
|
226
229
|
- lib/generators/USAGE
|
|
227
230
|
- lib/generators/assets/javascripts/ckeditor/config.js
|
|
@@ -246,6 +249,7 @@ files:
|
|
|
246
249
|
- lib/installer_templates/example_app_tests/test/integration/example_app_photos_test.rb
|
|
247
250
|
- lib/installer_templates/example_app_tests/test/integration/example_app_routing_test.rb
|
|
248
251
|
- lib/installer_templates/example_app_tests/test/models/example_app_apartment_photo_test.rb
|
|
252
|
+
- lib/installer_templates/example_app_tests/test/models/example_app_paper_trail_changeset_test.rb
|
|
249
253
|
- lib/locales/inline_forms.en.yml
|
|
250
254
|
- lib/locales/inline_forms.nl.yml
|
|
251
255
|
- lib/otherstuff/20120310065554_inline_forms_create_view_for_translations.rb
|
|
@@ -256,6 +260,7 @@ files:
|
|
|
256
260
|
- lib/vagrant/vagrantbox-inline_forms.zip
|
|
257
261
|
- test/form_element_from_callee_test.rb
|
|
258
262
|
- test/inline_edit_polymorphic_path_test.rb
|
|
263
|
+
- test/inline_forms_generator_test.rb
|
|
259
264
|
- test/test_helper.rb
|
|
260
265
|
homepage: http://github.com/acesuares/inline_forms
|
|
261
266
|
licenses:
|