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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6dbffa35c00698de69d27e5e6c51ac9a8ffbbab983e5a7092d129347c790f3ae
4
- data.tar.gz: 78cec43c0ea51439b4c065a9bb6ef2738ee2b00193e07c4b62808afa8466cd20
3
+ metadata.gz: 46c8d9d11975c43765ea29ed896933ac0dc63b64d1b23ae97d7239e2005c1190
4
+ data.tar.gz: 531398598e0d12f391f3f61a95c445cc2d9bc9ff9b507c1eaead1c48bb871f19
5
5
  SHA512:
6
- metadata.gz: b54ec339cff6f10c8c7dc2aac2392337ca49193e1b6e99516f280d22d95601c0802ce00d47b75746ca2615cef8a420ca0c523778042372b2363926d121f2057b
7
- data.tar.gz: f8478bda112dd62f3baf447cf620a5394b766046cd1324973bfc9fe5db8f75ff4d772d32a5fc21b165d9a8466d954d33daeccf7b17f11fc222eec23f712990f0
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,4 +1,4 @@
1
- <% @BUTTONS_UNDER = [ "text_area", "kansen_slider" ] %>
1
+ <% @BUTTONS_UNDER = [ "text_area", "kansen_slider", "rich_text" ] %>
2
2
  <%= form_tag polymorphic_path(@object,
3
3
  :update => @update_span,
4
4
  :attribute => @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 (#{@object.versions.length})" %>
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
- <% @object.versions.reverse.each do | version | %>
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
- <%= link_to t('inline_forms.view.restore'),
36
- send('revert_' + @object.class.to_s.underscore + "_path",
37
- version,
38
- :update => "#{@object.class.name.underscore}_#{@object.id}"
39
- ),
40
- :remote => true,
41
- :method => :post
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
+ &nbsp;
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"><%= attribute %></th>
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
- <td><%= value[0] %></td>
70
- <td><%= value[1] %></td>
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 Ckeditor.cdn_url %>
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 Ckeditor.cdn_url %>
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-gemfile --skip-test-unit --skip-bootsnap")
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', '~> 6.2'
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', git: 'https://github.com/acesuares/paper_trail.git'
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', '6.1.3.1'
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 6.1.3 expects Minitest 5; 6.x breaks railties test runner (run arity, parallelization).
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[5.0]
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[5.0]
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 ckeditor..."
340
- generate "ckeditor:install --orm=active_record --backend=carrierwave"
341
-
342
- say "- Copy ckeditor/config.js to app/javascripts..."
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
- # --with-mysql embeds InnoDB options in create_table; that SQL is invalid on SQLite (example app).
352
- if ENV['using_sqlite'] == 'true'
353
- generate "paper_trail:install --with-changes"
354
- else
355
- generate "paper_trail:install --with-changes --with-mysql"
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[5.0]
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:ckeditor apartment:belongs_to _presentation:\'#{name}\''
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:ckeditor photos:has_many photos:associated _enabled:yes _presentation:\'#{name}\''
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,5 @@
1
+ # Keep this directory for checked-in prompt docs.
2
+ # Ignore local scratch files by default.
3
+ *
4
+ !.gitignore
5
+ !*.md
@@ -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', '>= 6.1.3.1', '< 7')
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" +
@@ -1,4 +1,4 @@
1
- class InlineFormsCreate<%= table_name.camelize %> < ActiveRecord::Migration[6.1]
1
+ class InlineFormsCreate<%= table_name.camelize %> < ActiveRecord::Migration[7.0]
2
2
 
3
3
  def self.up
4
4
  create_table :<%= table_name + @primary_key_option %> do |t|
@@ -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 -%>
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module InlineForms
3
- VERSION = "6.3.3"
3
+ VERSION = "7.0.4"
4
4
  end
@@ -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: 6.3.3
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: 6.1.3.1
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: 6.1.3.1
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: