├── .editorconfig
├── .gitattributes
├── .gitignore
├── .rubocop.yml
├── .ruby-version
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app
└── models
│ └── form_core
│ ├── application_record.rb
│ ├── field.rb
│ └── form.rb
├── bin
└── rails
├── db
└── migrate
│ ├── 20170430190404_create_forms.rb
│ └── 20170430191336_create_fields.rb
├── form_core.gemspec
├── lib
├── form_core.rb
├── form_core
│ ├── coder.rb
│ ├── coders
│ │ ├── hash_coder.rb
│ │ └── yaml_coder.rb
│ ├── concerns
│ │ └── models
│ │ │ ├── field.rb
│ │ │ └── form.rb
│ ├── engine.rb
│ ├── errors.rb
│ ├── version.rb
│ └── virtual_model.rb
└── tasks
│ └── form_core_tasks.rake
└── test
├── dummy
├── Rakefile
├── app
│ ├── assets
│ │ ├── config
│ │ │ └── manifest.js
│ │ ├── images
│ │ │ └── .keep
│ │ ├── javascripts
│ │ │ ├── application.es6
│ │ │ └── direct_uploads.es6
│ │ └── stylesheets
│ │ │ ├── application.scss
│ │ │ └── direct_uploads.css
│ ├── channels
│ │ └── application_cable
│ │ │ ├── channel.rb
│ │ │ └── connection.rb
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ ├── dictionaries_controller.rb
│ │ ├── fields
│ │ │ ├── application_controller.rb
│ │ │ ├── choices_controller.rb
│ │ │ ├── data_source_options_controller.rb
│ │ │ ├── options_controller.rb
│ │ │ └── validations_controller.rb
│ │ ├── forms
│ │ │ ├── application_controller.rb
│ │ │ ├── fields_controller.rb
│ │ │ ├── loads_controller.rb
│ │ │ ├── previews_controller.rb
│ │ │ └── sections_controller.rb
│ │ ├── forms_controller.rb
│ │ ├── nested_forms
│ │ │ ├── application_controller.rb
│ │ │ └── fields_controller.rb
│ │ └── time_zones_controller.rb
│ ├── helpers
│ │ ├── application_helper.rb
│ │ ├── fields_helper.rb
│ │ └── forms_helper.rb
│ ├── jobs
│ │ └── application_job.rb
│ ├── lib
│ │ └── .keep
│ ├── models
│ │ ├── application_record.rb
│ │ ├── choice.rb
│ │ ├── concerns
│ │ │ ├── .keep
│ │ │ ├── acts_as_default_value.rb
│ │ │ ├── enum_attribute_localizable.rb
│ │ │ ├── fields
│ │ │ │ ├── fake.rb
│ │ │ │ ├── helper.rb
│ │ │ │ ├── options
│ │ │ │ │ └── data_source.rb
│ │ │ │ └── validations
│ │ │ │ │ ├── acceptance.rb
│ │ │ │ │ ├── confirmation.rb
│ │ │ │ │ ├── exclusion.rb
│ │ │ │ │ ├── format.rb
│ │ │ │ │ ├── inclusion.rb
│ │ │ │ │ ├── length.rb
│ │ │ │ │ ├── numericality.rb
│ │ │ │ │ └── presence.rb
│ │ │ ├── form_core
│ │ │ │ ├── active_storage_bridge
│ │ │ │ │ └── attached
│ │ │ │ │ │ └── macros.rb
│ │ │ │ └── acts_as_default_value.rb
│ │ │ └── forms
│ │ │ │ └── fake.rb
│ │ ├── data_source.rb
│ │ ├── data_sources.rb
│ │ ├── data_sources
│ │ │ ├── dictionary.rb
│ │ │ └── empty.rb
│ │ ├── dictionary.rb
│ │ ├── field.rb
│ │ ├── field_options.rb
│ │ ├── fields.rb
│ │ ├── fields
│ │ │ ├── attachment_field.rb
│ │ │ ├── boolean_field.rb
│ │ │ ├── choice_field.rb
│ │ │ ├── date_field.rb
│ │ │ ├── date_range_field.rb
│ │ │ ├── datetime_field.rb
│ │ │ ├── datetime_range_field.rb
│ │ │ ├── decimal_field.rb
│ │ │ ├── decimal_range_field.rb
│ │ │ ├── embeds
│ │ │ │ ├── date_range.rb
│ │ │ │ ├── datetime_range.rb
│ │ │ │ ├── decimal_range.rb
│ │ │ │ └── integer_range.rb
│ │ │ ├── integer_field.rb
│ │ │ ├── integer_range_field.rb
│ │ │ ├── multiple_attachment_field.rb
│ │ │ ├── multiple_choice_field.rb
│ │ │ ├── multiple_nested_form_field.rb
│ │ │ ├── multiple_resource_field.rb
│ │ │ ├── multiple_resource_select_field.rb
│ │ │ ├── multiple_select_field.rb
│ │ │ ├── nested_form_field.rb
│ │ │ ├── options
│ │ │ │ ├── date_field.rb
│ │ │ │ ├── date_range_field.rb
│ │ │ │ ├── datetime_field.rb
│ │ │ │ ├── datetime_range_field.rb
│ │ │ │ ├── decimal_field.rb
│ │ │ │ ├── decimal_range_field.rb
│ │ │ │ ├── integer_field.rb
│ │ │ │ ├── integer_range_field.rb
│ │ │ │ ├── multiple_resource_field.rb
│ │ │ │ ├── multiple_resource_select_field.rb
│ │ │ │ ├── multiple_select_field.rb
│ │ │ │ ├── resource_field.rb
│ │ │ │ ├── resource_select_field.rb
│ │ │ │ ├── select_field.rb
│ │ │ │ └── text_field.rb
│ │ │ ├── resource_field.rb
│ │ │ ├── resource_select_field.rb
│ │ │ ├── select_field.rb
│ │ │ ├── text_field.rb
│ │ │ └── validations
│ │ │ │ ├── attachment_field.rb
│ │ │ │ ├── boolean_field.rb
│ │ │ │ ├── choice_field.rb
│ │ │ │ ├── date_field.rb
│ │ │ │ ├── date_range_field.rb
│ │ │ │ ├── datetime_field.rb
│ │ │ │ ├── datetime_range_field.rb
│ │ │ │ ├── decimal_field.rb
│ │ │ │ ├── decimal_range_field.rb
│ │ │ │ ├── integer_field.rb
│ │ │ │ ├── integer_range_field.rb
│ │ │ │ ├── multiple_attachment_field.rb
│ │ │ │ ├── multiple_choice_field.rb
│ │ │ │ ├── multiple_nested_form_field.rb
│ │ │ │ ├── multiple_resource_field.rb
│ │ │ │ ├── multiple_resource_select_field.rb
│ │ │ │ ├── multiple_select_field.rb
│ │ │ │ ├── nested_form_field.rb
│ │ │ │ ├── resource_field.rb
│ │ │ │ ├── resource_select_field.rb
│ │ │ │ ├── select_field.rb
│ │ │ │ └── text_field.rb
│ │ ├── form.rb
│ │ ├── metal_form.rb
│ │ ├── nested_form.rb
│ │ ├── non_configurable.rb
│ │ ├── section.rb
│ │ └── virtual_model.rb
│ ├── overrides
│ │ └── action_view
│ │ │ └── helpers
│ │ │ └── tags
│ │ │ ├── date_field_override.rb
│ │ │ └── datetime_local_field_override.rb
│ ├── presenters
│ │ ├── application_presenter.rb
│ │ ├── concerns
│ │ │ └── fields
│ │ │ │ └── presenter_for_number_field.rb
│ │ └── fields
│ │ │ ├── attachment_field_presenter.rb
│ │ │ ├── boolean_field_presenter.rb
│ │ │ ├── choice_field_presenter.rb
│ │ │ ├── composite_field_presenter.rb
│ │ │ ├── date_field_presenter.rb
│ │ │ ├── date_range_field_presenter.rb
│ │ │ ├── datetime_field_presenter.rb
│ │ │ ├── datetime_range_field_presenter.rb
│ │ │ ├── decimal_field_presenter.rb
│ │ │ ├── decimal_range_field_presenter.rb
│ │ │ ├── field_presenter.rb
│ │ │ ├── integer_field_presenter.rb
│ │ │ ├── integer_range_field_presenter.rb
│ │ │ ├── multiple_attachment_field_presenter.rb
│ │ │ ├── multiple_choice_field_presenter.rb
│ │ │ ├── multiple_nested_form_field_presenter.rb
│ │ │ ├── multiple_resource_field_presenter.rb
│ │ │ ├── multiple_resource_select_field_presenter.rb
│ │ │ ├── multiple_select_field_presenter.rb
│ │ │ ├── nested_form_field_presenter.rb
│ │ │ ├── resource_field_presenter.rb
│ │ │ ├── resource_select_field_presenter.rb
│ │ │ ├── select_field_presenter.rb
│ │ │ └── text_field_presenter.rb
│ └── views
│ │ ├── _form_core
│ │ ├── data_source_options
│ │ │ ├── _dictionary.html.erb
│ │ │ └── _empty.html.erb
│ │ ├── field_options
│ │ │ ├── _date_field.html.erb
│ │ │ ├── _date_range_field.html.erb
│ │ │ ├── _datetime_field.html.erb
│ │ │ ├── _datetime_range_field.html.erb
│ │ │ ├── _decimal_field.html.erb
│ │ │ ├── _decimal_range_field.html.erb
│ │ │ ├── _integer_field.html.erb
│ │ │ ├── _integer_range_field.html.erb
│ │ │ ├── _multiple_resource_field.html.erb
│ │ │ ├── _multiple_resource_select_field.html.erb
│ │ │ ├── _multiple_select_field.html.erb
│ │ │ ├── _resource_field.html.erb
│ │ │ ├── _resource_select_field.html.erb
│ │ │ ├── _select_field.html.erb
│ │ │ └── _text_field.html.erb
│ │ ├── fields
│ │ │ ├── _attachment_field.html.erb
│ │ │ ├── _boolean_field.html.erb
│ │ │ ├── _choice_field.html.erb
│ │ │ ├── _date_field.html.erb
│ │ │ ├── _date_range_field.html.erb
│ │ │ ├── _datetime_field.html.erb
│ │ │ ├── _datetime_range_field.html.erb
│ │ │ ├── _decimal_field.html.erb
│ │ │ ├── _decimal_range_field.html.erb
│ │ │ ├── _integer_field.html.erb
│ │ │ ├── _integer_range_field.html.erb
│ │ │ ├── _multiple_attachment_field.html.erb
│ │ │ ├── _multiple_choice_field.html.erb
│ │ │ ├── _multiple_nested_form_field.html.erb
│ │ │ ├── _multiple_resource_field.html.erb
│ │ │ ├── _multiple_resource_select_field.html.erb
│ │ │ ├── _multiple_select_field.html.erb
│ │ │ ├── _nested_form.html.erb
│ │ │ ├── _nested_form_field.html.erb
│ │ │ ├── _resource_field.html.erb
│ │ │ ├── _resource_select_field.html.erb
│ │ │ ├── _select_field.html.erb
│ │ │ └── _text_field.html.erb
│ │ ├── preview
│ │ │ ├── _form.html.erb
│ │ │ └── _nested_form.html.erb
│ │ ├── render
│ │ │ └── _form.html.erb
│ │ └── validations
│ │ │ ├── _acceptance.html.erb
│ │ │ ├── _confirmation.html.erb
│ │ │ ├── _exclusion.html.erb
│ │ │ ├── _format.html.erb
│ │ │ ├── _inclusion.html.erb
│ │ │ ├── _length.html.erb
│ │ │ ├── _numericality.html.erb
│ │ │ └── _presence.html.erb
│ │ ├── dictionaries
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ └── new.html.erb
│ │ ├── fields
│ │ ├── choices
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ └── new.html.erb
│ │ ├── data_source_options
│ │ │ ├── _form.html.erb
│ │ │ └── edit.html.erb
│ │ ├── options
│ │ │ ├── _form.html.erb
│ │ │ └── edit.html.erb
│ │ └── validations
│ │ │ ├── _form.html.erb
│ │ │ └── edit.html.erb
│ │ ├── forms
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── fields
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ └── new.html.erb
│ │ ├── index.html.erb
│ │ ├── loads
│ │ │ ├── create.html.erb
│ │ │ └── show.html.erb
│ │ ├── new.html.erb
│ │ ├── previews
│ │ │ ├── create.html.erb
│ │ │ └── show.html.erb
│ │ └── sections
│ │ │ ├── _form.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── index.html.erb
│ │ │ └── new.html.erb
│ │ ├── layouts
│ │ ├── _alert.html.erb
│ │ ├── _footer.html.erb
│ │ ├── _nav.html.erb
│ │ ├── _notice.html.erb
│ │ ├── application.html.erb
│ │ └── forms.html.erb
│ │ └── nested_forms
│ │ └── fields
│ │ ├── _form.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ └── new.html.erb
├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── update
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── actionview.rb
│ │ ├── application_controller_renderer.rb
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── content_security_policy.rb
│ │ ├── cookies_serializer.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── form_core.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── validates_timeliness.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ ├── en.yml
│ │ ├── form_core.en.yml
│ │ └── validates_timeliness.en.yml
│ ├── puma.rb
│ ├── routes.rb
│ ├── secrets.yml
│ ├── spring.rb
│ └── storage.yml
├── db
│ ├── migrate
│ │ ├── 20170504211819_add_columns_to_forms.rb
│ │ ├── 20170504214301_create_sections.rb
│ │ ├── 20170504225506_add_columns_to_fields.rb
│ │ ├── 20170515212355_create_dictionaries.rb
│ │ ├── 20170613184106_add_attachable_to_forms.rb
│ │ ├── 20180120200440_add_position_to_fields.rb
│ │ ├── 20180120201200_add_position_to_sections.rb
│ │ ├── 20180220232604_create_choices.rb
│ │ ├── 20180228201120_add_position_to_choices.rb
│ │ └── 20210108214331_create_active_storage_tables.active_storage.rb
│ └── schema.rb
├── lib
│ ├── assets
│ │ └── .keep
│ └── monkey_patches
│ │ ├── active_support.rb
│ │ └── active_support
│ │ └── concern+prependable.rb
├── log
│ └── .keep
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── apple-touch-icon-precomposed.png
│ ├── apple-touch-icon.png
│ └── favicon.ico
├── storage
│ └── .keep
└── test
│ ├── application_system_test_case.rb
│ ├── controllers
│ └── .keep
│ ├── fixtures
│ └── .keep
│ ├── models
│ └── .keep
│ └── system
│ └── .keep
├── fixtures
└── form_core
│ ├── fields.yml
│ └── forms.yml
├── form_core_test.rb
├── integration
└── navigation_test.rb
├── models
└── form_core
│ ├── field_test.rb
│ └── form_test.rb
└── test_helper.rb
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 | indent_style = space
11 | indent_size = 2
12 | end_of_line = lf
13 |
14 | [*.md]
15 | trim_trailing_whitespace = true
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.rb diff=ruby
2 | *.gemspec diff=ruby
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | .bundle/
9 |
10 | # Ignore the default SQLite database.
11 | test/dummy/db/*.sqlite3
12 | test/dummy/db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | log/*.log
16 | !test/dummy/log/.keep
17 | !test/dummy/tmp/.keep
18 | test/dummy/log/*.log
19 | test/dummy/tmp/
20 |
21 | # Ignore uploaded files in development
22 | !test/dummy/storage/.keep
23 | test/dummy/storage/*
24 |
25 | pkg/
26 | .byebug_history
27 |
28 | node_modules/
29 | test/dummy/public/packs
30 | test/dummy/node_modules/
31 | yarn-error.log
32 |
33 | *.gem
34 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-3.0.3
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5 |
6 | # Declare your gem"s dependencies in form_core.gemspec.
7 | # Bundler will treat runtime dependencies like base dependencies, and
8 | # development dependencies will be added by default to the :development group.
9 | gemspec
10 |
11 | gem "activeentity", path: "../activeentity"
12 |
13 | # Declare any dependencies that are still in development here instead of in
14 | # your gemspec. These might include edge Rails or gems from your path or
15 | # Git. Remember to move these dependencies to your gemspec before releasing
16 | # your gem to rubygems.org.
17 |
18 | gem "rails", "~> 7.0.0"
19 | gem "sqlite3"
20 |
21 | # To support ES6
22 | gem "sprockets", "~> 4.0"
23 | # Support ES6
24 | gem "babel-transpiler"
25 | # Use CoffeeScript for .coffee assets and views
26 | # gem "coffee-rails", "~> 4.2"
27 | # Use SCSS for stylesheets
28 | gem "sassc-rails"
29 | # Use Uglifier as compressor for JavaScript assets
30 | gem "uglifier", ">= 1.3.0"
31 |
32 | gem "bulma-rails"
33 | gem "jquery-rails"
34 | gem "selectize-rails"
35 | gem "turbolinks"
36 |
37 | # Use Puma as the app server
38 | gem "puma"
39 |
40 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
41 | gem "listen", ">= 3.2"
42 | gem "web-console", group: :development
43 | # Call "byebug" anywhere in the code to stop execution and get a debugger console
44 | gem "byebug", platforms: %i[mri mingw x64_mingw]
45 |
46 | gem "timeliness-i18n"
47 | gem "validates_timeliness", "~> 5.0.0.alpha1"
48 |
49 | gem "acts_as_list"
50 | gem "cocoon"
51 |
52 | gem "rubocop"
53 | gem "rubocop-performance"
54 | gem "rubocop-rails"
55 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Jun Jiang
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Form Core
2 | ====
3 |
4 | A Rails engine providing ability to generate dynamic form.
5 |
6 | ## Requirements
7 |
8 | ### 0.1 branch
9 |
10 | - MRI 2.5+
11 | - Rails 6.0+
12 |
13 | ### 0.0.1 branch
14 |
15 | - MRI 2.3+
16 | - Rails 5.0+
17 |
18 | ## Usage
19 |
20 | See demo for now.
21 |
22 | ## Installation
23 |
24 | Add this line to your Gemfile:
25 |
26 | ```ruby
27 | gem 'form_core'
28 | ```
29 |
30 | Or you may want to include the gem directly from GitHub:
31 |
32 | ```ruby
33 | gem 'form_core', github: 'rails-engine/form_core'
34 | ```
35 |
36 | And then execute:
37 |
38 | ```sh
39 | $ bundle
40 | ```
41 |
42 | Copy migrations
43 |
44 | ```sh
45 | $ bin/rails form_core:install:migrations
46 | ```
47 |
48 | Then do migrate
49 |
50 | ```sh
51 | $ bin/rails db:migrate
52 | ```
53 |
54 | ## Demo
55 |
56 | Clone the repository.
57 |
58 | ```sh
59 | $ git clone https://github.com/rails-engine/form_core.git
60 | ```
61 |
62 | Change directory
63 |
64 | ```sh
65 | $ cd form_core
66 | ```
67 |
68 | Run bundler
69 |
70 | ```sh
71 | $ bundle install
72 | ```
73 |
74 | Preparing database
75 |
76 | ```sh
77 | $ bin/rails db:migrate
78 | ```
79 |
80 | Start the Rails server
81 |
82 | ```sh
83 | $ bin/rails s
84 | ```
85 |
86 | Open your browser, and visit `http://localhost:3000`
87 |
88 | ## Contributing
89 |
90 | Bug report or pull request are welcome.
91 |
92 | ### Make a pull request
93 |
94 | 1. Fork it
95 | 2. Create your feature branch (`git checkout -b my-new-feature`)
96 | 3. Commit your changes (`git commit -am 'Add some feature'`)
97 | 4. Push to the branch (`git push origin my-new-feature`)
98 | 5. Create new Pull Request
99 |
100 | Please write unit test with your code if necessary.
101 |
102 | ## License
103 |
104 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
105 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | begin
4 | require "bundler/setup"
5 | rescue LoadError
6 | puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7 | end
8 |
9 | require "rdoc/task"
10 |
11 | RDoc::Task.new(:rdoc) do |rdoc|
12 | rdoc.rdoc_dir = "rdoc"
13 | rdoc.title = "FormCore"
14 | rdoc.options << "--line-numbers"
15 | rdoc.rdoc_files.include("README.md")
16 | rdoc.rdoc_files.include("lib/**/*.rb")
17 | end
18 |
19 | APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
20 | load "rails/tasks/engine.rake"
21 |
22 | load "rails/tasks/statistics.rake"
23 |
24 | require "bundler/gem_tasks"
25 |
26 | require "rake/testtask"
27 |
28 | Rake::TestTask.new(:test) do |t|
29 | t.libs << "test"
30 | t.pattern = "test/**/*_test.rb"
31 | t.verbose = false
32 | end
33 |
34 | task default: :test
35 |
--------------------------------------------------------------------------------
/app/models/form_core/application_record.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | class ApplicationRecord < ActiveRecord::Base
5 | self.abstract_class = true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/form_core/field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | class Field < ApplicationRecord
5 | include FormCore::Concerns::Models::Field
6 |
7 | self.table_name = "fields"
8 |
9 | belongs_to :form, touch: true
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/models/form_core/form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | class Form < ApplicationRecord
5 | include FormCore::Concerns::Models::Form
6 |
7 | self.table_name = "forms"
8 |
9 | has_many :fields, dependent: :destroy
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | # This command will automatically be run when you run "rails" with Rails gems
5 | # installed from the root of your application.
6 |
7 | ENGINE_ROOT = File.expand_path("../..", __FILE__)
8 | ENGINE_PATH = File.expand_path("../../lib/form_core/engine", __FILE__)
9 | APP_PATH = File.expand_path("../../test/dummy/config/application", __FILE__)
10 |
11 | # Set up gems listed in the Gemfile.
12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
13 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
14 |
15 | require "rails/all"
16 | require "rails/engine/commands"
17 |
--------------------------------------------------------------------------------
/db/migrate/20170430190404_create_forms.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateForms < ActiveRecord::Migration[5.1]
4 | def change
5 | create_table :forms do |t|
6 | t.string :type, null: false, index: true
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20170430191336_create_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateFields < ActiveRecord::Migration[5.1]
4 | def change
5 | create_table :fields do |t|
6 | t.string :name, null: false
7 | t.integer :accessibility, null: false
8 | t.text :validations
9 | t.text :options
10 | t.string :type, null: false, index: true
11 | t.references :form, foreign_key: true
12 |
13 | t.timestamps
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/form_core.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | $LOAD_PATH.push File.expand_path("lib", __dir__)
4 |
5 | # Maintain your gem's version:
6 | require "form_core/version"
7 |
8 | # Describe your gem and declare its dependencies:
9 | Gem::Specification.new do |s|
10 | s.name = "form_core"
11 | s.version = FormCore::VERSION
12 | s.authors = ["jasl"]
13 | s.email = ["jasl9187@hotmail.com"]
14 | s.homepage = "https://github.com/rails-engine/form_core"
15 | s.summary = "A Rails engine providing ability to generate dynamic form."
16 | s.description = <<-TEXT.lstrip
17 | A Rails engine providing ability to generate dynamic form.
18 | It's would make such as dynamic fields of model or questionnaire easily.
19 | TEXT
20 | s.license = "MIT"
21 |
22 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
23 |
24 | #s.add_dependency "activeentity", ">= 6.1.0"
25 | s.add_dependency "rails", ">= 6.1", "< 8"
26 | end
27 |
--------------------------------------------------------------------------------
/lib/form_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "form_core/engine"
4 | require "form_core/errors"
5 |
6 | require "form_core/coder"
7 | require "form_core/coders/hash_coder"
8 | require "form_core/coders/yaml_coder"
9 |
10 | require "form_core/virtual_model"
11 | require "form_core/concerns/models/form"
12 | require "form_core/concerns/models/field"
13 |
14 | module FormCore
15 | class << self
16 | def virtual_model_class
17 | @virtual_model_class ||= VirtualModel
18 | end
19 |
20 | def virtual_model_class=(klass)
21 | raise ArgumentError, "#{klass} should be sub-class of #{VirtualModel}." unless klass && klass < VirtualModel
22 |
23 | @reserved_names = nil
24 | @virtual_model_class = klass
25 | end
26 |
27 | def reserved_names
28 | @reserved_names ||= Set.new(
29 | %i[def class module private public protected allocate new parent superclass] +
30 | virtual_model_class.instance_methods(true)
31 | )
32 | end
33 |
34 | def virtual_model_coder_class
35 | @virtual_model_coder_class ||= HashCoder
36 | end
37 |
38 | def virtual_model_coder_class=(klass)
39 | raise ArgumentError, "#{klass} should be sub-class of #{Coder}." unless klass && klass < Coder
40 |
41 | @virtual_model_coder_class = klass
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/form_core/coder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | class Coder
5 | cattr_accessor :strict
6 |
7 | attr_reader :object_class
8 |
9 | def initialize(object_class)
10 | @object_class = object_class
11 | end
12 |
13 | def strict?
14 | Coder.strict
15 | end
16 |
17 | def dump(_obj)
18 | raise NotImplementedError
19 | end
20 |
21 | def load(_src)
22 | raise NotImplementedError
23 | end
24 |
25 | private
26 |
27 | def new_or_raise_decoding_error
28 | if strict?
29 | raise DecodingDataCorrupted
30 | else
31 | object_class.new
32 | end
33 | end
34 |
35 | def valid_attribute_names
36 | object_class.attribute_names + object_class._embeds_reflections.keys
37 | end
38 |
39 | def valid_attributes(hash)
40 | hash.slice(*valid_attribute_names)
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/lib/form_core/coders/hash_coder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "yaml"
4 |
5 | module FormCore
6 | class HashCoder < FormCore::Coder # :nodoc:
7 | def dump(obj)
8 | obj&.serializable_hash || {}
9 | end
10 |
11 | def load(hash)
12 | return new_or_raise_decoding_error if hash.nil? || !hash.respond_to?(:to_h)
13 |
14 | object_class.new valid_attributes(hash)
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/form_core/coders/yaml_coder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "yaml"
4 |
5 | module FormCore
6 | class YAMLCoder < FormCore::Coder # :nodoc:
7 | cattr_accessor :safe_mode
8 |
9 | def self.whitelist_classes
10 | @whitelist_classes ||= []
11 | end
12 |
13 | def safe_mode?
14 | YAMLCoder.safe_mode
15 | end
16 |
17 | def dump(obj)
18 | return YAML.dump({}) unless obj
19 |
20 | YAML.dump obj.serializable_hash
21 | end
22 |
23 | def load(yaml)
24 | return object_class.new if yaml.blank?
25 |
26 | return new_or_raise_decoding_error unless yaml.is_a?(String) && /^---/.match?(yaml)
27 |
28 | decoded =
29 | if safe_mode?
30 | YAML.safe_load(yaml, YAMLCoder.whitelist_classes)
31 | else
32 | YAML.safe_load(yaml)
33 | end
34 | return new_or_raise_decoding_error unless decoded.is_a? Hash
35 |
36 | object_class.new valid_attributes(decoded)
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/form_core/concerns/models/form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore::Concerns
4 | module Models
5 | module Form
6 | extend ActiveSupport::Concern
7 |
8 | def to_virtual_model(model_name: "Form",
9 | fields_scope: proc { |fields| fields },
10 | overrides: {})
11 | model = FormCore.virtual_model_class.build model_name
12 |
13 | append_to_virtual_model(model, fields_scope: fields_scope, overrides: overrides)
14 | end
15 |
16 | def append_to_virtual_model(model,
17 | fields_scope: proc { |fields| fields },
18 | overrides: {})
19 | check_model_validity! model
20 |
21 | global_overrides = overrides.fetch(:_global, {})
22 | fields_scope.call(fields).each do |f|
23 | f.interpret_to model, overrides: global_overrides.merge(overrides.fetch(f.name, {}))
24 | end
25 |
26 | model
27 | end
28 |
29 | private
30 |
31 | def check_model_validity!(model)
32 | unless model.is_a?(Class) && model < ::FormCore::VirtualModel
33 | raise ArgumentError, "#{model} must be a #{::FormCore::VirtualModel}'s subclass"
34 | end
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/lib/form_core/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | class Engine < ::Rails::Engine
5 | isolate_namespace FormCore
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/form_core/errors.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | # = Form Core Errors
5 | #
6 | # Generic Form Core exception class.
7 | class FormCoreError < StandardError
8 | end
9 |
10 | class DecodingDataCorrupted < FormCoreError
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/form_core/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormCore
4 | VERSION = "0.1.5"
5 | end
6 |
--------------------------------------------------------------------------------
/lib/tasks/form_core_tasks.rake:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # desc "Explaining what the task does"
3 | # task :form_core do
4 | # # Task goes here
5 | # end
6 |
--------------------------------------------------------------------------------
/test/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Add your own tasks in files placed in lib/tasks ending in .rake,
4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
5 |
6 | require_relative "config/application"
7 |
8 | Rails.application.load_tasks
9 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../javascripts .js
3 | //= link_directory ../stylesheets .css
4 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/app/assets/images/.keep
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/application.es6:
--------------------------------------------------------------------------------
1 | //= require rails-ujs
2 | //= require turbolinks
3 | //= require jquery3
4 |
5 | //= require selectize
6 | //= require cocoon
7 | //= require activestorage
8 | //= require direct_uploads
9 |
10 | // Cheat form https://github.com/jgthms/bulma/blob/master/docs/_javascript/main.js
11 | document.addEventListener('DOMContentLoaded', () => {
12 |
13 | // Dropdowns
14 |
15 | const $dropdowns = getAll('.dropdown:not(.is-hoverable)');
16 |
17 | if ($dropdowns.length > 0) {
18 | $dropdowns.forEach($el => {
19 | $el.addEventListener('click', event => {
20 | event.stopPropagation();
21 | $el.classList.toggle('is-active');
22 | });
23 | });
24 |
25 | document.addEventListener('click', event => {
26 | closeDropdowns();
27 | });
28 | }
29 |
30 | function closeDropdowns() {
31 | $dropdowns.forEach($el => {
32 | $el.classList.remove('is-active');
33 | });
34 | }
35 |
36 | // Functions
37 |
38 | function getAll(selector) {
39 | return Array.prototype.slice.call(document.querySelectorAll(selector), 0);
40 | }
41 |
42 | // Utils
43 |
44 | function removeFromArray(array, value) {
45 | if (array.includes(value)) {
46 | const value_index = array.indexOf(value);
47 | array.splice(value_index, 1);
48 | }
49 |
50 | return array;
51 | }
52 |
53 | Array.prototype.diff = function (a) {
54 | return this.filter(function (i) {
55 | return a.indexOf(i) < 0;
56 | });
57 | };
58 | });
59 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/javascripts/direct_uploads.es6:
--------------------------------------------------------------------------------
1 | addEventListener("direct-upload:initialize", event => {
2 | const { target, detail } = event
3 | const { id, file } = detail
4 | target.insertAdjacentHTML("beforebegin", `
5 |
9 | `)
10 | })
11 |
12 | addEventListener("direct-upload:start", event => {
13 | const { id } = event.detail
14 | const element = document.getElementById(`direct-upload-${id}`)
15 | element.classList.remove("direct-upload--pending")
16 | })
17 |
18 | addEventListener("direct-upload:progress", event => {
19 | const { id, progress } = event.detail
20 | const progressElement = document.getElementById(`direct-upload-progress-${id}`)
21 | progressElement.style.width = `${progress}%`
22 | })
23 |
24 | addEventListener("direct-upload:error", event => {
25 | event.preventDefault()
26 | const { id, error } = event.detail
27 | const element = document.getElementById(`direct-upload-${id}`)
28 | element.classList.add("direct-upload--error")
29 | element.setAttribute("title", error)
30 | })
31 |
32 | addEventListener("direct-upload:end", event => {
33 | const { id } = event.detail
34 | const element = document.getElementById(`direct-upload-${id}`)
35 | element.classList.add("direct-upload--complete")
36 | })
37 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/application.scss:
--------------------------------------------------------------------------------
1 | @import "selectize";
2 | @import "bulma";
3 | @import "direct_uploads";
4 |
5 | body {
6 | display: flex;
7 | min-height: 100vh;
8 | flex-direction: column;
9 |
10 | & nav.nav {
11 | a.brand {
12 | padding: 0.5rem 0.75em 0.5em 0;
13 | }
14 | }
15 |
16 | & .main {
17 | flex: 1;
18 | }
19 |
20 | & footer.footer {
21 | padding: 3rem 1.5rem 3rem;
22 | }
23 | }
24 |
25 | .section-header {
26 | background-color:#fafafa;
27 | }
28 |
29 | .flash {
30 | overflow: hidden;
31 | top: 0;
32 | left: 0;
33 | right: 0;
34 | line-height: 2.5;
35 | background: $info;
36 | color: $text-invert;
37 | text-align: center;
38 | }
39 |
40 | #alert {
41 | background: $danger;
42 | }
43 |
44 | .nested_form_field {
45 | .collection {
46 | .nested_form {
47 | border: 1px solid $green;
48 | padding: 0.5em;
49 | margin-left: 0.75em;
50 | margin-bottom: 0.75rem;
51 | }
52 | }
53 | }
54 |
55 | .content {
56 | .nested-content {
57 | margin-left: 0.75em;
58 | margin-bottom: 1em;
59 | }
60 | }
61 |
62 | .message-body.content {
63 | > :first-child {
64 | margin-top: 0;
65 | }
66 | }
67 |
68 | .field {
69 | flex: 1;
70 | }
71 |
--------------------------------------------------------------------------------
/test/dummy/app/assets/stylesheets/direct_uploads.css:
--------------------------------------------------------------------------------
1 | .direct-upload {
2 | display: inline-block;
3 | position: relative;
4 | padding: 2px 4px;
5 | margin: 0 3px 3px 0;
6 | border: 1px solid rgba(0, 0, 0, 0.3);
7 | border-radius: 3px;
8 | font-size: 11px;
9 | line-height: 13px;
10 | }
11 |
12 | .direct-upload--pending {
13 | opacity: 0.6;
14 | }
15 |
16 | .direct-upload__progress {
17 | position: absolute;
18 | top: 0;
19 | left: 0;
20 | bottom: 0;
21 | opacity: 0.2;
22 | background: #0076ff;
23 | transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
24 | transform: translate3d(0, 0, 0);
25 | }
26 |
27 | .direct-upload--complete .direct-upload__progress {
28 | opacity: 0.4;
29 | }
30 |
31 | .direct-upload--error {
32 | border-color: red;
33 | }
34 |
35 | input[type=file][data-direct-upload-url][disabled] {
36 | display: none;
37 | }
38 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ApplicationCable
4 | class Channel < ActionCable::Channel::Base
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/test/dummy/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ApplicationCable
4 | class Connection < ActionCable::Connection::Base
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationController < ActionController::Base
4 | around_action :set_time_zone
5 |
6 | helper_method :current_time_zone
7 |
8 | private
9 |
10 | def set_time_zone(&block)
11 | Time.use_zone(current_time_zone, &block)
12 | end
13 |
14 | def current_time_zone
15 | @_current_time_zone ||=
16 | if session[:current_time_zone].present?
17 | ActiveSupport::TimeZone[session[:current_time_zone]] || ActiveSupport::TimeZone["UTC"]
18 | else
19 | ActiveSupport::TimeZone["UTC"]
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/controllers/dictionaries_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DictionariesController < ApplicationController
4 | before_action :set_dictionary, only: %i[edit update destroy]
5 |
6 | # GET /dictionaries/dictionaries
7 | def index
8 | @dictionaries = Dictionary.all
9 | end
10 |
11 | # GET /dictionaries/dictionaries/new
12 | def new
13 | @dictionary = Dictionary.new
14 | end
15 |
16 | # GET /dictionaries/dictionaries/1/edit
17 | def edit; end
18 |
19 | # POST /dictionaries/dictionaries
20 | def create
21 | @dictionary = Dictionary.new(dictionary_params)
22 |
23 | if @dictionary.save
24 | redirect_to dictionaries_url, notice: "dictionary was successfully created."
25 | else
26 | render :new
27 | end
28 | end
29 |
30 | # PATCH/PUT /dictionaries/dictionaries/1
31 | def update
32 | if @dictionary.update(dictionary_params)
33 | redirect_to dictionaries_url, notice: "dictionary was successfully updated."
34 | else
35 | render :edit
36 | end
37 | end
38 |
39 | # DELETE /dictionaries/dictionaries/1
40 | def destroy
41 | @dictionary.destroy
42 | redirect_to dictionaries_url, notice: "dictionary was successfully destroyed."
43 | end
44 |
45 | private
46 |
47 | # Use callbacks to share common setup or constraints between actions.
48 | def set_dictionary
49 | @dictionary = Dictionary.find(params[:id])
50 | end
51 |
52 | # Only allow a trusted parameter "white list" through.
53 | def dictionary_params
54 | params.fetch(:dictionary, {}).permit(:scope, :value)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/fields/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::ApplicationController < ApplicationController
4 | before_action :set_field
5 |
6 | protected
7 |
8 | # Use callbacks to share common setup or constraints between actions.
9 | def set_field
10 | @field = Field.find(params[:field_id])
11 | end
12 |
13 | def fields_url
14 | form = @field.form
15 |
16 | case form
17 | when Form
18 | form_fields_url(form)
19 | when NestedForm
20 | nested_form_fields_url(form)
21 | else
22 | raise "Unknown form: #{form.class}"
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/fields/choices_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::ChoicesController < Fields::ApplicationController
4 | before_action :require_attach_choices!
5 | before_action :set_choice, only: %i[edit update destroy]
6 |
7 | def new
8 | @choice = @field.choices.build
9 | end
10 |
11 | def create
12 | @choice = @field.choices.build choice_params
13 | if @choice.save
14 | redirect_to field_choices_url(@field)
15 | else
16 | render :new
17 | end
18 | end
19 |
20 | def edit; end
21 |
22 | def update
23 | if @choice.update choice_params
24 | redirect_to field_choices_url(@field)
25 | else
26 | render :edit
27 | end
28 | end
29 |
30 | def destroy
31 | @choice.destroy
32 | redirect_to field_choices_url(@field)
33 | end
34 |
35 | private
36 |
37 | def require_attach_choices!
38 | redirect_to fields_url unless @field.attached_choices?
39 | end
40 |
41 | def choice_params
42 | params.require(:choice).permit(:label)
43 | end
44 |
45 | def set_choice
46 | @choice = @field.choices.find(params[:id])
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/fields/data_source_options_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::DataSourceOptionsController < Fields::ApplicationController
4 | before_action :require_data_source_options
5 | before_action :set_options
6 |
7 | def edit; end
8 |
9 | def update
10 | @options.assign_attributes(options_params)
11 | if @options.valid? && @field.save(validate: false)
12 | redirect_to fields_url, notice: "Field was successfully updated."
13 | else
14 | render :edit
15 | end
16 | end
17 |
18 | private
19 |
20 | def require_data_source_options
21 | redirect_to fields_url unless @field.respond_to?(:data_source)
22 | end
23 |
24 | def set_options
25 | @options = @field.data_source
26 | end
27 |
28 | def options_params
29 | params.fetch(:options, {}).permit!
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/fields/options_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::OptionsController < Fields::ApplicationController
4 | before_action :set_options
5 |
6 | def edit; end
7 |
8 | def update
9 | @options.assign_attributes(options_params)
10 | if @options.valid? && @field.save(validate: false)
11 | redirect_to fields_url, notice: "Field was successfully updated."
12 | else
13 | render :edit
14 | end
15 | end
16 |
17 | private
18 |
19 | def set_options
20 | @options = @field.options
21 | end
22 |
23 | def options_params
24 | params.fetch(:options, {}).permit!
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/fields/validations_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::ValidationsController < Fields::ApplicationController
4 | before_action :set_validations
5 |
6 | def edit; end
7 |
8 | def update
9 | @validations.assign_attributes(validations_params)
10 | if @validations.valid? && @field.save(validate: false)
11 | redirect_to fields_url, notice: "Field was successfully updated."
12 | else
13 | render :edit
14 | end
15 | end
16 |
17 | private
18 |
19 | def set_validations
20 | @validations = @field.validations
21 | end
22 |
23 | def validations_params
24 | params.fetch(:validations, {}).permit!
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Forms::ApplicationController < ApplicationController
4 | layout "forms"
5 |
6 | before_action :set_form
7 |
8 | protected
9 |
10 | # Use callbacks to share common setup or constraints between actions.
11 | def set_form
12 | @form = Form.find(params[:form_id])
13 | end
14 |
15 | def set_form_with_eager_load_fields_and_sections
16 | @form = Form.includes(:sections, fields: [:choices]).find(params[:form_id])
17 |
18 | grouped_fields = @form.fields.group_by(&:section_id)
19 | @form.sections.each do |section|
20 | association = section.fields.instance_variable_get(:@association)
21 | association.target.concat grouped_fields.fetch(section.id, []).sort_by(&:position)
22 | association.loaded!
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms/fields_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Forms::FieldsController < Forms::ApplicationController
4 | before_action :set_field, only: %i[show edit update destroy]
5 |
6 | # GET /forms/1/fields
7 | def index
8 | @fields = @form.fields.includes(:section).all
9 | end
10 |
11 | # GET /forms/fields/new
12 | def new
13 | @field = @form.fields.build
14 | end
15 |
16 | # GET /forms/1/fields/1/edit
17 | def edit; end
18 |
19 | # POST /forms/1/fields
20 | def create
21 | @field = @form.fields.build(field_params)
22 |
23 | if @field.save
24 | redirect_to form_fields_url(@form), notice: "Field was successfully created."
25 | else
26 | render :new
27 | end
28 | end
29 |
30 | # PATCH/PUT /forms/1/fields/1
31 | def update
32 | if @field.update(field_params)
33 | redirect_to form_fields_url(@form), notice: "Field was successfully updated."
34 | else
35 | render :edit
36 | end
37 | end
38 |
39 | # DELETE /forms/1/fields/1
40 | def destroy
41 | @field.destroy
42 | redirect_to form_fields_url(@form), notice: "Field was successfully destroyed."
43 | end
44 |
45 | private
46 |
47 | # Use callbacks to share common setup or constraints between actions.
48 | def set_field
49 | @field = @form.fields.find(params[:id])
50 | end
51 |
52 | # Only allow a trusted parameter "white list" through.
53 | def field_params
54 | params.fetch(:field, {}).permit(:name, :label, :hint, :section_id, :accessibility, :type)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms/loads_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Forms::LoadsController < Forms::ApplicationController
4 | skip_before_action :set_form, except: [:show]
5 | before_action :set_form_with_eager_load_fields_and_sections, except: [:show]
6 | before_action :set_preview, except: [:show]
7 |
8 | def show; end
9 |
10 | def create
11 | @instance = @preview.load(serialized_form_data)
12 | render :create
13 | end
14 |
15 | private
16 |
17 | def set_preview
18 | @preview = @form.to_virtual_model
19 | end
20 |
21 | def serialized_form_data
22 | params.fetch(:serialized, "")
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms/previews_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Forms::PreviewsController < Forms::ApplicationController
4 | skip_before_action :set_form
5 | before_action :set_form_with_eager_load_fields_and_sections
6 | before_action :set_preview
7 |
8 | def show
9 | @instance = @preview.new
10 | end
11 |
12 | def create
13 | @instance = @preview.new(preview_params)
14 | if @instance.valid?
15 | render :create
16 | else
17 | render :show
18 | end
19 | end
20 |
21 | private
22 |
23 | def set_preview
24 | @preview = @form.to_virtual_model
25 | end
26 |
27 | def preview_params
28 | params.fetch(:preview, {}).permit!
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms/sections_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Forms::SectionsController < Forms::ApplicationController
4 | before_action :set_section, only: %i[show edit update destroy]
5 |
6 | # GET /forms/1/sections
7 | def index
8 | @sections = @form.sections.all
9 | end
10 |
11 | # GET /forms/sections/new
12 | def new
13 | @section = @form.sections.build
14 | end
15 |
16 | # GET /forms/1/sections/1/edit
17 | def edit; end
18 |
19 | # POST /forms/1/sections
20 | def create
21 | @section = @form.sections.build(section_params)
22 |
23 | if @section.save
24 | redirect_to form_sections_url(@form), notice: "Section was successfully created."
25 | else
26 | render :new
27 | end
28 | end
29 |
30 | # PATCH/PUT /forms/1/sections/1
31 | def update
32 | if @section.update(section_params)
33 | redirect_to form_sections_url(@form), notice: "Section was successfully updated."
34 | else
35 | render :edit
36 | end
37 | end
38 |
39 | # DELETE /forms/1/sections/1
40 | def destroy
41 | @section.destroy
42 | redirect_to form_sections_url(@form), notice: "Section was successfully destroyed."
43 | end
44 |
45 | private
46 |
47 | # Use callbacks to share common setup or constraints between actions.
48 | def set_section
49 | @section = @form.sections.find(params[:id])
50 | end
51 |
52 | # Only allow a trusted parameter "white list" through.
53 | def section_params
54 | params.fetch(:section, {}).permit(:title, :headless)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/forms_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class FormsController < ApplicationController
4 | layout "application"
5 |
6 | before_action :set_form, only: %i[edit update destroy]
7 |
8 | # GET /forms
9 | def index
10 | @forms = Form.all
11 | end
12 |
13 | # GET /forms/new
14 | def new
15 | @form = Form.new
16 | end
17 |
18 | # GET /forms/1/edit
19 | def edit; end
20 |
21 | # POST /forms
22 | def create
23 | @form = Form.new(form_params)
24 |
25 | if @form.save
26 | redirect_to form_fields_url(@form), notice: "Form was successfully created."
27 | else
28 | render :new
29 | end
30 | end
31 |
32 | # PATCH/PUT /forms/1
33 | def update
34 | if @form.update(form_params)
35 | redirect_to form_fields_url(@form), notice: "Form was successfully updated."
36 | else
37 | render :edit
38 | end
39 | end
40 |
41 | # DELETE /forms/1
42 | def destroy
43 | @form.destroy
44 | redirect_to forms_url, notice: "Form was successfully destroyed."
45 | end
46 |
47 | def random
48 | @form = Form.create_random_form!
49 |
50 | redirect_to form_fields_url(@form), notice: "Form was successfully generated."
51 | end
52 |
53 | private
54 |
55 | # Use callbacks to share common setup or constraints between actions.
56 | def set_form
57 | @form = Form.find(params[:id])
58 | end
59 |
60 | # Only allow a trusted parameter "white list" through.
61 | def form_params
62 | params.fetch(:form, {}).permit(:title, :description)
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/nested_forms/application_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NestedForms::ApplicationController < ApplicationController
4 | before_action :set_nested_form
5 |
6 | protected
7 |
8 | # Use callbacks to share common setup or constraints between actions.
9 | def set_nested_form
10 | @nested_form = NestedForm.find(params[:nested_form_id])
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/nested_forms/fields_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NestedForms::FieldsController < NestedForms::ApplicationController
4 | before_action :set_field, only: %i[show edit update destroy]
5 |
6 | def index
7 | @fields = @nested_form.fields.includes(:section).all
8 | end
9 |
10 | def new
11 | @field = @nested_form.fields.build
12 | end
13 |
14 | def edit; end
15 |
16 | def create
17 | @field = @nested_form.fields.build(field_params)
18 |
19 | if @field.save
20 | redirect_to nested_form_fields_url(@nested_form), notice: "Field was successfully created."
21 | else
22 | render :new
23 | end
24 | end
25 |
26 | def update
27 | if @field.update(field_params)
28 | redirect_to nested_form_fields_url(@nested_form), notice: "Field was successfully updated."
29 | else
30 | render :edit
31 | end
32 | end
33 |
34 | def destroy
35 | @field.destroy
36 | redirect_to nested_form_fields_url(@nested_form), notice: "Field was successfully destroyed."
37 | end
38 |
39 | private
40 |
41 | # Use callbacks to share common setup or constraints between actions.
42 | def set_field
43 | @field = @nested_form.fields.find(params[:id])
44 | end
45 |
46 | # Only allow a trusted parameter "white list" through.
47 | def field_params
48 | params.fetch(:field, {}).permit(:name, :label, :hint, :accessibility, :type)
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/test/dummy/app/controllers/time_zones_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class TimeZonesController < ApplicationController
4 | def update
5 | @time_zone = ActiveSupport::TimeZone[params[:time_zone]]
6 | return render :not_found unless @time_zone
7 |
8 | session[:current_time_zone] = params[:time_zone]
9 |
10 | redirect_back fallback_location: root_url
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ApplicationHelper
4 | def options_for_enum_select(klass, attribute, selected = nil)
5 | container = klass.public_send(attribute.to_s.pluralize).map do |k, v|
6 | v ||= k
7 | [klass.human_enum_value(attribute, k), v]
8 | end
9 |
10 | options_for_select(container, selected)
11 | end
12 |
13 | def present(model, options = {})
14 | klass = options.delete(:presenter_class) || "#{model.class}Presenter".constantize
15 | presenter = klass.new(model, self, options)
16 |
17 | yield(presenter) if block_given?
18 |
19 | presenter
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/fields_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FieldsHelper
4 | def options_for_field_types(selected: nil)
5 | options_for_select(Field.descendants.map { |klass| [klass.model_name.human, klass.to_s] }, selected)
6 | end
7 |
8 | def options_for_data_source_types(selected: nil)
9 | options_for_select(DataSource.descendants.map { |klass| [klass.model_name.human, klass.to_s] }, selected)
10 | end
11 |
12 | def field_label(form, field_name:)
13 | field_name = field_name.to_s.split(".").first.to_sym
14 |
15 | form.fields.select do |field|
16 | field.name == field_name
17 | end.first&.label
18 | end
19 |
20 | def fields_path
21 | form = @field.form
22 |
23 | case form
24 | when Form
25 | form_fields_path(form)
26 | when NestedForm
27 | nested_form_fields_path(form)
28 | else
29 | raise "Unknown form: #{form.class}"
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/helpers/forms_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module FormsHelper
4 | def smart_form_fields_path(form)
5 | case form
6 | when Form
7 | form_fields_path(form)
8 | when NestedForm
9 | nested_form_fields_path(form)
10 | else
11 | raise "Unknown form: #{form.class}"
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/test/dummy/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationJob < ActiveJob::Base
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/lib/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/app/lib/.keep
--------------------------------------------------------------------------------
/test/dummy/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationRecord < ActiveRecord::Base
4 | self.abstract_class = true
5 |
6 | include ActsAsDefaultValue
7 | include EnumAttributeLocalizable
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/choice.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Choice < ApplicationRecord
4 | belongs_to :field
5 |
6 | validates :label,
7 | presence: true
8 |
9 | acts_as_list scope: [:field_id]
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/app/models/concerns/.keep
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/enum_attribute_localizable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module EnumAttributeLocalizable
4 | extend ActiveSupport::Concern
5 |
6 | module ClassMethods
7 | def human_enum_value(attribute, value, options = {})
8 | parts = attribute.to_s.split(".")
9 | attribute = parts.pop.pluralize
10 | attributes_scope = "#{i18n_scope}.attributes"
11 |
12 | if parts.any?
13 | namespace = parts.join("/")
14 | defaults = lookup_ancestors.map do |klass|
15 | :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}.#{value}"
16 | end
17 | defaults << :"#{attributes_scope}.#{namespace}.#{attribute}.#{value}"
18 | else
19 | defaults = lookup_ancestors.map do |klass|
20 | :"#{attributes_scope}.#{klass.model_name.i18n_key}.#{attribute}.#{value}"
21 | end
22 | end
23 |
24 | defaults << :"attributes.#{attribute}.#{value}"
25 | defaults << options.delete(:default) if options[:default]
26 | defaults << value.to_s.humanize
27 |
28 | options[:default] = defaults
29 | I18n.translate(defaults.shift, **options)
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/fake.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Fake
5 | extend ActiveSupport::Concern
6 |
7 | module ClassMethods
8 | def configure_fake_options_to(_field); end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Helper
5 | extend ActiveSupport::Concern
6 |
7 | def options_configurable?
8 | options.is_a?(FieldOptions) && options.attributes.any?
9 | end
10 |
11 | def validations_configurable?
12 | validations.is_a?(FieldOptions) && validations.attributes.any?
13 | end
14 |
15 | def attached_choices?
16 | false
17 | end
18 |
19 | def attached_data_source?
20 | false
21 | end
22 |
23 | def attached_nested_form?
24 | false
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/options/data_source.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Options::DataSource
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :data_source_type, :string, default: DataSources::Empty.to_s
9 |
10 | ::DataSource.descendants.each do |klass|
11 | key = :"#{klass.type_key}_data_source"
12 | embeds_one key, class_name: klass.to_s
13 | accepts_nested_attributes_for key
14 | end
15 |
16 | validates :data_source_type,
17 | inclusion: { in: ->(_) { ::DataSource.descendants.map(&:to_s) } },
18 | allow_blank: false
19 | end
20 |
21 | def data_source
22 | send(:"#{data_source_class.type_key}_data_source") || send(:"build_#{data_source_class.type_key}_data_source")
23 | end
24 |
25 | def data_source_class
26 | data_source_type.safe_constantize || ::DataSources::Empty
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/acceptance.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Acceptance
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :acceptance, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless acceptance
14 |
15 | model.validates field_name, acceptance: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/confirmation.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Confirmation
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :confirmation, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless confirmation
14 |
15 | model.validates field_name, confirmation: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/exclusion.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Exclusion
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :exclusion, class_name: "Fields::Validations::Exclusion::ExclusionOptions"
9 | accepts_nested_attributes_for :exclusion
10 |
11 | after_initialize do
12 | build_exclusion unless exclusion
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | exclusion&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class ExclusionOptions < FieldOptions
22 | attribute :message, :string, default: ""
23 | attribute :in, :string, default: [], array: true
24 |
25 | def interpret_to(model, field_name, _accessibility, _options = {})
26 | return if self.in.empty?
27 |
28 | options = { in: self.in }
29 | options[:message] = message if message.present?
30 |
31 | model.validates field_name, exclusion: options, allow_blank: true
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/format.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Format
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :format, class_name: "Fields::Validations::Format::FormatOptions"
9 | accepts_nested_attributes_for :format
10 |
11 | after_initialize do
12 | build_format unless format
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | format&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class FormatOptions < FieldOptions
22 | attribute :with, :string, default: ""
23 | attribute :message, :string, default: ""
24 |
25 | validate do
26 | Regexp.new(with) if with.present?
27 | rescue RegexpError
28 | errors.add :with, :invalid
29 | end
30 |
31 | def interpret_to(model, field_name, _accessibility, _options = {})
32 | return if with.blank?
33 |
34 | with = Regexp.new(self.with)
35 |
36 | options = { with: with }
37 | options[:message] = message if message.present?
38 |
39 | model.validates field_name, format: options, allow_blank: true
40 | end
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/inclusion.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Inclusion
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | embeds_one :inclusion, class_name: "Fields::Validations::Inclusion::InclusionOptions"
9 | accepts_nested_attributes_for :inclusion
10 |
11 | after_initialize do
12 | build_inclusion unless inclusion
13 | end
14 | end
15 |
16 | def interpret_to(model, field_name, accessibility, options = {})
17 | super
18 | inclusion&.interpret_to model, field_name, accessibility, options
19 | end
20 |
21 | class InclusionOptions < FieldOptions
22 | attribute :message, :string, default: ""
23 | attribute :in, :string, default: [], array: true
24 |
25 | def interpret_to(model, field_name, _accessibility, _options = {})
26 | return if self.in.empty?
27 |
28 | options = { in: self.in }
29 | options[:message] = message if message.present?
30 |
31 | model.validates field_name, inclusion: options, allow_blank: true
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/test/dummy/app/models/concerns/fields/validations/presence.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Validations::Presence
5 | extend ActiveSupport::Concern
6 |
7 | included do
8 | attribute :presence, :boolean, default: false
9 | end
10 |
11 | def interpret_to(model, field_name, _accessibility, _options = {})
12 | super
13 | return unless presence
14 |
15 | model.validates field_name, presence: true
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/dummy/app/models/data_source.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DataSource < FieldOptions
4 | def type_key
5 | self.class.type_key
6 | end
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | def foreign_field_name_suffix
13 | "_id"
14 | end
15 |
16 | def foreign_field_name(field_name)
17 | "#{field_name}#{foreign_field_name_suffix}"
18 | end
19 |
20 | def value_method
21 | :id
22 | end
23 |
24 | def text_method
25 | raise NotImplementedError
26 | end
27 |
28 | def value_for_preview_method
29 | raise NotImplementedError
30 | end
31 |
32 | def scoped_condition
33 | serializable_hash
34 | end
35 |
36 | def scoped_records(**additional_condition)
37 | condition = scoped_condition.merge(additional_condition)
38 | self.class.scoped_records(condition)
39 | end
40 |
41 | def interpret_to(model, field_name, accessibility, _options = {}); end
42 |
43 | class << self
44 | def type_key
45 | model_name.name.split("::").last.underscore
46 | end
47 |
48 | def scoped_records(_condition)
49 | raise NotImplementedError
50 | end
51 | end
52 | end
53 |
54 | require_dependency "data_sources"
55 |
--------------------------------------------------------------------------------
/test/dummy/app/models/data_sources.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DataSources
4 | %w[empty dictionary].each do |type|
5 | require_dependency "data_sources/#{type}"
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/data_sources/dictionary.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DataSources
4 | class Dictionary < DataSource
5 | def text_method
6 | :value
7 | end
8 |
9 | def value_for_preview_method
10 | :value
11 | end
12 |
13 | attribute :scope, :string, default: ""
14 |
15 | validates :scope,
16 | format: { with: ::Dictionary::SCOPE_REGEX },
17 | allow_blank: true
18 |
19 | class << self
20 | def scoped_records(condition)
21 | return ::Dictionary.none if condition.blank?
22 |
23 | ::Dictionary.where(condition)
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/data_sources/empty.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DataSources
4 | class Empty < DataSource
5 | def foreign_field_name_suffix
6 | ""
7 | end
8 |
9 | def foreign_field_name(field_name)
10 | field_name
11 | end
12 |
13 | def text_method
14 | nil
15 | end
16 |
17 | def interpret_to(_model, _field_name, _accessibility, _options = {}); end
18 |
19 | class << self
20 | def scoped_records(*)
21 | ApplicationRecord.none
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/app/models/dictionary.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Dictionary < ApplicationRecord
4 | SCOPE_REGEX = /\A([a-z_][a-z_0-9]*\.)*[a-z_][a-z_0-9]*\z/.freeze
5 |
6 | attribute :value, :string
7 | validates :value,
8 | presence: true, uniqueness: { scope: :scope }
9 |
10 | validates :scope,
11 | presence: true,
12 | format: { with: SCOPE_REGEX }
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | %w[
5 | text boolean decimal integer
6 | date datetime
7 | choice multiple_choice
8 | select multiple_select
9 | integer_range decimal_range date_range datetime_range
10 | nested_form multiple_nested_form
11 | attachment multiple_attachment
12 | resource_select multiple_resource_select
13 | resource multiple_resource
14 | ].each do |type|
15 | require_dependency "fields/#{type}_field"
16 | end
17 |
18 | MAP = Hash[*Field.descendants.map { |f| [f.type_key, f] }.flatten]
19 | end
20 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/attachment_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class AttachmentField < Field
5 | serialize :validations, Validations::AttachmentField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | def interpret_to(model, overrides: {})
13 | check_model_validity!(model)
14 |
15 | accessibility = overrides.fetch(:accessibility, self.accessibility)
16 | return model if accessibility == :hidden
17 |
18 | model.attribute name, stored_type
19 | model.has_one_attached name
20 | model.attr_readonly name if accessibility == :readonly
21 |
22 | interpret_validations_to model, accessibility, overrides
23 | interpret_extra_to model, accessibility, overrides
24 |
25 | model
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/boolean_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class BooleanField < Field
5 | serialize :validations, Validations::BooleanField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :boolean
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/choice_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ChoiceField < Field
5 | serialize :validations, Validations::ChoiceField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | def attached_choices?
13 | true
14 | end
15 |
16 | protected
17 |
18 | def interpret_extra_to(model, accessibility, overrides = {})
19 | super
20 | return if accessibility != :read_and_write
21 |
22 | choice_ids = choices.pluck(:id)
23 | return if choice_ids.empty?
24 |
25 | model.validates name, inclusion: { in: choice_ids }, allow_blank: true
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/date_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DateField < Field
5 | serialize :validations, Validations::DateField
6 | serialize :options, Options::DateField
7 |
8 | def stored_type
9 | :datetime
10 | end
11 |
12 | protected
13 |
14 | def interpret_extra_to(model, accessibility, overrides = {})
15 | super
16 |
17 | model.class_eval <<-CODE, __FILE__, __LINE__ + 1
18 | def #{name}=(val)
19 | super(val.try(:in_time_zone)&.utc)
20 | end
21 | CODE
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/date_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DateRangeField < Field
5 | serialize :validations, Validations::DateRangeField
6 | serialize :options, Options::DateRangeField
7 |
8 | def interpret_to(model, overrides: {})
9 | check_model_validity!(model)
10 |
11 | accessibility = overrides.fetch(:accessibility, self.accessibility)
12 | return model if accessibility == :hidden
13 |
14 | nested_model = Class.new(::Fields::Embeds::DateRange)
15 |
16 | model.nested_models[name] = nested_model
17 |
18 | model.embeds_one name, anonymous_class: nested_model, validate: true
19 | model.accepts_nested_attributes_for name, reject_if: :all_blank
20 |
21 | interpret_validations_to model, accessibility, overrides
22 | interpret_extra_to model, accessibility, overrides
23 |
24 | model
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/datetime_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DatetimeField < Field
5 | serialize :validations, Validations::DatetimeField
6 | serialize :options, Options::DatetimeField
7 |
8 | def stored_type
9 | :datetime
10 | end
11 |
12 | protected
13 |
14 | def interpret_extra_to(model, accessibility, overrides = {})
15 | super
16 |
17 | model.class_eval <<-CODE, __FILE__, __LINE__ + 1
18 | def #{name}=(val)
19 | super(val.try(:in_time_zone)&.utc)
20 | end
21 | CODE
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/datetime_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DatetimeRangeField < Field
5 | serialize :validations, Validations::DatetimeRangeField
6 | serialize :options, Options::DatetimeRangeField
7 |
8 | def interpret_to(model, overrides: {})
9 | check_model_validity!(model)
10 |
11 | accessibility = overrides.fetch(:accessibility, self.accessibility)
12 | return model if accessibility == :hidden
13 |
14 | nested_model = Class.new(::Fields::Embeds::DatetimeRange)
15 |
16 | model.nested_models[name] = nested_model
17 |
18 | model.embeds_one name, anonymous_class: nested_model, validate: true
19 | model.accepts_nested_attributes_for name, reject_if: :all_blank
20 |
21 | interpret_validations_to model, accessibility, overrides
22 | interpret_extra_to model, accessibility, overrides
23 |
24 | model
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DecimalField < Field
5 | serialize :validations, Validations::DecimalField
6 | serialize :options, Options::DecimalField
7 |
8 | def stored_type
9 | :decimal
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/decimal_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DecimalRangeField < Field
5 | serialize :validations, Validations::DecimalRangeField
6 | serialize :options, Options::DecimalRangeField
7 |
8 | def interpret_to(model, overrides: {})
9 | check_model_validity!(model)
10 |
11 | accessibility = overrides.fetch(:accessibility, self.accessibility)
12 | return model if accessibility == :hidden
13 |
14 | nested_model = Class.new(::Fields::Embeds::DecimalRange)
15 |
16 | model.nested_models[name] = nested_model
17 |
18 | model.embeds_one name, anonymous_class: nested_model, validate: true
19 | model.accepts_nested_attributes_for name, reject_if: :all_blank
20 |
21 | interpret_validations_to model, accessibility, overrides
22 | interpret_extra_to model, accessibility, overrides
23 |
24 | model
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/embeds/date_range.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Embeds
5 | class DateRange < VirtualModel
6 | attribute :begin, :datetime
7 | attribute :end, :datetime
8 |
9 | validates :begin,
10 | presence: true
11 |
12 | validates :end,
13 | timeliness: {
14 | after: :begin,
15 | type: :date
16 | },
17 | allow_blank: true,
18 | if: -> { read_attribute(:begin).present? }
19 |
20 | def begin=(val)
21 | super(val.try(:in_time_zone)&.utc)
22 | end
23 |
24 | def end=(val)
25 | super(val.try(:in_time_zone)&.utc)
26 | end
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/embeds/datetime_range.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Embeds
5 | class DatetimeRange < VirtualModel
6 | attribute :begin, :datetime
7 | attribute :end, :datetime
8 |
9 | validates :begin,
10 | presence: true
11 |
12 | validates :end,
13 | timeliness: {
14 | after: :begin,
15 | type: :datetime
16 | },
17 | allow_blank: true,
18 | if: -> { read_attribute(:begin).present? }
19 |
20 | def begin=(val)
21 | super(val.try(:in_time_zone)&.utc)
22 | end
23 |
24 | def end=(val)
25 | super(val.try(:in_time_zone)&.utc)
26 | end
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/embeds/decimal_range.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Embeds
5 | class DecimalRange < VirtualModel
6 | attribute :begin, :decimal
7 | attribute :end, :decimal
8 |
9 | validates :begin, :end,
10 | presence: true,
11 | numericality: { only_integer: false }
12 |
13 | validates :end,
14 | numericality: {
15 | greater_than: :begin
16 | },
17 | allow_blank: true,
18 | if: -> { read_attribute(:begin).present? }
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/embeds/integer_range.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module Embeds
5 | class IntegerRange < VirtualModel
6 | attribute :begin, :integer
7 | attribute :end, :integer
8 |
9 | validates :begin, :end,
10 | presence: true,
11 | numericality: { only_integer: true }
12 |
13 | validates :end,
14 | numericality: {
15 | greater_than: :begin
16 | },
17 | allow_blank: true,
18 | if: -> { read_attribute(:begin).present? }
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class IntegerField < Field
5 | serialize :validations, Validations::IntegerField
6 | serialize :options, Options::IntegerField
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | protected
13 |
14 | def interpret_extra_to(model, accessibility, _overrides = {})
15 | return if accessibility != :read_and_write
16 |
17 | model.validates name, numericality: { only_integer: true }, allow_blank: true
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/integer_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class IntegerRangeField < Field
5 | serialize :validations, Validations::IntegerRangeField
6 | serialize :options, Options::IntegerRangeField
7 |
8 | def interpret_to(model, overrides: {})
9 | check_model_validity!(model)
10 |
11 | accessibility = overrides.fetch(:accessibility, self.accessibility)
12 | return model if accessibility == :hidden
13 |
14 | nested_model = Class.new(::Fields::Embeds::IntegerRange)
15 |
16 | model.nested_models[name] = nested_model
17 |
18 | model.embeds_one name, anonymous_class: nested_model, validate: true
19 | model.accepts_nested_attributes_for name, reject_if: :all_blank
20 |
21 | interpret_validations_to model, accessibility, overrides
22 | interpret_extra_to model, accessibility, overrides
23 |
24 | model
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_attachment_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleAttachmentField < Field
5 | serialize :validations, Validations::MultipleAttachmentField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | def interpret_to(model, overrides: {})
13 | check_model_validity!(model)
14 |
15 | accessibility = overrides.fetch(:accessibility, self.accessibility)
16 | return model if accessibility == :hidden
17 |
18 | model.attribute name, stored_type, default: [], array_without_blank: true
19 | model.has_many_attached name
20 | model.attr_readonly name if accessibility == :readonly
21 |
22 | interpret_validations_to model, accessibility, overrides
23 | interpret_extra_to model, accessibility, overrides
24 |
25 | model
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_choice_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleChoiceField < Field
5 | serialize :validations, Validations::MultipleChoiceField
6 | serialize :options, NonConfigurable
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | def attached_choices?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | model.attribute name, stored_type, default: [], array_without_blank: true
23 | model.attr_readonly name if accessibility == :readonly
24 |
25 | interpret_validations_to model, accessibility, overrides
26 | interpret_extra_to model, accessibility, overrides
27 |
28 | model
29 | end
30 |
31 | protected
32 |
33 | def interpret_extra_to(model, accessibility, overrides = {})
34 | super
35 | return if accessibility != :read_and_write
36 |
37 | choice_ids = choices.pluck(:id)
38 | return if choice_ids.empty?
39 |
40 | model.validates name, subset: { in: choice_ids }, allow_blank: true
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleNestedFormField < Field
5 | after_create do
6 | build_nested_form.save!
7 | end
8 |
9 | serialize :validations, Validations::MultipleNestedFormField
10 | serialize :options, NonConfigurable
11 |
12 | def attached_nested_form?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | overrides[:name] = name
23 |
24 | nested_model = nested_form.to_virtual_model(overrides: { _global: { accessibility: accessibility } })
25 |
26 | model.nested_models[name] = nested_model
27 |
28 | model.embeds_many name, anonymous_class: nested_model, validate: true
29 | model.accepts_nested_attributes_for name, reject_if: :all_blank
30 | model.attr_readonly name if accessibility == :readonly
31 |
32 | interpret_validations_to model, accessibility, overrides
33 | interpret_extra_to model, accessibility, overrides
34 |
35 | model
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleResourceField < Field
5 | serialize :validations, Validations::MultipleResourceField
6 | serialize :options, Options::MultipleResourceField
7 |
8 | def stored_type
9 | :string
10 | end
11 |
12 | delegate :data_source, to: :options
13 |
14 | def collection
15 | data_source.scoped_records
16 | end
17 |
18 | def attached_data_source?
19 | true
20 | end
21 |
22 | def interpret_to(model, overrides: {})
23 | check_model_validity!(model)
24 |
25 | accessibility = overrides.fetch(:accessibility, self.accessibility)
26 | return model if accessibility == :hidden
27 |
28 | model.attribute name, stored_type, default: [], array_without_blank: true
29 | model.attr_readonly name if accessibility == :readonly
30 |
31 | interpret_validations_to model, accessibility, overrides
32 | interpret_extra_to model, accessibility, overrides
33 |
34 | model
35 | end
36 |
37 | protected
38 |
39 | def interpret_extra_to(model, accessibility, overrides = {})
40 | super
41 | return if accessibility != :read_and_write
42 |
43 | # TODO: performance
44 | # model.validates name, subset: {in: collection}, allow_blank: true
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleResourceSelectField < Field
5 | serialize :validations, Validations::MultipleResourceSelectField
6 | serialize :options, Options::MultipleResourceSelectField
7 |
8 | def stored_type
9 | :string
10 | end
11 |
12 | delegate :data_source, to: :options
13 |
14 | def collection
15 | data_source.scoped_records
16 | end
17 |
18 | def attached_data_source?
19 | true
20 | end
21 |
22 | def interpret_to(model, overrides: {})
23 | check_model_validity!(model)
24 |
25 | accessibility = overrides.fetch(:accessibility, self.accessibility)
26 | return model if accessibility == :hidden
27 |
28 | model.attribute name, stored_type, default: [], array_without_blank: true
29 | model.attr_readonly name if accessibility == :readonly
30 |
31 | interpret_validations_to model, accessibility, overrides
32 | interpret_extra_to model, accessibility, overrides
33 |
34 | model
35 | end
36 |
37 | protected
38 |
39 | def interpret_extra_to(model, accessibility, overrides = {})
40 | super
41 | return if accessibility != :read_and_write || !options.strict_select
42 |
43 | # TODO: performance
44 | # model.validates name, subset: {in: collection}, allow_blank: true
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/multiple_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleSelectField < Field
5 | serialize :validations, Validations::MultipleSelectField
6 | serialize :options, Options::MultipleSelectField
7 |
8 | def stored_type
9 | :string
10 | end
11 |
12 | def attached_choices?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | model.attribute name, stored_type, default: [], array_without_blank: true
23 | model.attr_readonly name if accessibility == :readonly
24 |
25 | interpret_validations_to model, accessibility, overrides
26 | interpret_extra_to model, accessibility, overrides
27 |
28 | model
29 | end
30 |
31 | protected
32 |
33 | def interpret_extra_to(model, accessibility, overrides = {})
34 | super
35 | return if accessibility != :read_and_write || !options.strict_select
36 |
37 | model.validates name, subset: { in: choices.pluck(:label) }, allow_blank: true
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class NestedFormField < Field
5 | after_create do
6 | build_nested_form.save!
7 | end
8 |
9 | serialize :validations, Validations::NestedFormField
10 | serialize :options, NonConfigurable
11 |
12 | def attached_nested_form?
13 | true
14 | end
15 |
16 | def interpret_to(model, overrides: {})
17 | check_model_validity!(model)
18 |
19 | accessibility = overrides.fetch(:accessibility, self.accessibility)
20 | return model if accessibility == :hidden
21 |
22 | nested_model = nested_form.to_virtual_model(overrides: { _global: { accessibility: accessibility } })
23 |
24 | model.nested_models[name] = nested_model
25 |
26 | model.embeds_one name, anonymous_class: nested_model, validate: true
27 | model.accepts_nested_attributes_for name, reject_if: :all_blank
28 | model.attr_readonly name if accessibility == :readonly
29 |
30 | interpret_validations_to model, accessibility, overrides
31 | interpret_extra_to model, accessibility, overrides
32 |
33 | model
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class DecimalField < FieldOptions
5 | attribute :step, :decimal, default: 0.01
6 |
7 | validates :step,
8 | numericality: {
9 | greater_than_or_equal_to: 0.0
10 | }
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class IntegerField < FieldOptions
5 | attribute :step, :integer, default: 0
6 |
7 | validates :step,
8 | numericality: {
9 | only_integer: true,
10 | greater_than_or_equal_to: 0
11 | }
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/multiple_resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class MultipleResourceField < FieldOptions
5 | include Fields::Options::DataSource
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/multiple_resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class MultipleResourceSelectField < FieldOptions
5 | include Fields::Options::DataSource
6 |
7 | attribute :strict_select, :boolean, default: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/multiple_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class MultipleSelectField < FieldOptions
5 | attribute :strict_select, :boolean, default: true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class ResourceField < FieldOptions
5 | include Fields::Options::DataSource
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class ResourceSelectField < FieldOptions
5 | include Fields::Options::DataSource
6 |
7 | attribute :strict_select, :boolean, default: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class SelectField < FieldOptions
5 | attribute :strict_select, :boolean, default: true
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/options/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Options
4 | class TextField < FieldOptions
5 | attribute :multiline, :boolean, default: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ResourceField < Field
5 | serialize :options, Options::ResourceField
6 | serialize :validations, Validations::ResourceField
7 |
8 | def stored_type
9 | :integer
10 | end
11 |
12 | delegate :data_source, to: :options
13 |
14 | def collection
15 | data_source.scoped_records
16 | end
17 |
18 | def attached_data_source?
19 | true
20 | end
21 |
22 | protected
23 |
24 | def interpret_extra_to(model, accessibility, overrides = {})
25 | super
26 | return if accessibility != :read_and_write
27 |
28 | # TODO: performance
29 | # model.validates name, inclusion: {in: collection}, allow_blank: true
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ResourceSelectField < Field
5 | serialize :options, Options::ResourceSelectField
6 | serialize :validations, Validations::ResourceSelectField
7 |
8 | def stored_type
9 | :string
10 | end
11 |
12 | delegate :data_source, to: :options
13 |
14 | def collection
15 | data_source.scoped_records
16 | end
17 |
18 | def attached_data_source?
19 | true
20 | end
21 |
22 | protected
23 |
24 | def interpret_extra_to(model, accessibility, overrides = {})
25 | super
26 | return if accessibility != :read_and_write || !options.strict_select
27 |
28 | # TODO: performance
29 | # model.validates name, inclusion: {in: collection}, allow_blank: true
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class SelectField < Field
5 | serialize :validations, Validations::SelectField
6 | serialize :options, Options::SelectField
7 |
8 | def stored_type
9 | :string
10 | end
11 |
12 | def attached_choices?
13 | true
14 | end
15 |
16 | protected
17 |
18 | def interpret_extra_to(model, accessibility, overrides = {})
19 | super
20 | return if accessibility != :read_and_write || !options.strict_select
21 |
22 | model.validates name, inclusion: { in: choices.pluck(:label) }, allow_blank: true
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class TextField < Field
5 | serialize :validations, Validations::TextField
6 | serialize :options, Options::TextField
7 |
8 | def stored_type
9 | :string
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/attachment_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class AttachmentField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/boolean_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class BooleanField < FieldOptions
5 | prepend Fields::Validations::Acceptance
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/choice_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class ChoiceField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/date_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DateField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/date_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DateRangeField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/datetime_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DatetimeField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/datetime_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DatetimeRangeField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/decimal_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DecimalField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Numericality
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/decimal_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class DecimalRangeField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/integer_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class IntegerField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Numericality
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/integer_range_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class IntegerRangeField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_attachment_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleAttachmentField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_choice_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleChoiceField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleNestedFormField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleResourceField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleResourceSelectField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/multiple_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class MultipleSelectField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/nested_form_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class NestedFormField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/resource_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class ResourceField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/resource_select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class ResourceSelectField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/select_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class SelectField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/models/fields/validations/text_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields::Validations
4 | class TextField < FieldOptions
5 | prepend Fields::Validations::Presence
6 | prepend Fields::Validations::Length
7 | prepend Fields::Validations::Format
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/models/form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Form < MetalForm
4 | has_many :sections, -> { order(position: :asc) }, dependent: :destroy
5 |
6 | validates :title,
7 | presence: true
8 |
9 | after_create :auto_create_default_section
10 |
11 | private
12 |
13 | def auto_create_default_section
14 | sections.create! title: I18n.t("defaults.section.title"), headless: true
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/models/metal_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class MetalForm < ApplicationRecord
4 | include FormCore::Concerns::Models::Form
5 |
6 | self.table_name = "forms"
7 |
8 | has_many :fields, foreign_key: "form_id", dependent: :destroy
9 |
10 | include Forms::Fake
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/models/nested_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NestedForm < MetalForm
4 | belongs_to :attachable, polymorphic: true, touch: true
5 | end
6 |
--------------------------------------------------------------------------------
/test/dummy/app/models/non_configurable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class NonConfigurable < FieldOptions
4 | end
5 |
--------------------------------------------------------------------------------
/test/dummy/app/models/section.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Section < ApplicationRecord
4 | belongs_to :form, touch: true
5 |
6 | has_many :fields, -> { order(position: :asc) }, dependent: :nullify
7 |
8 | acts_as_list scope: [:form_id]
9 |
10 | validates :title,
11 | presence: true
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/app/models/virtual_model.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class VirtualModel < FormCore::VirtualModel
4 | include FormCore::ActiveStorageBridge::Attached::Macros
5 | include FormCore::ActsAsDefaultValue
6 |
7 | include EnumAttributeLocalizable
8 |
9 | # self.inheritance_column = nil
10 |
11 | def persisted?
12 | false
13 | end
14 |
15 | class << self
16 | def nested_models
17 | @nested_models ||= {}
18 | end
19 |
20 | def attr_readonly?(attr_name)
21 | readonly_attributes.include? attr_name.to_s
22 | end
23 |
24 | def metadata
25 | @metadata ||= {}
26 | end
27 |
28 | def _embeds_reflections
29 | _reflections.select { |_, v| v.is_a? ActiveEntity::Reflection::EmbeddedAssociationReflection }
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/dummy/app/overrides/action_view/helpers/tags/date_field_override.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ActionView::Helpers::Tags::DateField.class_eval do
4 | def format_date(value)
5 | value&.in_time_zone&.strftime("%Y-%m-%d")
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/overrides/action_view/helpers/tags/datetime_local_field_override.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ActionView::Helpers::Tags::DatetimeLocalField.class_eval do
4 | def format_date(value)
5 | value&.in_time_zone&.strftime("%Y-%m-%dT%T")
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/application_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationPresenter < SimpleDelegator
4 | def initialize(model, view, options = {})
5 | super(model)
6 |
7 | @model = model
8 | @view = view
9 | @options = options
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/concerns/fields/presenter_for_number_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | module PresenterForNumberField
5 | extend ActiveSupport::Concern
6 |
7 | def min
8 | return if @model.validations.numericality.lower_bound_check_disabled?
9 |
10 | min = @model.validations.numericality.lower_bound_value
11 | integer_only? ? min.to_i : min
12 | end
13 |
14 | def max
15 | return if @model.validations.numericality.upper_bound_check_disabled?
16 |
17 | max = @model.validations.numericality.upper_bound_value
18 | integer_only? ? max.to_i : max
19 | end
20 |
21 | def step
22 | step = @model.options.step
23 | return if step.zero?
24 |
25 | integer_only? ? step.to_i : step
26 | end
27 |
28 | def integer_only?
29 | false
30 | end
31 |
32 | def to_builder_options
33 | { min: min, max: max, step: step, required: required? }.reject { |_, v| v.blank? }
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/attachment_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class AttachmentFieldPresenter < FieldPresenter
5 | def value_for_preview
6 | id = value
7 | return if id.blank?
8 |
9 | blob = ActiveStorage::Blob.find_by id: id
10 | return unless blob
11 |
12 | @view.link_to blob.filename, @view.rails_blob_path(blob, disposition: "attachment")
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/boolean_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class BooleanFieldPresenter < FieldPresenter
5 | def required
6 | @model.validations&.acceptance
7 | end
8 |
9 | def value_for_preview
10 | super ? I18n.t("values.true") : I18n.t("values.false")
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/choice_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ChoiceFieldPresenter < FieldPresenter
5 | def value_for_preview
6 | id = value
7 | return if id.blank?
8 |
9 | if choices.loaded?
10 | choices.target.find { |choice| choice.id == id }&.label
11 | else
12 | choices.find_by(id: id)&.label
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/composite_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class CompositeFieldPresenter < FieldPresenter
5 | def value
6 | target&.send(@model.name)
7 | end
8 |
9 | def value_for_preview
10 | target&.send(@model.name)
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/decimal_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class DecimalFieldPresenter < FieldPresenter
5 | include Fields::PresenterForNumberField
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Fields::FieldPresenter < ApplicationPresenter
4 | def required
5 | @model.validations&.presence
6 | end
7 | alias required? required
8 |
9 | def target
10 | @options[:target]
11 | end
12 |
13 | def value
14 | target&.read_attribute(@model.name)
15 | end
16 |
17 | def value_for_preview
18 | target&.read_attribute(@model.name)
19 | end
20 |
21 | def access_readonly?
22 | target.class.attr_readonly?(@model.name)
23 | end
24 |
25 | def access_hidden?
26 | target.class.attribute_names.exclude?(@model.name.to_s) && target.class._reflections.keys.exclude?(@model.name.to_s)
27 | end
28 |
29 | def access_read_and_write?
30 | !access_readonly? &&
31 | (target.class.attribute_names.include?(@model.name.to_s) || target.class._reflections.key?(@model.name.to_s))
32 | end
33 |
34 | def id
35 | "form_field_#{@model.id}"
36 | end
37 |
38 | def nested_form_field?
39 | false
40 | end
41 |
42 | def multiple_nested_form?
43 | false
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/integer_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class IntegerFieldPresenter < FieldPresenter
5 | include Fields::PresenterForNumberField
6 |
7 | def integer_only?
8 | true
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_attachment_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleAttachmentFieldPresenter < FieldPresenter
5 | def value_for_preview
6 | ids = value
7 | return if ids.blank?
8 |
9 | blobs = ActiveStorage::Blob.where(id: ids)
10 | return if blobs.blank?
11 |
12 | blobs.map do |blob|
13 | @view.link_to blob.filename, @view.rails_blob_path(blob, disposition: "attachment")
14 | end.join(", ").html_safe
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_choice_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleChoiceFieldPresenter < FieldPresenter
5 | def value_for_preview
6 | ids = value
7 | return if ids.blank?
8 |
9 | if choices.loaded?
10 | choices.target.select { |choice| ids.include?(choice.id) }.map(&:label)
11 | else
12 | choices.where(id: ids).map(&:label)
13 | end.join(", ")
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_nested_form_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleNestedFormFieldPresenter < CompositeFieldPresenter
5 | def multiple_nested_form?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_resource_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleResourceFieldPresenter < FieldPresenter
5 | MAX_HARD_CODE_ITEMS_SIZE = 20
6 |
7 | def include_blank?
8 | required?
9 | end
10 |
11 | def value_for_preview
12 | return unless @model.collection
13 | return if @model.collection.none?
14 |
15 | collection
16 | .where(@model.data_source.value_method => value)
17 | .map(&@model.data_source.text_method)
18 | .join(", ")
19 | end
20 |
21 | def collection
22 | return unless @model.collection
23 |
24 | # TODO: limit 100 for performance
25 | @model.collection.limit(100)
26 | end
27 |
28 | def options_for_select
29 | return @view.options_for_select([]) unless @model.collection
30 |
31 | @view.options_from_collection_for_select(
32 | collection, @model.data_source.value_method, @model.data_source.text_method, value
33 | )
34 | end
35 |
36 | def max_items_size
37 | size = @model.validations.length.maximum
38 | size.positive? ? size : MAX_HARD_CODE_ITEMS_SIZE
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_resource_select_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleResourceSelectFieldPresenter < FieldPresenter
5 | MAX_HARD_CODE_ITEMS_SIZE = 20
6 |
7 | def include_blank?
8 | required?
9 | end
10 |
11 | def value_for_preview
12 | super&.join(", ")
13 | end
14 |
15 | def can_custom_value?
16 | !@model.options.strict_select
17 | end
18 |
19 | def collection
20 | values =
21 | if @model.collection
22 | # TODO: limit 100 for performance
23 | @model.collection.limit(100).map(&@model.data_source.text_method)
24 | else
25 | []
26 | end
27 |
28 | if can_custom_value? && value.present?
29 | ([value] + values).uniq
30 | else
31 | values
32 | end
33 | end
34 |
35 | def options_for_select
36 | @view.options_for_select(collection, value)
37 | end
38 |
39 | def max_items_size
40 | size = @model.validations.length.maximum
41 | size.positive? ? size : MAX_HARD_CODE_ITEMS_SIZE
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/multiple_select_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class MultipleSelectFieldPresenter < FieldPresenter
5 | MAX_HARD_CODE_ITEMS_SIZE = 20
6 |
7 | def include_blank?
8 | required?
9 | end
10 |
11 | def value_for_preview
12 | super&.join(", ")
13 | end
14 |
15 | def can_custom_value?
16 | !@model.options.strict_select
17 | end
18 |
19 | def collection
20 | collection = @model.choices.map(&:label)
21 | if can_custom_value? && value.present?
22 | (value + collection).uniq
23 | else
24 | collection
25 | end
26 | end
27 |
28 | def options_for_select
29 | @view.options_for_select(collection, value)
30 | end
31 |
32 | def max_items_size
33 | size = @model.validations.length.maximum
34 | size.positive? ? size : MAX_HARD_CODE_ITEMS_SIZE
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/nested_form_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class NestedFormFieldPresenter < CompositeFieldPresenter
5 | def nested_form_field?
6 | true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/resource_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ResourceFieldPresenter < FieldPresenter
5 | def value_for_preview
6 | return unless @model.collection
7 | return if @model.collection.none?
8 |
9 | id = value
10 | return if id.blank?
11 |
12 | collection
13 | .where(@model.data_source.value_method => id)
14 | .first
15 | &.send(@model.data_source.text_method)
16 | end
17 |
18 | def include_blank?
19 | required?
20 | end
21 |
22 | def collection
23 | return unless @model.collection
24 |
25 | # TODO: limit 100 for performance
26 | @model.collection.limit(100)
27 | end
28 |
29 | def options_for_select
30 | return @view.options_for_select([]) unless @model.collection
31 |
32 | @view.options_from_collection_for_select(
33 | collection, @model.data_source.value_method, @model.data_source.text_method, value
34 | )
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/resource_select_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class ResourceSelectFieldPresenter < FieldPresenter
5 | def include_blank?
6 | required?
7 | end
8 |
9 | def can_custom_value?
10 | !@model.options.strict_select
11 | end
12 |
13 | def collection
14 | values =
15 | if @model.collection
16 | # TODO: limit 100 for performance
17 | @model.collection.limit(100).map(&@model.data_source.text_method)
18 | else
19 | []
20 | end
21 |
22 | if can_custom_value? && value.present?
23 | ([value] + values).uniq
24 | else
25 | values
26 | end
27 | end
28 |
29 | def options_for_select
30 | @view.options_for_select(collection, value)
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/select_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class SelectFieldPresenter < FieldPresenter
5 | def include_blank?
6 | required?
7 | end
8 |
9 | def can_custom_value?
10 | !@model.options.strict_select
11 | end
12 |
13 | def collection
14 | collection = @model.choices.map(&:label)
15 | if can_custom_value? && value.present?
16 | ([value] + collection).uniq
17 | else
18 | collection
19 | end
20 | end
21 |
22 | def options_for_select
23 | @view.options_for_select(collection, value)
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/dummy/app/presenters/fields/text_field_presenter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Fields
4 | class TextFieldPresenter < FieldPresenter
5 | def multiline
6 | @model.options.multiline
7 | end
8 | alias multiline? multiline
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/data_source_options/_dictionary.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label :scope %>
3 |
4 | <%= f.text_field :scope, class: "input", required: true %>
5 |
6 |
7 | The dictionary's scope you've created, go to <%= link_to "Dictionaries", dictionaries_path, target: "_blank" %> to check this out.
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/data_source_options/_empty.html.erb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/app/views/_form_core/data_source_options/_empty.html.erb
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_decimal_field.html.erb:
--------------------------------------------------------------------------------
1 | Decimal field
2 |
3 |
4 | <%= f.label :step, class: "label" %>
5 |
6 | <%= f.number_field :step, class: "input", min: 0, step: 0.01 %>
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_integer_field.html.erb:
--------------------------------------------------------------------------------
1 | Integer field
2 |
3 |
4 | <%= f.label :step, class: "label" %>
5 |
6 | <%= f.number_field :step, class: "input", min: 0, step: 1 %>
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_multiple_resource_field.html.erb:
--------------------------------------------------------------------------------
1 | Multiple resource field
2 |
3 |
4 | <%= f.label :data_source_type, class: "label" %>
5 |
6 |
7 | <%= f.select :data_source_type, options_for_data_source_types(selected: options.data_source_type) %>
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_multiple_resource_select_field.html.erb:
--------------------------------------------------------------------------------
1 | Multiple resource Select field
2 |
3 |
4 | <%= f.label :data_source_type, class: "label" %>
5 |
6 |
7 | <%= f.select :data_source_type, options_for_data_source_types(selected: options.data_source_type) %>
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_multiple_select_field.html.erb:
--------------------------------------------------------------------------------
1 | Select field
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_resource_field.html.erb:
--------------------------------------------------------------------------------
1 | Resource field
2 |
3 |
4 | <%= f.label :data_source_type, class: "label" %>
5 |
6 |
7 | <%= f.select :data_source_type, options_for_data_source_types(selected: options.data_source_type) %>
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_resource_select_field.html.erb:
--------------------------------------------------------------------------------
1 | Resource Select field
2 |
3 |
4 | <%= f.label :data_source_type, class: "label" %>
5 |
6 |
7 | <%= f.select :data_source_type, options_for_data_source_types(selected: options.data_source_type) %>
8 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_select_field.html.erb:
--------------------------------------------------------------------------------
1 | Select field
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/field_options/_text_field.html.erb:
--------------------------------------------------------------------------------
1 | Text field
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_attachment_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.file_field field.name, direct_upload: true %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_boolean_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | <% if field.hint.present? %>
9 |
<%= field.hint %>
10 | <% end %>
11 |
12 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_choice_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.collection_radio_buttons field.name, field.choices, :id, :label do |m| %>
5 |
9 | <% end %>
10 |
11 | <% if field.hint.present? %>
12 |
<%= field.hint %>
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_date_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.date_field field.name, field.field_options.merge(class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?) %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_date_range_field.html.erb:
--------------------------------------------------------------------------------
1 | <% f.object.send("build_#{field.name}") unless f.object.send(field.name) %>
2 |
3 |
4 | <%= f.label field.name, field.label, class: 'label' %>
5 |
6 | <%= f.fields_for field.name do |ff| %>
7 |
8 |
9 | <%= ff.date_field :begin, class: 'input', id: "#{field.id}_begin", required: field.required, **field.begin_options %>
10 |
11 |
12 |
13 | ~
14 |
15 |
16 |
17 | <%= ff.date_field :end, class: 'input', id: "#{field.id}_end", **field.end_options %>
18 |
19 |
20 | <% end %>
21 |
22 | <% if field.hint.present? %>
23 |
<%= field.hint %>
24 | <% end %>
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_datetime_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.datetime_field field.name, field.field_options.merge(class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?) %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_datetime_range_field.html.erb:
--------------------------------------------------------------------------------
1 | <% f.object.send("build_#{field.name}") unless f.object.send(field.name) %>
2 |
3 |
4 | <%= f.label field.name, field.label, class: 'label' %>
5 |
6 | <%= f.fields_for field.name do |ff| %>
7 |
8 |
9 | <%= ff.datetime_field :begin, class: 'input', id: "#{field.id}_begin", required: field.required, **field.begin_options %>
10 |
11 |
12 |
13 | ~
14 |
15 |
16 |
17 | <%= ff.datetime_field :end, class: 'input', id: "#{field.id}_end", **field.end_options %>
18 |
19 |
20 | <% end %>
21 |
22 | <% if field.hint.present? %>
23 |
<%= field.hint %>
24 | <% end %>
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_decimal_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.number_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?, **field.to_builder_options %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_decimal_range_field.html.erb:
--------------------------------------------------------------------------------
1 | <% f.object.send("build_#{field.name}") unless f.object.send(field.name) %>
2 |
3 |
4 | <%= f.label field.name, field.label, class: 'label' %>
5 |
6 | <%= f.fields_for field.name do |ff| %>
7 |
8 |
9 | <%= ff.number_field :begin, class: 'input', id: "#{field.id}_begin", required: field.required, **field.begin_options %>
10 |
11 |
12 |
13 | ~
14 |
15 |
16 |
17 | <%= ff.number_field :end, class: 'input', id: "#{field.id}_end", required: field.required, **field.end_options %>
18 |
19 |
20 | <% end %>
21 |
22 | <% if field.hint.present? %>
23 |
<%= field.hint %>
24 | <% end %>
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_integer_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.number_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly?, **field.to_builder_options %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_integer_range_field.html.erb:
--------------------------------------------------------------------------------
1 | <% f.object.send("build_#{field.name}") unless f.object.send(field.name) %>
2 |
3 |
4 | <%= f.label field.name, field.label, class: 'label' %>
5 |
6 | <%= f.fields_for field.name do |ff| %>
7 |
8 |
9 | <%= ff.number_field :begin, class: 'input', id: "#{field.id}_begin", required: field.required, **field.begin_options %>
10 |
11 |
12 |
13 | ~
14 |
15 |
16 |
17 | <%= ff.number_field :end, class: 'input', id: "#{field.id}_end", required: field.required, **field.end_options %>
18 |
19 |
20 | <% end %>
21 |
22 | <% if field.hint.present? %>
23 |
<%= field.hint %>
24 | <% end %>
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_attachment_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.file_field field.name, multiple: true, direct_upload: true %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_choice_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.collection_check_boxes field.name, field.choices, :id, :label do |m| %>
5 |
9 | <% end %>
10 |
11 | <% if field.hint.present? %>
12 |
<%= field.hint %>
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_nested_form_field.html.erb:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_resource_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly?, multiple: true %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_resource_select_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly?, multiple: true %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
27 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_multiple_select_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly?, multiple: true %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
27 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_nested_form.html.erb:
--------------------------------------------------------------------------------
1 | <% nesting ||= false %>
2 |
3 |
40 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_nested_form_field.html.erb:
--------------------------------------------------------------------------------
1 |
25 |
26 | <% if field.access_read_and_write? %>
27 |
42 | <% end %>
43 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_resource_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly? %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
21 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_resource_select_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly? %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_select_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <%= f.select field.name, field.options_for_select, {include_blank: field.include_blank?}, id: field.id, class: field.id, required: field.required, disabled: field.access_readonly? %>
5 |
6 | <% if field.hint.present? %>
7 |
<%= field.hint %>
8 | <% end %>
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/fields/_text_field.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.label field.name, field.label, class: 'label' %>
3 |
4 | <% if field.options.multiline %>
5 | <%= f.text_area field.name, class: 'textarea', id: field.id, required: field.required, disabled: field.access_readonly? %>
6 | <% else %>
7 | <%= f.text_field field.name, class: 'input', id: field.id, required: field.required, disabled: field.access_readonly? %>
8 | <% end %>
9 |
10 | <% if field.hint.present? %>
11 |
<%= field.hint %>
12 | <% end %>
13 |
14 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/preview/_form.html.erb:
--------------------------------------------------------------------------------
1 | <% title_tag ||= :h3 %>
2 | <% form.sections.each do |section| %>
3 | <% fields = section.fields.map { |field| present(field, target: instance) }.reject(&:access_hidden?) %>
4 | <% next if fields.empty? %>
5 |
6 | <% unless section.headless? %>
7 | <%= content_tag title_tag, section.title %>
8 | <% end %>
9 |
10 | <% fields.each do |field| %>
11 | <% if field.nested_form_field? %>
12 | <% next unless field.value_for_preview %>
13 |
14 | <%= field.label %>:
15 | <%= render "_form_core/preview/nested_form", form: field.nested_form, instance: field.value_for_preview %>
16 | <% elsif field.multiple_nested_form? %>
17 | <% next if field.value_for_preview.empty? %>
18 |
19 | <%= field.label %>:
20 | <%= field.value_for_preview.map do |nested_instance| %>
21 | <% render "_form_core/preview/nested_form", form: field.nested_form, instance: nested_instance %>
22 | <% end.join("
").html_safe %>
23 | <% else %>
24 | <%= field.label %>: <%= field.value_for_preview %>
25 | <% end %>
26 | <% end %>
27 | <% end %>
28 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/preview/_nested_form.html.erb:
--------------------------------------------------------------------------------
1 | <% fields = form.fields.map { |field| present(field, target: instance) }.reject(&:access_hidden?) %>
2 | <% return if fields.empty? %>
3 |
4 |
5 | <% fields.each do |field| %>
6 | <% if field.nested_form_field? %>
7 | <% next unless field.value_for_preview %>
8 |
9 |
<%= field.label %>:
10 | <%= render "_form_core/preview/nested_form", form: field.nested_form, instance: field.value_for_preview %>
11 | <% elsif field.multiple_nested_form? %>
12 | <% next if field.value_for_preview.empty? %>
13 |
14 |
<%= field.label %>:
15 | <%= field.value_for_preview.map do |nested_instance| %>
16 | <% render "_form_core/preview/nested_form", form: field.nested_form, instance: nested_instance %>
17 | <% end.join("
").html_safe %>
18 | <% else %>
19 |
<%= field.label %>: <%= field.value_for_preview %>
20 | <% end %>
21 | <% end %>
22 |
23 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/render/_form.html.erb:
--------------------------------------------------------------------------------
1 | <% options ||= {} %>
2 | <%= form_with(model: instance, **options) do |f| %>
3 | <% if instance.errors.any? %>
4 |
5 |
10 |
11 |
12 | <% instance.errors.messages.each do |name, messages| %>
13 | <% messages.each do |message| %>
14 | - <%= "#{field_label(form, field_name: name)} #{message}" %>
15 | <% end %>
16 | <% end %>
17 |
18 |
19 |
20 | <% end %>
21 |
22 | <% form.sections.each do |section| %>
23 | <% fields = section.fields.map { |field| present(field, target: instance) }.reject(&:access_hidden?) %>
24 | <% next if fields.empty? %>
25 |
26 | <% unless section.headless? %>
27 | <%= section.title %>
28 | <% end %>
29 |
30 | <% fields.each do |field| %>
31 | <%= render "_form_core/fields/#{field.type_key}", f: f, field: field %>
32 | <% end %>
33 | <% end %>
34 |
35 |
36 |
37 | <%= f.submit "Submit", class: "button is-primary" %>
38 |
39 |
40 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
41 |
42 |
43 | <% end %>
44 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_acceptance.html.erb:
--------------------------------------------------------------------------------
1 | Acceptance
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_confirmation.html.erb:
--------------------------------------------------------------------------------
1 | Confirmation
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_exclusion.html.erb:
--------------------------------------------------------------------------------
1 | Exclusion
2 |
3 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_format.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_format unless validations.format %>
2 | <% format = validations.format %>
3 |
4 | Format
5 |
6 | <%= f.fields_for :format, format do |ff| %>
7 | <% if format.errors.any? %>
8 |
9 |
14 |
15 | <% format.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 | <%= ff.label :with %>
24 |
25 | <%= ff.text_field :with, class: "input" %>
26 |
27 |
28 |
29 |
30 | <%= ff.label :message %>
31 |
32 | <%= ff.text_field :message, class: "input" %>
33 |
34 |
35 | <% end %>
36 |
37 |
38 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_inclusion.html.erb:
--------------------------------------------------------------------------------
1 | Inclusion
2 |
3 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_length.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_length unless validations.length %>
2 | <% length = validations.length %>
3 |
4 | Length
5 |
6 | <%= f.fields_for :length, length do |ff| %>
7 | <% if length.errors.any? %>
8 |
9 |
14 |
15 | <% length.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 | <%= ff.label :minimum %>
24 |
25 | <%= ff.number_field :minimum, min: 0, step: 1, class: 'input' %>
26 |
27 |
28 |
29 |
30 | <%= ff.label :maximum %>
31 |
32 | <%= ff.number_field :maximum, min: 0, step: 1, class: 'input' %>
33 |
34 |
35 |
36 |
37 | <%= ff.label :is %>
38 |
39 | <%= ff.number_field :is, min: 0, step: 1, class: 'input' %>
40 |
41 |
42 | <% end %>
43 |
44 |
45 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_numericality.html.erb:
--------------------------------------------------------------------------------
1 | <% validations.build_numericality unless validations.numericality %>
2 | <% numericality = validations.numericality %>
3 |
4 | Numericality
5 |
6 | <%= f.fields_for :numericality, numericality do |ff| %>
7 | <% if numericality.errors.any? %>
8 |
9 |
14 |
15 | <% numericality.errors.full_messages.each do |message| %>
16 |
<%= message %>
17 | <% end %>
18 |
19 |
20 | <% end %>
21 |
22 |
23 |
24 |
25 | <%= ff.select :lower_bound_check, options_for_enum_select(numericality.class, :lower_bound_check, numericality.lower_bound_check), {}, class: "select" %>
26 |
27 |
28 |
29 | <%= ff.number_field :lower_bound_value, step: 0.01, class: "input" %>
30 |
31 |
32 |
33 |
34 |
35 |
36 | <%= ff.select :upper_bound_check, options_for_enum_select(numericality.class, :upper_bound_check, numericality.upper_bound_check), {}, class: "select" %>
37 |
38 |
39 |
40 | <%= ff.number_field :upper_bound_value, step: 0.01, class: "input" %>
41 |
42 |
43 | <% end %>
44 |
45 |
46 |
--------------------------------------------------------------------------------
/test/dummy/app/views/_form_core/validations/_presence.html.erb:
--------------------------------------------------------------------------------
1 | Presence
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy/app/views/dictionaries/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: dictionary, local: true) do |f| %>
2 | <% if dictionary.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% dictionary.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :scope, class: 'label' %>
21 |
22 | <%= f.text_field :scope, class: 'input', required: true %>
23 |
24 |
25 | The value must follow the pattern <%= Dictionary::SCOPE_REGEX.source %>
.
26 |
27 |
28 |
29 |
30 | <%= f.label :value, class: 'label' %>
31 |
32 | <%= f.text_field :value, class: 'input', required: true %>
33 |
34 |
35 |
36 |
37 |
38 | <%= f.submit class: 'button is-primary' %>
39 |
40 |
41 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
42 |
43 |
44 | <% end %>
45 |
--------------------------------------------------------------------------------
/test/dummy/app/views/dictionaries/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing dictionary
4 | <%= render 'form', dictionary: @dictionary %>
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/dictionaries/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to 'New', new_dictionary_path, class: 'button is-primary' %>
5 |
6 |
7 |
8 |
9 | Id |
10 | Scope |
11 | Value |
12 | |
13 |
14 |
15 |
16 | <% @dictionaries.each do |dictionary| %>
17 |
18 |
19 | <%= dictionary.id %>
20 | |
21 |
22 | <%= dictionary.scope %>
23 | |
24 |
25 | <%= dictionary.value %>
26 | |
27 |
28 | <%= link_to 'Edit', edit_dictionary_path(dictionary) %> |
29 | <%= link_to 'Destroy', dictionary, method: :delete, data: { confirm: 'Are you sure?' } %>
30 | |
31 |
32 | <% end %>
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/test/dummy/app/views/dictionaries/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New dictionary
4 | <%= render 'form', dictionary: @dictionary %>
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/choices/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: [field.becomes(Field), choice], local: true) do |f| %>
2 | <% if choice.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% choice.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :label, class: 'label' %>
21 |
22 | <%= f.text_field :label, class: 'input' %>
23 |
24 |
25 |
26 |
27 |
28 | <%= f.submit class: 'button is-primary' %>
29 |
30 |
31 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
32 |
33 |
34 | <% end %>
35 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/choices/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing choice
4 | <%= render "form", field: @field, choice: @choice %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/choices/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New choice", new_field_choice_path(@field), class: "button is-primary" %>
5 | <%= link_to "Back", fields_path, class: "button is-link" %>
6 |
7 |
8 |
9 |
10 | Label |
11 | |
12 |
13 |
14 |
15 | <% @field.choices.each do |choice| %>
16 |
17 | <%= choice.label %> |
18 |
19 | <%= link_to "Edit", edit_field_choice_path(@field, choice) %> |
20 | <%= link_to "Destroy", field_choice_path(@field, choice), method: :delete, data: {confirm: "Are you sure?"} %>
21 | |
22 |
23 | <% end %>
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/choices/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New choice
4 | <%= render "form", field: @field, choice: @choice %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/data_source_options/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: options, scope: :options, url: field_data_source_options_path(field), method: :patch, local: true) do |f| %>
2 | <% if options.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% options.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <%= render "_form_core/data_source_options/#{options.type_key}", f: f %>
20 |
21 |
22 |
23 | <%= f.submit "Update", class: 'button is-primary' %>
24 |
25 |
26 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
27 |
28 |
29 | <% end %>
30 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/data_source_options/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing data source options
4 | <%= render "form", field: @field, options: @options %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/options/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: options, scope: :options, url: field_options_path(field), method: :patch, local: true) do |f| %>
2 | <% if options.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% options.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <%= render "_form_core/field_options/#{field.type_key}", f: f, options: options %>
20 |
21 |
22 |
23 | <%= f.submit "Update", class: 'button is-primary' %>
24 |
25 |
26 | <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
27 |
28 |
29 | <% end %>
30 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/options/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing options
4 | <%= render "form", field: @field, options: @options %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/validations/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: validations, scope: :validations, url: field_validations_path(field), method: :patch, local: true) do |f| %>
2 | <% if validations.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% validations.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 | <% validations.class.attribute_names.each do |attribute_name| %>
20 | <%= render "_form_core/validations/#{attribute_name}", f: f, validations: validations %>
21 | <% end %>
22 | <% validations.class.reflections.keys.each do |attribute_name| %>
23 | <%= render "_form_core/validations/#{attribute_name}", f: f, validations: validations %>
24 | <% end %>
25 |
26 |
27 |
28 | <%= f.submit "Update", class: "button is-primary" %>
29 |
30 |
31 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
32 |
33 |
34 | <% end %>
35 |
--------------------------------------------------------------------------------
/test/dummy/app/views/fields/validations/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing validations
4 | <%= render "form", field: @field, validations: @validations %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: form, local: true) do |f| %>
2 | <% if form.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% form.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :title, class: "label" %>
21 |
22 | <%= f.text_field :title, class: "input", placeholder: "Title" %>
23 |
24 |
25 |
26 |
27 | <%= f.label :description, class: "label" %>
28 |
29 | <%= f.text_area :description, class: "textarea", placeholder: "Description" %>
30 |
31 |
32 |
33 |
34 |
35 | <%= f.submit class: "button is-primary" %>
36 |
37 |
38 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
39 |
40 |
41 | <% end %>
42 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing form
4 | <%= render "form", form: @form %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/fields/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing field
4 | <%= render "form", form: @form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/fields/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New field
4 | <%= render "form", form: @form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New Form", new_form_path, class: "button is-primary" %>
5 | <%= link_to "Generate form", random_forms_path(@form), method: :post, class: "button is-link" %>
6 |
7 |
8 |
9 |
10 | Title |
11 | Description |
12 | Updated at |
13 | |
14 |
15 |
16 |
17 | <% @forms.each do |form| %>
18 |
19 | <%= form.title %> |
20 | <%= form.description %> |
21 | <%= form.updated_at %> |
22 |
23 | <%= link_to "Show", form_fields_path(form) %> |
24 | <%= link_to "Edit", edit_form_path(form) %> |
25 | <%= link_to "Destroy", form, method: :delete, data: { confirm: "Are you sure?" } %>
26 | |
27 |
28 | <% end %>
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/loads/create.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render "_form_core/render/form",
4 | form: @form, instance: @instance,
5 | options: {scope: :preview, url: form_preview_path(@form), local: true} %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/loads/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= form_with url: form_load_path(@form), method: :post, local: true do |f| %>
4 |
5 |
6 | <%= f.text_area :serialized, class: "textarea", rows: 20 %>
7 |
8 |
9 |
10 |
11 |
12 | <%= f.submit "Load from YAML", class: "button is-primary" %>
13 |
14 |
15 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
16 |
17 |
18 | <% end %>
19 |
20 |
21 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New form
4 | <%= render "form", form: @form %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/previews/create.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= render "_form_core/preview/form", form: @form, instance: @instance %>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Serialized result
12 |
13 | You can copy the YAML and paste into <%= link_to 'load page', form_load_path(@form) %> to validate deserialization.
14 |
15 |
16 |
17 |
18 | <%= @instance.dump.gsub("\n", "
").gsub(" ", " ").html_safe %>
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/previews/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= render "_form_core/render/form",
4 | form: @form, instance: @instance,
5 | options: {scope: :preview, url: form_preview_path(@form), local: true} %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/sections/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_with(model: [form, section], local: true) do |f| %>
2 | <% if section.errors.any? %>
3 |
4 |
9 |
10 |
11 | <% section.errors.full_messages.each do |message| %>
12 | - <%= message %>
13 | <% end %>
14 |
15 |
16 |
17 | <% end %>
18 |
19 |
20 | <%= f.label :title, class: "label" %>
21 |
22 | <%= f.text_field :title, class: "input", placeholder: "Title" %>
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 | <%= f.submit class: "button is-primary" %>
38 |
39 |
40 | <%= link_to "Back", url_for(:back), class: "button is-link" %>
41 |
42 |
43 | <% end %>
44 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/sections/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing section
4 | <%= render "form", form: @form, section: @section %>
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/sections/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= link_to "New Section", new_form_section_path(@form), class: "button is-primary" %>
5 |
6 |
7 |
8 |
9 | Title |
10 | |
11 |
12 |
13 |
14 | <% @sections.each do |section| %>
15 |
16 | <%= section.title %> |
17 |
18 | <%= link_to "Edit", edit_form_section_path(@form, section) %> |
19 | <%= link_to "Destroy", [@form, section], method: :delete, data: {confirm: "Are you sure?" } %>
20 | |
21 |
22 | <% end %>
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test/dummy/app/views/forms/sections/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New section
4 | <%= render "form", form: @form, section: @section %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_alert.html.erb:
--------------------------------------------------------------------------------
1 | <% return if alert.blank? %>
2 |
5 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_nav.html.erb:
--------------------------------------------------------------------------------
1 |
34 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/_notice.html.erb:
--------------------------------------------------------------------------------
1 | <% return if notice.blank? %>
2 |
5 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Form Core
5 |
6 | <%= csrf_meta_tags %>
7 |
8 |
9 |
10 |
11 | <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
12 | <%= javascript_include_tag "application", "data-turbolinks-track": "reload" %>
13 |
14 |
15 | <%= render "layouts/notice" %>
16 | <%= render "layouts/alert" %>
17 | <%= render "layouts/nav" %>
18 |
19 |
20 | <%= content_for?(:content) ? yield(:content) : yield %>
21 |
22 |
23 | <%= render "layouts/footer" %>
24 |
25 |
26 |
--------------------------------------------------------------------------------
/test/dummy/app/views/layouts/forms.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :content do %>
2 |
3 |
4 |
5 |
6 | <%= @form.title %>
7 |
8 |
9 | <%= @form.description %>
10 |
11 |
12 |
13 |
14 |
34 |
35 |
36 | <%= yield %>
37 | <% end %>
38 |
39 | <%= render template: "layouts/application" %>
40 |
--------------------------------------------------------------------------------
/test/dummy/app/views/nested_forms/fields/edit.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Editing field
4 | <%= render "form", form: @nested_form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/app/views/nested_forms/fields/new.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
New field
4 | <%= render "form", form: @nested_form, field: @field %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | APP_PATH = File.expand_path("../config/application", __dir__)
5 | require_relative "../config/boot"
6 | require "rails/commands"
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require_relative "../config/boot"
5 | require "rake"
6 | Rake.application.run
7 |
--------------------------------------------------------------------------------
/test/dummy/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "pathname"
5 | require "fileutils"
6 | include FileUtils
7 |
8 | # path to your application root.
9 | APP_ROOT = Pathname.new File.expand_path("../../", __FILE__)
10 |
11 | def system!(*args)
12 | system(*args) || abort("\n== Command #{args} failed ==")
13 | end
14 |
15 | chdir APP_ROOT do
16 | # This script is a starting point to setup your application.
17 | # Add necessary setup steps to this file.
18 |
19 | puts "== Installing dependencies =="
20 | system! "gem install bundler --conservative"
21 | system("bundle check") || system!("bundle install")
22 |
23 | # Install JavaScript dependencies if using Yarn
24 | system("bin/yarn")
25 |
26 | # puts "\n== Copying sample files =="
27 | # unless File.exist?('config/database.yml')
28 | # cp 'config/database.yml.sample', 'config/database.yml'
29 | # end
30 |
31 | puts "\n== Preparing database =="
32 | system! "bin/rails db:setup"
33 |
34 | puts "\n== Removing old logs and tempfiles =="
35 | system! "bin/rails log:clear tmp:clear"
36 |
37 | puts "\n== Restarting application server =="
38 | system! "bin/rails restart"
39 | end
40 |
--------------------------------------------------------------------------------
/test/dummy/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require "pathname"
5 | require "fileutils"
6 | include FileUtils
7 |
8 | # path to your application root.
9 | APP_ROOT = Pathname.new File.expand_path("../../", __FILE__)
10 |
11 | def system!(*args)
12 | system(*args) || abort("\n== Command #{args} failed ==")
13 | end
14 |
15 | chdir APP_ROOT do
16 | # This script is a way to update your development environment automatically.
17 | # Add necessary update steps to this file.
18 |
19 | puts "== Installing dependencies =="
20 | system! "gem install bundler --conservative"
21 | system("bundle check") || system!("bundle install")
22 |
23 | puts "\n== Updating database =="
24 | system! "bin/rails db:migrate"
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! "bin/rails log:clear tmp:clear"
28 |
29 | puts "\n== Restarting application server =="
30 | system! "bin/rails restart"
31 | end
32 |
--------------------------------------------------------------------------------
/test/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This file is used by Rack-based servers to start the application.
4 |
5 | require_relative "config/environment"
6 |
7 | run Rails.application
8 |
--------------------------------------------------------------------------------
/test/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "boot"
4 |
5 | require "rails"
6 | # Pick the frameworks you want:
7 | require "active_model/railtie"
8 | # require "active_job/railtie"
9 | require "active_record/railtie"
10 | require "active_storage/engine"
11 | require "action_controller/railtie"
12 | # require "action_mailer/railtie"
13 | require "action_view/railtie"
14 | # require "action_cable/engine"
15 | require "sprockets/railtie"
16 | require "rails/test_unit/railtie"
17 |
18 | Bundler.require(*Rails.groups)
19 | require "form_core"
20 |
21 | Dir[Pathname.new(File.dirname(__FILE__)).realpath.parent.join("lib", "monkey_patches", "*.rb")].map do |file|
22 | require file
23 | end
24 |
25 | module Dummy
26 | class Application < Rails::Application
27 | # Initialize configuration defaults for originally generated Rails version.
28 | config.load_defaults 7.0
29 |
30 | # Settings in config/environments/* take precedence over those specified here.
31 | # Application configuration should go into files in config/initializers
32 | # -- all .rb files in that directory are automatically loaded.
33 |
34 | Rails.autoloaders.main.ignore(Rails.root.join("app", "overrides").to_s)
35 |
36 | config.to_prepare do
37 | Dir.glob(Rails.root + "app/overrides/**/*_override*.rb").each do |c|
38 | require(c)
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/test/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Set up gems listed in the Gemfile.
4 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
5 |
6 | require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
7 | $LOAD_PATH.unshift File.expand_path("../../../lib", __dir__)
8 |
--------------------------------------------------------------------------------
/test/dummy/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: redis://localhost:6379/1
10 | channel_prefix: dummy_production
11 |
--------------------------------------------------------------------------------
/test/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/test/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Load the Rails application.
4 | require_relative "application"
5 |
6 | # Initialize the Rails application.
7 | Rails.application.initialize!
8 |
--------------------------------------------------------------------------------
/test/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # The test environment is used exclusively to run your application's
7 | # test suite. You never need to work with it otherwise. Remember that
8 | # your test database is "scratch space" for the test suite and is wiped
9 | # and recreated between test runs. Don't rely on the data there!
10 | config.cache_classes = true
11 |
12 | # Do not eager load code on boot. This avoids loading your whole application
13 | # just for the purpose of running a single test. If you are using a tool that
14 | # preloads Rails for running tests, you may have to set it to true.
15 | config.eager_load = false
16 |
17 | # Configure public file server for tests with Cache-Control for performance.
18 | config.public_file_server.enabled = true
19 | config.public_file_server.headers = {
20 | "Cache-Control" => "public, max-age=#{1.hour.to_i}"
21 | }
22 |
23 | # Show full error reports and disable caching.
24 | config.consider_all_requests_local = true
25 | config.action_controller.perform_caching = false
26 |
27 | # Raise exceptions instead of rendering exception templates.
28 | config.action_dispatch.show_exceptions = false
29 |
30 | # Disable request forgery protection in test environment.
31 | config.action_controller.allow_forgery_protection = false
32 |
33 | # Store uploaded files on the local file system in a temporary directory
34 | config.active_storage.service = :test
35 |
36 | # Print deprecation notices to the stderr.
37 | config.active_support.deprecation = :stderr
38 |
39 | # Raises error for missing translations
40 | # config.action_view.raise_on_missing_translations = true
41 | end
42 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/actionview.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ActionView::Base.field_error_proc = proc do |html_tag, _instance|
4 | if /<(input|label|textarea|select)/.match?(html_tag)
5 | html_field = Nokogiri::HTML::DocumentFragment.parse(html_tag)
6 | html_field.children.add_class "is-danger"
7 | html_field.to_s.html_safe
8 | else
9 | html_tag.html_safe
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # ApplicationController.renderer.defaults.merge!(
5 | # http_host: "example.org",
6 | # https: false
7 | # )
8 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = "1.0"
5 |
6 | # Add additional assets to the asset load path.
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 | # Add Yarn node_modules folder to the asset load path.
9 | Rails.application.config.assets.paths << Rails.root.join("node_modules")
10 |
11 | # Precompile additional assets.
12 | # application.js, application.css, and all non-JS/CSS in the app/assets
13 | # folder are already added.
14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
15 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
6 |
7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
8 | # Rails.backtrace_cleaner.remove_silencers!
9 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Define an application-wide content security policy
6 | # For further information see the following documentation
7 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
8 |
9 | # Rails.application.config.content_security_policy do |policy|
10 | # policy.default_src :self, :https
11 | # policy.font_src :self, :https, :data
12 | # policy.img_src :self, :https, :data
13 | # policy.object_src :none
14 | # policy.script_src :self, :https
15 | # policy.style_src :self, :https
16 |
17 | # # Specify URI for violation reports
18 | # # policy.report_uri "/csp-violation-report-endpoint"
19 | # end
20 |
21 | # If you are using UJS then enable automatic nonce generation
22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
23 |
24 | # Report CSP violations to a specified URI
25 | # For further information see the following documentation:
26 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
27 | # Rails.application.config.content_security_policy_report_only = true
28 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Specify a serializer for the signed and encrypted cookie jars.
6 | # Valid fields are :json, :marshal, and :hybrid.
7 | Rails.application.config.action_dispatch.cookies_serializer = :json
8 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Configure sensitive parameters which will be filtered from the log file.
6 | Rails.application.config.filter_parameters += [:password]
7 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/form_core.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.configuration.to_prepare do
4 | FormCore.virtual_model_class = ::VirtualModel
5 | FormCore.virtual_model_coder_class = FormCore::YAMLCoder
6 |
7 | FormCore::YAMLCoder.safe_mode = true
8 | FormCore::YAMLCoder.whitelist_classes.concat [BigDecimal, Date, Time]
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Add new inflection rules using the following format. Inflections
5 | # are locale specific, and you may define rules for as many different
6 | # locales as you wish. All of these examples are active by default:
7 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
8 | # inflect.plural /^(ox)$/i, '\1en'
9 | # inflect.singular /^(ox)en/i, '\1'
10 | # inflect.irregular "person", "people"
11 | # inflect.uncountable %w( fish sheep )
12 | # end
13 |
14 | # These inflection rules are supported but not enabled by default:
15 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
16 | # inflect.acronym "RESTful"
17 | # end
18 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Add new mime types for use in respond_to blocks:
5 | # Mime::Type.register "text/richtext", :rtf
6 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/validates_timeliness.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ValidatesTimeliness.setup do |config|
4 | # Extend ORM/ODMs for full support (:active_record included).
5 | config.extend_orms = [:active_record]
6 | #
7 | # Default timezone
8 | # config.default_timezone = :utc
9 | #
10 | # Set the dummy date part for a time type values.
11 | # config.dummy_date_for_time_type = [ 2000, 1, 1 ]
12 | #
13 | # Ignore errors when restriction options are evaluated
14 | # config.ignore_restriction_errors = false
15 | #
16 | # Re-display invalid values in date/time selects
17 | # config.enable_date_time_select_extension!
18 | #
19 | # Handle multiparameter date/time values strictly
20 | # config.enable_multiparameter_extension!
21 | #
22 | # Shorthand date and time symbols for restrictions
23 | # config.restriction_shorthand_symbols.update(
24 | # :now => lambda { Time.current },
25 | # :today => lambda { Date.current }
26 | # )
27 | #
28 | # Use the plugin date/time parser which is stricter and extendable
29 | # config.use_plugin_parser = false
30 | #
31 | # Add one or more formats making them valid. e.g. add_formats(:date, 'd(st|rd|th) of mmm, yyyy')
32 | # config.parser.add_formats()
33 | #
34 | # Remove one or more formats making them invalid. e.g. remove_formats(:date, 'dd/mm/yyy')
35 | # config.parser.remove_formats()
36 | #
37 | # Change the ambiguous year threshold when parsing a 2 digit year
38 | # config.parser.ambiguous_year_threshold = 30
39 | #
40 | # Treat ambiguous dates, such as 01/02/1950, as a Non-US date.
41 | # config.parser.remove_us_formats
42 | end
43 |
--------------------------------------------------------------------------------
/test/dummy/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # This file contains settings for ActionController::ParamsWrapper which
6 | # is enabled by default.
7 |
8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
9 | ActiveSupport.on_load(:action_controller) do
10 | wrap_parameters format: [:json]
11 | end
12 |
13 | # To enable root element in JSON for ActiveRecord objects.
14 | # ActiveSupport.on_load(:active_record) do
15 | # self.include_root_in_json = true
16 | # end
17 |
--------------------------------------------------------------------------------
/test/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | defaults:
34 | section:
35 | title: Default
36 | values:
37 | 'true': 'Yes'
38 | 'false': 'No'
39 |
--------------------------------------------------------------------------------
/test/dummy/config/locales/validates_timeliness.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | errors:
3 | messages:
4 | invalid_date: "is not a valid date"
5 | invalid_time: "is not a valid time"
6 | invalid_datetime: "is not a valid datetime"
7 | is_at: "must be at %{restriction}"
8 | before: "must be before %{restriction}"
9 | on_or_before: "must be on or before %{restriction}"
10 | after: "must be after %{restriction}"
11 | on_or_after: "must be on or after %{restriction}"
12 | validates_timeliness:
13 | error_value_formats:
14 | date: '%Y-%m-%d'
15 | time: '%H:%M:%S'
16 | datetime: '%Y-%m-%d %H:%M:%S'
17 |
--------------------------------------------------------------------------------
/test/dummy/config/puma.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Puma can serve each request in a thread from an internal thread pool.
4 | # The `threads` method setting takes two numbers: a minimum and maximum.
5 | # Any libraries that use thread pools should be configured to match
6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
7 | # and maximum; this matches the default thread size of Active Record.
8 | #
9 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
10 | threads threads_count, threads_count
11 |
12 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
13 | #
14 | port ENV.fetch("PORT") { 3000 }
15 |
16 | # Specifies the `environment` that Puma will run in.
17 | #
18 | environment ENV.fetch("RAILS_ENV") { "development" }
19 |
20 | # Specifies the number of `workers` to boot in clustered mode.
21 | # Workers are forked webserver processes. If using threads and workers together
22 | # the concurrency of the application would be max `threads` * `workers`.
23 | # Workers do not work on JRuby or Windows (both of which do not support
24 | # processes).
25 | #
26 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
27 |
28 | # Use the `preload_app!` method when specifying a `workers` number.
29 | # This directive tells Puma to first boot the application and load code
30 | # before forking the application. This takes advantage of Copy On Write
31 | # process behavior so workers use less memory.
32 | #
33 | # preload_app!
34 |
35 | # Allow puma to be restarted by `rails restart` command.
36 | plugin :tmp_restart
37 |
--------------------------------------------------------------------------------
/test/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.routes.draw do
4 | resources :dictionaries, except: %i[show]
5 |
6 | resources :forms, except: %i[show] do
7 | collection do
8 | post "random"
9 | end
10 |
11 | scope module: :forms do
12 | resource :preview, only: %i[show create]
13 | resource :load, only: %i[show create]
14 | resources :sections, except: %i[show]
15 | resources :fields, except: %i[show]
16 | end
17 | end
18 |
19 | resources :fields, only: %i[] do
20 | scope module: :fields do
21 | resource :validations, only: %i[edit update]
22 | resource :options, only: %i[edit update]
23 | resource :data_source_options, only: %i[edit update]
24 | resources :choices, except: %i[show]
25 | end
26 | end
27 |
28 | resources :nested_forms, only: %i[] do
29 | scope module: :nested_forms do
30 | resources :fields, except: %i[show]
31 | end
32 | end
33 |
34 | root to: "forms#index"
35 |
36 | resource :time_zone, only: [:update]
37 | end
38 |
--------------------------------------------------------------------------------
/test/dummy/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rails secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | # Shared secrets are available across all environments.
14 |
15 | # shared:
16 | # api_key: a1B2c3D4e5F6
17 |
18 | # Environmental secrets are only available for that specific environment.
19 |
20 | development:
21 | secret_key_base: aacd284148dbbd47e20f36637c777a3537a02b671c16ef6c7516409f776821a7c5bd938c4c4a948b4dbc3953163a6b74da2b6bce97d4f264f64190df0600571d
22 |
23 | test:
24 | secret_key_base: ddc01f0a4c5c2b000a0e14fa7385f972e1a48f8bdb524fc7d14b2c839ff9c403fb1a43078b07fa47600ab3672d378ce59310591fd79879a81f4db385b44a38d8
25 |
26 | # Do not keep production secrets in the unencrypted secrets file.
27 | # Instead, either read values from the environment.
28 | # Or, use `bin/rails secrets:setup` to configure encrypted secrets
29 | # and move the `production:` environment over there.
30 |
31 | production:
32 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
33 |
--------------------------------------------------------------------------------
/test/dummy/config/spring.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | %w[
4 | .ruby-version
5 | .rbenv-vars
6 | tmp/restart.txt
7 | tmp/caching-dev.txt
8 | ].each { |path| Spring.watch(path) }
9 |
--------------------------------------------------------------------------------
/test/dummy/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20170504211819_add_columns_to_forms.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToForms < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :forms do |t|
6 | t.string :title, default: ""
7 | t.text :description, default: ""
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20170504214301_create_sections.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateSections < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :sections do |t|
6 | t.string :title, default: ""
7 | t.boolean :headless, null: false, default: false
8 | t.references :form, foreign_key: true
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20170504225506_add_columns_to_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddColumnsToFields < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :fields do |t|
6 | t.string :label, default: ""
7 | t.string :hint, default: ""
8 | t.references :section, foreign_key: true
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20170515212355_create_dictionaries.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateDictionaries < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :dictionaries do |t|
6 | t.string :value, null: false, default: "", index: true
7 | t.string :scope, null: false, default: "", index: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20170613184106_add_attachable_to_forms.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddAttachableToForms < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :forms do |t|
6 | t.references :attachable, polymorphic: true, index: true
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180120200440_add_position_to_fields.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddPositionToFields < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :fields do |t|
6 | t.integer :position
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180120201200_add_position_to_sections.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddPositionToSections < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :sections do |t|
6 | t.integer :position
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180220232604_create_choices.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateChoices < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :choices do |t|
6 | t.text :label, null: false
7 | t.references :field, foreign_key: true
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20180228201120_add_position_to_choices.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddPositionToChoices < ActiveRecord::Migration[6.0]
4 | def change
5 | change_table :choices do |t|
6 | t.integer :position
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/dummy/db/migrate/20210108214331_create_active_storage_tables.active_storage.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This migration comes from active_storage (originally 20170806125915)
4 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
5 | def change
6 | create_table :active_storage_blobs do |t|
7 | t.string :key, null: false
8 | t.string :filename, null: false
9 | t.string :content_type
10 | t.text :metadata
11 | t.string :service_name, null: false
12 | t.bigint :byte_size, null: false
13 | t.string :checksum, null: false
14 | t.datetime :created_at, null: false
15 |
16 | t.index [ :key ], unique: true
17 | end
18 |
19 | create_table :active_storage_attachments do |t|
20 | t.string :name, null: false
21 | t.references :record, null: false, polymorphic: true, index: false
22 | t.references :blob, null: false
23 |
24 | t.datetime :created_at, null: false
25 |
26 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
27 | t.foreign_key :active_storage_blobs, column: :blob_id
28 | end
29 |
30 | create_table :active_storage_variant_records do |t|
31 | t.belongs_to :blob, null: false, index: false
32 | t.string :variation_digest, null: false
33 |
34 | t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
35 | t.foreign_key :active_storage_blobs, column: :blob_id
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/test/dummy/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/lib/assets/.keep
--------------------------------------------------------------------------------
/test/dummy/lib/monkey_patches/active_support.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "active_support/concern+prependable"
4 |
--------------------------------------------------------------------------------
/test/dummy/lib/monkey_patches/active_support/concern+prependable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Cheated from https://gitlab.com/gitlab-org/gitlab-ee/blob/master/config/initializers/0_as_concern.rb
4 | # This module is based on: https://gist.github.com/bcardarella/5735987
5 |
6 | module Prependable
7 | def prepend_features(base)
8 | if base.instance_variable_defined?(:@_dependencies)
9 | base.instance_variable_get(:@_dependencies) << self
10 | false
11 | else
12 | return false if base < self
13 |
14 | super
15 | base.singleton_class.send(:prepend, const_get("ClassMethods")) if const_defined?(:ClassMethods)
16 | @_dependencies.each { |dep| base.send(:prepend, dep) }
17 | base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
18 | end
19 | end
20 | end
21 |
22 | module ActiveSupport
23 | module Concern
24 | prepend Prependable
25 |
26 | alias prepended included
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/test/dummy/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/log/.keep
--------------------------------------------------------------------------------
/test/dummy/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/test/dummy/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/test/dummy/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/test/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/public/favicon.ico
--------------------------------------------------------------------------------
/test/dummy/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/storage/.keep
--------------------------------------------------------------------------------
/test/dummy/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
6 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
7 | end
8 |
--------------------------------------------------------------------------------
/test/dummy/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/test/controllers/.keep
--------------------------------------------------------------------------------
/test/dummy/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/dummy/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/test/models/.keep
--------------------------------------------------------------------------------
/test/dummy/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rails-engine/form_core/b7fca1b1a184700adf9801c57dcd4dfeef5bc586/test/dummy/test/system/.keep
--------------------------------------------------------------------------------
/test/fixtures/form_core/fields.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | name: MyString
5 | label: MyString
6 | hint: MyString
7 | prompt: MyString
8 | accessibility: 0
9 | validations:
10 | options:
11 | section: one
12 |
13 | two:
14 | name: MyString
15 | label: MyString
16 | hint: MyString
17 | prompt: MyString
18 | accessibility: 0
19 | validations:
20 | options:
21 | section: two
22 |
--------------------------------------------------------------------------------
/test/fixtures/form_core/forms.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | title: MyString
5 | description: MyText
6 |
7 | two:
8 | title: MyString
9 | description: MyText
10 |
--------------------------------------------------------------------------------
/test/form_core_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | class FormCore::Test < ActiveSupport::TestCase
6 | test "truth" do
7 | assert_kind_of Module, FormCore
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/integration/navigation_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | class NavigationTest < ActionDispatch::IntegrationTest
6 | # test "the truth" do
7 | # assert true
8 | # end
9 | end
10 |
--------------------------------------------------------------------------------
/test/models/form_core/field_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | module FormCore
6 | class FieldTest < ActiveSupport::TestCase
7 | # test "the truth" do
8 | # assert true
9 | # end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/models/form_core/form_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | module FormCore
6 | class FormTest < ActiveSupport::TestCase
7 | # test "the truth" do
8 | # assert true
9 | # end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require File.expand_path("../test/dummy/config/environment.rb", __dir__)
4 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
5 | ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__)
6 | require "rails/test_help"
7 |
8 | # Filter out Minitest backtrace while allowing backtrace from other libraries
9 | # to be shown.
10 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new
11 |
12 | # Load fixtures from the engine
13 | if ActiveSupport::TestCase.respond_to?(:fixture_path=)
14 | ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__)
15 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
16 | ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
17 | ActiveSupport::TestCase.fixtures :all
18 | end
19 |
--------------------------------------------------------------------------------