├── .circleci
└── DISABLED__config.yml
├── .github
├── FUNDING.yml
└── workflows
│ └── test_suite.yml
├── .gitignore
├── .ruby-version
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── README2.md
├── app
├── assets
│ └── config
│ │ └── manifest.js
├── helpers
│ ├── hot_glue
│ │ └── controller_helper.rb
│ └── hot_glue_helper.rb
└── views
│ └── layouts
│ └── _flash_notices.erb
├── config
├── database.yml
└── hot_glue.yml
├── db
└── schema.rb
├── dummy
├── .gitattributes
├── .gitignore
├── .rspec
├── .ruby-version
├── Gemfile
├── README.md
├── Rakefile
├── app
│ ├── assets
│ │ ├── config
│ │ │ └── manifest.js
│ │ ├── images
│ │ │ └── .keep
│ │ └── stylesheets
│ │ │ └── application.css
│ ├── channels
│ │ └── application_cable
│ │ │ ├── channel.rb
│ │ │ └── connection.rb
│ ├── controllers
│ │ ├── application_controller.rb
│ │ └── welcome_controller.rb
│ ├── helpers
│ │ └── application_helper.rb
│ ├── javascript
│ │ └── application.js
│ ├── jobs
│ │ └── application_job.rb
│ ├── mailers
│ │ └── application_mailer.rb
│ ├── models
│ │ ├── abc.rb
│ │ ├── application_record.rb
│ │ ├── appointment.rb
│ │ ├── atw_display_name.rb
│ │ ├── atw_full_name.rb
│ │ ├── atw_to_label.rb
│ │ ├── borked.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ ├── dfg.rb
│ │ ├── family.rb
│ │ ├── fruits
│ │ │ └── cantelope.rb
│ │ ├── ghi.rb
│ │ ├── hgi.rb
│ │ ├── human.rb
│ │ ├── jkl.rb
│ │ ├── missing_label_table.rb
│ │ ├── nothing.rb
│ │ ├── pet.rb
│ │ ├── user.rb
│ │ ├── visit.rb
│ │ └── xyz.rb
│ └── views
│ │ ├── devise
│ │ ├── confirmations
│ │ │ └── new.html.erb
│ │ ├── mailer
│ │ │ ├── confirmation_instructions.html.erb
│ │ │ ├── email_changed.html.erb
│ │ │ ├── password_change.html.erb
│ │ │ ├── reset_password_instructions.html.erb
│ │ │ └── unlock_instructions.html.erb
│ │ ├── passwords
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.erb
│ │ ├── registrations
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.erb
│ │ ├── sessions
│ │ │ └── new.html.erb
│ │ ├── shared
│ │ │ ├── _error_messages.html.erb
│ │ │ └── _links.html.erb
│ │ └── unlocks
│ │ │ └── new.html.erb
│ │ ├── layouts
│ │ ├── _flash_notices.erb
│ │ └── application.html.erb
│ │ └── welcome
│ │ └── index.erb
├── bin
│ ├── bundle
│ ├── importmap
│ ├── rails
│ ├── rake
│ └── setup
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── credentials.yml.enc
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── hot_glue.yml
│ ├── importmap.rb
│ ├── initializers
│ │ ├── assets.rb
│ │ ├── content_security_policy.rb
│ │ ├── devise.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ └── permissions_policy.rb
│ ├── locales
│ │ ├── devise.en.yml
│ │ └── en.yml
│ ├── puma.rb
│ ├── routes.rb
│ └── storage.yml
├── db
│ ├── migrate
│ │ ├── 20210306223300_create_dfgs.rb
│ │ ├── 20210306223305_create_ghis.rb
│ │ ├── 20210306223309_create_jkls.rb
│ │ ├── 20210306223701_devise_create_users.rb
│ │ ├── 20210306225506_create_xyzs.rb
│ │ ├── 20211226155351_create_abcs.rb
│ │ ├── 20211226165050_create_hgis.rb
│ │ ├── 20220201164536_add_cantelope_id_to_dfgs.rb
│ │ ├── 20220201165048_create_cantelopes.rb
│ │ ├── 20220318093158_create_pets.rb
│ │ ├── 20220318093211_create_human.rb
│ │ ├── 20220318093221_create_appointments.rb
│ │ ├── 20220320194207_create_atw_to_labels.rb
│ │ ├── 20220320200217_create_atw_full_names.rb
│ │ ├── 20220320200230_create_atw_display_names.rb
│ │ ├── 20220320214017_create_borkeds.rb
│ │ ├── 20220320223316_create_missing_label_tables.rb
│ │ ├── 20220323000346_create_families.rb
│ │ ├── 20220323000410_create_visits.rb
│ │ └── 20230317162618_create_active_storage_tables.active_storage.rb
│ ├── schema.rb
│ └── seeds.rb
├── lib
│ ├── assets
│ │ └── .keep
│ └── tasks
│ │ └── .keep
├── log
│ └── .keep
├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── apple-touch-icon-precomposed.png
│ ├── apple-touch-icon.png
│ ├── favicon.ico
│ └── robots.txt
├── spec
│ ├── factories
│ │ ├── abc_factory.rb
│ │ ├── cantelope_factory.rb
│ │ ├── dfg_factory.rb
│ │ ├── family_factory.rb
│ │ ├── ghi_factory.rb
│ │ ├── hgi_factory.rb
│ │ ├── human_factory.rb
│ │ ├── jkl_factory.rb
│ │ ├── pet_factory.rb
│ │ ├── user_factory.rb
│ │ └── xyz_factory.rb
│ ├── files
│ │ └── computer_code.jpg
│ ├── rails_helper.rb
│ ├── spec_helper.rb
│ └── support
│ │ └── capybara_login.rb
├── storage
│ └── .keep
├── test
│ ├── application_system_test_case.rb
│ ├── channels
│ │ └── application_cable
│ │ │ └── connection_test.rb
│ ├── controllers
│ │ └── .keep
│ ├── fixtures
│ │ └── files
│ │ │ └── .keep
│ ├── helpers
│ │ └── .keep
│ ├── integration
│ │ └── .keep
│ ├── mailers
│ │ └── .keep
│ ├── models
│ │ └── .keep
│ ├── system
│ │ └── .keep
│ └── test_helper.rb
└── vendor
│ ├── .keep
│ └── javascript
│ └── .keep
├── hot_glue.gemspec
├── lib
├── generators
│ └── hot_glue
│ │ ├── default_config_loader.rb
│ │ ├── direct_upload_install_generator.rb
│ │ ├── dropzone_install_generator.rb
│ │ ├── field_factory.rb
│ │ ├── fields
│ │ ├── association_field.rb
│ │ ├── attachment_field.rb
│ │ ├── boolean_field.rb
│ │ ├── date_field.rb
│ │ ├── date_time_field.rb
│ │ ├── enum_field.rb
│ │ ├── field.rb
│ │ ├── float_field.rb
│ │ ├── integer_field.rb
│ │ ├── related_set_field.rb
│ │ ├── string_field.rb
│ │ ├── text_field.rb
│ │ ├── time_field.rb
│ │ └── uuid_field.rb
│ │ ├── flash_notices_install_generator.rb
│ │ ├── hot_glue.rb
│ │ ├── install_generator.rb
│ │ ├── layout
│ │ └── builder.rb
│ │ ├── layout_strategy
│ │ ├── base.rb
│ │ ├── bootstrap.rb
│ │ ├── hot_glue.rb
│ │ └── tailwind.rb
│ │ ├── markup_templates
│ │ ├── base.rb
│ │ └── erb.rb
│ │ ├── nav_template_generator.rb
│ │ ├── scaffold_generator.rb
│ │ ├── set_search_interface_install_generator.rb
│ │ ├── templates
│ │ ├── base_controller.rb.erb
│ │ ├── capybara_login.rb
│ │ ├── computer_code.jpg
│ │ ├── controller.rb.erb
│ │ ├── erb
│ │ │ ├── _edit.erb
│ │ │ ├── _flash_notices.erb
│ │ │ ├── _form.erb
│ │ │ ├── _line.erb
│ │ │ ├── _list.erb
│ │ │ ├── _nav.html.erb
│ │ │ ├── _new_button.erb
│ │ │ ├── _new_form.erb
│ │ │ ├── _show.erb
│ │ │ ├── create.turbo_stream.erb
│ │ │ ├── destroy.turbo_stream.erb
│ │ │ ├── edit.erb
│ │ │ ├── edit.turbo_stream.erb
│ │ │ ├── index.erb
│ │ │ ├── new.erb
│ │ │ └── update.turbo_stream.erb
│ │ ├── javascript
│ │ │ ├── date_range_picker_controller.js
│ │ │ ├── dropzone_controller.js
│ │ │ ├── search_form_controller.js
│ │ │ └── time_range_picker_controller.js
│ │ ├── system_spec.rb.erb
│ │ ├── themes
│ │ │ ├── hotglue_scaffold_dark_knight.scss
│ │ │ ├── hotglue_scaffold_like_bootstrap.scss
│ │ │ ├── hotglue_scaffold_like_los_gatos.scss
│ │ │ └── hotglue_scaffold_like_mountain_view.scss
│ │ ├── typeahead_controller.rb.erb
│ │ └── typeahead_views
│ │ │ ├── _thing.html.erb
│ │ │ ├── index.html.erb
│ │ │ ├── typeahead.scss
│ │ │ ├── typeahead_controller.js
│ │ │ └── typeahead_results_controller.js
│ │ ├── typeahead_generator.rb
│ │ └── typeahead_install_generator.rb
├── hot-glue.rb
└── hotglue
│ ├── engine.rb
│ └── version.rb
├── script
├── clean_generated_code
└── test
└── spec
├── dummy
├── app
│ ├── models
│ │ ├── abc.rb
│ │ └── dfg.rb
│ └── policies
│ │ └── dfg_policy.rb
├── config
│ └── hot_glue.yml
└── spec
│ ├── files
│ └── computer_code.jpg
│ └── support
│ └── capybara_login.rb
├── lib
├── generators
│ └── hot_glue
│ │ ├── direct_upload_install_generator_spec.rb
│ │ ├── dropzone_install_generator_spec.rb
│ │ ├── install_generator_spec.rb
│ │ ├── layout
│ │ └── builder_spec.rb
│ │ └── scaffold_generator_spec.rb
├── helpers
│ └── hot_glue_helper_spec.rb
├── hot_glue
│ ├── controller_helper_spec.rb
│ ├── field_factory_spec.rb
│ ├── hot_glue_spec.rb
│ ├── markup_templates
│ │ └── erb_spec.rb
│ └── version_spec.rb
└── hot_glue_spec.rb
├── rails_helper.rb
└── spec_helper.rb
/.circleci/DISABLED__config.yml:
--------------------------------------------------------------------------------
1 | # more about orbs: https://circleci.com/docs/2.0/using-orbs/
2 | version: 2.1
3 |
4 | orbs:
5 | ruby: circleci/ruby@1.0
6 | browser-tools: circleci/browser-tools@1.4.8
7 |
8 | jobs:
9 | build:
10 | docker:
11 | - image: cimg/ruby:3.2.2-browsers
12 | auth:
13 | username: mydockerhub-user
14 | password: $DOCKERHUB_PASSWORD
15 | - image: redis:6.2.6
16 |
17 | steps:
18 | - checkout
19 | - ruby/install-deps
20 | - run:
21 | name: Build assets
22 | command: bundle exec rails assets:precompile
23 |
24 | test:
25 | parallelism: 1
26 | docker:
27 | - image: cimg/ruby:3.2.2-browsers
28 | auth:
29 | username: mydockerhub-user
30 | password: $DOCKERHUB_PASSWORD
31 | - image: redis:6.2.6
32 | - image: cimg/postgres:13.7
33 | auth:
34 | username: mydockerhub-user
35 | password: $DOCKERHUB_PASSWORD
36 | environment:
37 | POSTGRES_USER: circleci-demo-ruby
38 | POSTGRES_DB: helios-dev-shop-test
39 | POSTGRES_PASSWORD: ""
40 |
41 | environment:
42 | BUNDLE_JOBS: "3"
43 | BUNDLE_RETRY: "3"
44 | PGHOST: 127.0.0.1
45 | PGUSER: circleci-demo-ruby
46 | PGPASSWORD: ""
47 | RAILS_ENV: test
48 |
49 | steps:
50 | - run: sudo apt-get update
51 |
52 | - browser-tools/install-chromedriver
53 | - checkout
54 | - ruby/install-deps
55 |
56 | - run:
57 | name: Wait for DB
58 | command: dockerize -wait tcp://localhost:5432 -timeout 1m
59 |
60 | - run:
61 | name: Run system tests
62 | command: script/test
63 |
64 | - run:
65 | name: Run internal tests
66 | command: bundle exec rspec
67 |
68 | workflows:
69 | version: 2
70 | build_and_test:
71 | jobs:
72 | - build
73 | - test:
74 | requires:
75 | - build
76 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ["https://twitter.com/HotGlueForRails", "https://school.jfbcodes.com/8188?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
2 |
--------------------------------------------------------------------------------
/.github/workflows/test_suite.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub. They are
2 | # provided by a third-party and are governed by separate terms of service,
3 | # privacy policy, and support documentation.
4 | #
5 | # This workflow will install a prebuilt Ruby version, install dependencies, and
6 | # run tests and linters.
7 | name: "Test Suite"
8 | on:
9 | push:
10 | branches: [ "main" ]
11 | pull_request:
12 | branches: [ "main" ]
13 | jobs:
14 | test:
15 | runs-on: ubuntu-latest
16 | services:
17 | postgres:
18 | image: postgres:11-alpine
19 | ports:
20 | - "5432:5432"
21 | env:
22 | POSTGRES_DB: rails_test
23 | POSTGRES_USER: rails
24 | POSTGRES_PASSWORD: password
25 | chrome:
26 | image: selenium/standalone-chrome:latest
27 | ports:
28 | - 4444:4444
29 | env:
30 | RAILS_ENV: test
31 | DATABASE_URL: "postgres://rails:password@localhost:5432/rails_test"
32 |
33 |
34 | steps:
35 | - name: Checkout code
36 | uses: actions/checkout@v3
37 | - name: Install Ruby and gems
38 | uses: ruby/setup-ruby@v1 # v1.146.0
39 | with:
40 | bundler-cache: true
41 |
42 | - name: internal tests
43 | run: bundle exec rspec
44 | - name: system tests
45 | run: script/test
46 |
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle/
2 | log/*.log
3 | pkg/
4 |
5 | .byebug_history
6 |
7 | .idea/
8 | *.gem
9 | .DS_Store
10 |
11 | dump.rdb
12 | tmp/
13 |
14 |
15 | db/*.sqlite3
16 |
17 | dummy/app/views/
18 | dummy/app/controllers/
19 | dummy/specs/
20 |
21 | dummy/node_modules/
22 | dummy/log/
23 | dummy/Gemfile.lock
24 | dummy/config/hot_glue.yml
25 |
26 |
27 | coverage/
28 |
29 | spec/dummy/app/controllers/
30 | spec/dummy/app/views/
31 | spec/dummy/app/javascript/application.js
32 | dummy/spec/features/
33 |
34 | spec/dummy/app/javascript/controllers/dropzone_controller.js
35 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.2.4
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 |
3 | before_install:
4 | - gem update --system
5 |
6 |
7 | branches:
8 | only:
9 | - main
10 |
11 |
12 | script: "script/test"
13 |
14 | rvm:
15 | - 3.1.2
16 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # THESE GEMS ARE NOT PART OF YOUR RAILS APP!!!
2 |
3 | source 'https://rubygems.org'
4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5 |
6 | gemspec
7 |
8 | # not required for your app
9 | gem 'sqlite3'
10 | gem 'byebug'
11 | # gem 'progress_formatter'
12 |
13 | # for testing
14 | gem 'simplecov-rcov'
15 | gem 'rake'
16 | gem "rspec-rails"
17 | gem "factory_bot_rails"
18 | gem "ffaker"
19 | gem "capybara"
20 | gem "selenium-webdriver", "4.11.0"
21 | # gem "webdrivers"
22 |
23 | gem "sprockets-rails"
24 | gem "importmap-rails"
25 | gem "stimulus-rails"
26 | gem "turbo-rails"
27 |
28 |
29 | gem "puma", "~> 5.0"
30 |
31 | gem "devise"
32 |
33 | gem "pg", "~> 1.5"
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 |
3 | Copyright © 2022 Jason Fleetwood-Boldt. All Rights Reserved
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
11 |
12 |
13 | TO PURCHASE A COMMERCIAL USAGE LICENSE PLEASE VISIT
14 | https://heliosdev.shop/hot-glue-license
15 |
16 | OR PURCHASE THE TUTORIALS AT
17 | https://school.jasonfleetwoodboldt.com/8188/?utm_source=github.com
18 |
--------------------------------------------------------------------------------
/README2.md:
--------------------------------------------------------------------------------
1 |
2 | ## LEGACY SETUP FOR RAILS 6
3 |
4 | ## Legacy Step #1. ADD HOTWIRE
5 | (RAILS 6 ONLY— SKIP THIS STEP FOR RAILS 7)
6 | ```
7 | yarn add @hotwired/turbo-rails
8 | ```
9 | or `npm install @hotwired/turbo-rails`
10 |
11 |
12 | ## Legacy Step #2. SWITCH FROM TurblLinks to Turbo-Rails
13 | (RAILS 6 ONLY — SKIP FOR RAILS 7)
14 | (THIS WAS AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION -- CONFIRM CHANGES ONLY)
15 | - Add `gem 'turbo-rails'` to your Gemfile & `bundle install`
16 | - Then install it with `rails turbo:install`
17 | - The Turbo install has switched your action cable settings from 'async' to Redis, so be sure to start a redis server
18 | - in `app/javascript/packs/application.js` remove this line
19 | ```
20 | import Turbolinks from "turbolinks"
21 | ```
22 | and replace it with
23 | ```
24 | import { Turbo } from "@hotwired/turbo-rails"
25 | ```
26 |
27 |
28 | Also replace
29 | ```
30 | Turbolinks.start()
31 | ```
32 | with:
33 | ```
34 | Turbo.start()
35 | ```
36 |
37 |
38 | ## Legacy Step #3. INSTALL WEBPACKER
39 | (_SKIP FOR RAILS 7_ unless you want to use Webpacker with Rails 7)
40 |
41 | ** For webpacker, you must be using Node version ^12.13.0 || ^14.15.0 || >=16 **
42 |
43 | I recommend Node Version Manager (NVM) to switch between nodes. You will not be able to get through the following command with a Node version that does not match above.
44 |
45 | Check your node version with `node -v`
46 |
47 | ```
48 | `yarn add @rails/webpacker`
49 | ```
50 |
51 |
52 | rails webpacker:install
53 |
54 | ## Legacy Step #4: Postgresql Enum Support for Rail 6
55 | For Enum support, I recommend activerecord-pg_enum
56 | Instructions for Rails 6 are here:
57 | https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
58 |
59 | _This functionality is now built-in to Rails 7._
60 |
61 |
62 | ## Legacy Step #5: Fix Devise if adding Turbo To Your Project
63 | ## IMPORTANT: Devise currently has serious compatibility issues with Turbo Rails. In particular, your log-in screens do not work out of the box. Follow the next step to fix them.
64 |
65 | Manually port the Devise views into your app with
66 |
67 | `rails generate devise:views`
68 |
69 | Edit `devise/registrations/new`, `devise/sessions/new`, `devise/passwords/new` and `devise/confirmations/new` modifying all four templates like so:
70 |
71 | form_for(resource, as: resource_name, url: session_path(resource_name) ) do |f|
72 |
73 | add the data-turbo false option in the html key:
74 |
75 | form_for(resource, as: resource_name, **html: {'data-turbo' => "false"},** url: session_path(resource_name) ) do |f|
76 |
77 | This tells Devise to fall back to non-Turbo interaction for the log-in and registration. For the rest of the app, we will use Turbo Rails interactions.
78 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/app/assets/config/manifest.js
--------------------------------------------------------------------------------
/app/helpers/hot_glue_helper.rb:
--------------------------------------------------------------------------------
1 | module HotGlueHelper
2 | class KVObject
3 | attr_accessor :key, :value
4 | def initialize(key: , value: )
5 | @key = key
6 | @value = value
7 | end
8 | end
9 |
10 | def enum_to_collection_select(hash)
11 | hash.collect{|k,v| KVObject.new(key: k, value: v)}
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/app/views/layouts/_flash_notices.erb:
--------------------------------------------------------------------------------
1 | <%= turbo_frame_tag "flash_notices" do %>
2 | <% unless notice.nil? %>
3 |
4 | <%= notice %>
5 |
6 | <% end %>
7 | <% unless alert.nil? %>
8 |
9 | <%= alert %>
10 |
11 | <% end %>
12 | <% end %>
13 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite. Versions 3.8.0 and up are supported.
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: dummy/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: dummy/db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: dummy/db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/config/hot_glue.yml:
--------------------------------------------------------------------------------
1 | ---
2 | :layout: hotglue
3 | :markup: erb
4 | :default_boolean_display: radio
5 | :sample_file_path: spec/files/computer_code.jpg
6 |
--------------------------------------------------------------------------------
/dummy/.gitattributes:
--------------------------------------------------------------------------------
1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files.
2 |
3 | # Mark the database schema as having been generated.
4 | db/schema.rb linguist-generated
5 |
6 | # Mark any vendored files as having been vendored.
7 | vendor/* linguist-vendored
8 |
--------------------------------------------------------------------------------
/dummy/.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 | /db/*.sqlite3
12 | /db/*.sqlite3-*
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*
16 | /tmp/*
17 | !/log/.keep
18 | !/tmp/.keep
19 |
20 | # Ignore pidfiles, but keep the directory.
21 | /tmp/pids/*
22 | !/tmp/pids/
23 | !/tmp/pids/.keep
24 |
25 | # Ignore uploaded files in development.
26 | /storage/*
27 | !/storage/.keep
28 | /tmp/storage/*
29 | !/tmp/storage/
30 | !/tmp/storage/.keep
31 |
32 | /public/assets
33 |
34 | # Ignore master key for decrypting credentials and more.
35 | /config/master.key
36 |
--------------------------------------------------------------------------------
/dummy/.rspec:
--------------------------------------------------------------------------------
1 | --require spec_helper
2 |
--------------------------------------------------------------------------------
/dummy/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.2.4
2 |
--------------------------------------------------------------------------------
/dummy/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3 |
4 | ruby "3.2.4"
5 |
6 |
7 | gem "rails", "~> 7.0.3", ">= 7.0.3.1"
8 |
9 |
10 | gem "sprockets-rails"
11 | gem "importmap-rails"
12 | gem "stimulus-rails"
13 | gem "turbo-rails"
14 |
15 | gem "sqlite3", "~> 1.4"
16 |
17 | gem "puma", "~> 5.0"
18 |
19 | gem "jbuilder"
20 | gem "devise"
21 |
22 | gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
23 |
24 | gem "bootsnap", require: false
25 |
26 |
27 | # gem "sassc-rails"
28 | gem 'rake'
29 |
30 |
31 | group :development, :test do
32 | gem "rspec-rails"
33 | gem "factory_bot_rails"
34 | gem "ffaker"
35 | gem "debug", platforms: %i[ mri mingw x64_mingw ]
36 | gem "byebug"
37 | end
38 |
39 | group :development do
40 | # Use console on exceptions pages [https://github.com/rails/web-console]
41 | gem "web-console"
42 | end
43 |
44 | group :test do
45 | # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
46 | gem "capybara"
47 | gem "selenium-webdriver"
48 | end
49 |
50 | # Use Redis for Action Cable
51 | gem "redis", "~> 4.0"
52 | gem 'hot-glue', path: "../"
53 |
54 | gem "image_processing", "~> 1.12"
55 |
56 | gem "pg", "~> 1.5"
57 |
--------------------------------------------------------------------------------
/dummy/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | This README would normally document whatever steps are necessary to get the
4 | application up and running.
5 |
6 | Things you may want to cover:
7 |
8 | * Ruby version
9 |
10 | * System dependencies
11 |
12 | * Configuration
13 |
14 | * Database creation
15 |
16 | * Database initialization
17 |
18 | * How to run the test suite
19 |
20 | * Services (job queues, cache servers, search engines, etc.)
21 |
22 | * Deployment instructions
23 |
24 | * ...
25 |
--------------------------------------------------------------------------------
/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require_relative "config/application"
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/dummy/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 | //= link_directory ../stylesheets .css
3 | //= link_tree ../../javascript .js
4 | //= link_tree ../../../vendor/javascript .js
5 |
--------------------------------------------------------------------------------
/dummy/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/app/assets/images/.keep
--------------------------------------------------------------------------------
/dummy/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
6 | * vendor/assets/stylesheets directory can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS
10 | * files in this directory. Styles in this file should be added after the last require_* statement.
11 | * It is generally better to create a new file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
--------------------------------------------------------------------------------
/dummy/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | layout 'application'
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/controllers/welcome_controller.rb:
--------------------------------------------------------------------------------
1 | class WelcomeController < ApplicationController
2 | def index
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/dummy/app/javascript/application.js:
--------------------------------------------------------------------------------
1 | // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
2 | import "@hotwired/turbo-rails"
3 |
--------------------------------------------------------------------------------
/dummy/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base
2 | # Automatically retry jobs that encountered a deadlock
3 | # retry_on ActiveRecord::Deadlocked
4 |
5 | # Most jobs are safe to ignore if the underlying records are no longer available
6 | # discard_on ActiveJob::DeserializationError
7 | end
8 |
--------------------------------------------------------------------------------
/dummy/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: "from@example.com"
3 | layout "mailer"
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/models/abc.rb:
--------------------------------------------------------------------------------
1 | class Abc < ApplicationRecord
2 | @@table_label_plural = "Apples"
3 | @@table_label_singular = "Apple"
4 |
5 | has_one_attached :aaa
6 |
7 | has_one_attached :bbb do |attachable|
8 | attachable.variant :thumb, resize_to_limit: [100,100]
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | primary_abstract_class
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/models/appointment.rb:
--------------------------------------------------------------------------------
1 | class Appointment < ApplicationRecord
2 |
3 | belongs_to :user
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/models/atw_display_name.rb:
--------------------------------------------------------------------------------
1 | class AtwDisplayName < ApplicationRecord
2 | belongs_to :xyz
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/models/atw_full_name.rb:
--------------------------------------------------------------------------------
1 | class AtwFullName < ApplicationRecord
2 | belongs_to :xyz
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/models/atw_to_label.rb:
--------------------------------------------------------------------------------
1 | class AtwToLabel < ApplicationRecord
2 |
3 | # this table has a to_label field
4 |
5 | belongs_to :xyz
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/dummy/app/models/borked.rb:
--------------------------------------------------------------------------------
1 | class Borked < ApplicationRecord
2 |
3 | # this table is intentionally missing belongs_to :xyz
4 | #
5 |
6 | # this tbale
7 | belongs_to :missing_label_table
8 | end
9 |
--------------------------------------------------------------------------------
/dummy/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/app/models/concerns/.keep
--------------------------------------------------------------------------------
/dummy/app/models/dfg.rb:
--------------------------------------------------------------------------------
1 | class Dfg < ApplicationRecord
2 | # can't use DEF as it is a Ruby Keyword
3 |
4 | belongs_to :user
5 | belongs_to :cantelope, class_name: "Fruits::Cantelope"
6 |
7 | has_many :ghis
8 | end
9 |
--------------------------------------------------------------------------------
/dummy/app/models/family.rb:
--------------------------------------------------------------------------------
1 | class Family < ApplicationRecord
2 |
3 | has_many :users
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/app/models/fruits/cantelope.rb:
--------------------------------------------------------------------------------
1 | class Fruits::Cantelope < ApplicationRecord
2 | self.table_name = 'cantelopes'
3 |
4 | has_many :dfgs
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/app/models/ghi.rb:
--------------------------------------------------------------------------------
1 | class Ghi < ApplicationRecord
2 |
3 | belongs_to :dfg, optional: true
4 | belongs_to :xyz, optional: true
5 | has_one :user, through: :dfg
6 |
7 | def name
8 | "name_of_#{id}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/app/models/hgi.rb:
--------------------------------------------------------------------------------
1 | class Hgi < ApplicationRecord
2 |
3 | has_many :jkls
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/models/human.rb:
--------------------------------------------------------------------------------
1 | class Human < ApplicationRecord
2 |
3 | has_many :pets
4 | end
5 |
--------------------------------------------------------------------------------
/dummy/app/models/jkl.rb:
--------------------------------------------------------------------------------
1 | class Jkl < ApplicationRecord
2 | belongs_to :hgi
3 |
4 | enum genre: {
5 | Fiction: "Fiction",
6 | Nonfiction: "Nonfiction",
7 | Mystery: "Mystery",
8 | Romance: "Romance",
9 | }
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/app/models/missing_label_table.rb:
--------------------------------------------------------------------------------
1 | class MissingLabelTable < ApplicationRecord
2 | has_many :borked
3 |
4 | # this table is missing a name field
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/app/models/nothing.rb:
--------------------------------------------------------------------------------
1 | class Nothing < ApplicationRecord
2 |
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/models/pet.rb:
--------------------------------------------------------------------------------
1 | class Pet < ApplicationRecord
2 | belongs_to :human
3 | end
4 |
--------------------------------------------------------------------------------
/dummy/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 | # Include default devise modules. Others available are:
3 | # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
4 | devise :database_authenticatable, :registerable,
5 | :recoverable, :rememberable, :validatable
6 |
7 | has_many :dfgs
8 | has_many :xyzs
9 |
10 | has_many :ghis, through: :dfgs
11 |
12 | belongs_to :family
13 | end
14 |
--------------------------------------------------------------------------------
/dummy/app/models/visit.rb:
--------------------------------------------------------------------------------
1 | class Visit < ApplicationRecord
2 |
3 | belongs_to :user
4 | has_one :family, through: :user
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/app/models/xyz.rb:
--------------------------------------------------------------------------------
1 | class Xyz < ApplicationRecord
2 | # belongs_to :nothing # association does not exist
3 |
4 | belongs_to :user
5 |
6 | has_many :ghis
7 |
8 | has_many :atw_to_label
9 | has_many :atw_full_name
10 | has_many :atw_display_name
11 |
12 | def name
13 | # "nothing here"
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/confirmations/new.html.erb:
--------------------------------------------------------------------------------
1 | Resend confirmation instructions
2 |
3 | <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
9 |
10 |
11 |
12 | <%= f.submit "Resend confirmation instructions" %>
13 |
14 | <% end %>
15 |
16 | <%= render "devise/shared/links" %>
17 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/mailer/confirmation_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Welcome <%= @email %>!
2 |
3 | You can confirm your account email through the link below:
4 |
5 | <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
6 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/mailer/email_changed.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @email %>!
2 |
3 | <% if @resource.try(:unconfirmed_email?) %>
4 | We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.
5 | <% else %>
6 | We're contacting you to notify you that your email has been changed to <%= @resource.email %>.
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/mailer/password_change.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | We're contacting you to notify you that your password has been changed.
4 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Someone has requested a link to change your password. You can do this through the link below.
4 |
5 | <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
6 |
7 | If you didn't request this, please ignore this email.
8 | Your password won't change until you access the link above and create a new one.
9 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/mailer/unlock_instructions.html.erb:
--------------------------------------------------------------------------------
1 | Hello <%= @resource.email %>!
2 |
3 | Your account has been locked due to an excessive number of unsuccessful sign in attempts.
4 |
5 | Click the link below to unlock your account:
6 |
7 | <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
8 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/passwords/edit.html.erb:
--------------------------------------------------------------------------------
1 | Change your password
2 |
3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 | <%= f.hidden_field :reset_password_token %>
6 |
7 |
8 | <%= f.label :password, "New password" %>
9 | <% if @minimum_password_length %>
10 | (<%= @minimum_password_length %> characters minimum)
11 | <% end %>
12 | <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
13 |
14 |
15 |
16 | <%= f.label :password_confirmation, "Confirm new password" %>
17 | <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
18 |
19 |
20 |
21 | <%= f.submit "Change my password" %>
22 |
23 | <% end %>
24 |
25 | <%= render "devise/shared/links" %>
26 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/passwords/new.html.erb:
--------------------------------------------------------------------------------
1 | Forgot your password?
2 |
3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
9 |
10 |
11 |
12 | <%= f.submit "Send me reset password instructions" %>
13 |
14 | <% end %>
15 |
16 | <%= render "devise/shared/links" %>
17 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/registrations/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit <%= resource_name.to_s.humanize %>
2 |
3 | <%= form_for(resource, html: {'data-turbo' => "false"}, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
9 |
10 |
11 | <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
12 | Currently waiting confirmation for: <%= resource.unconfirmed_email %>
13 | <% end %>
14 |
15 |
16 | <%= f.label :password %> (leave blank if you don't want to change it)
17 | <%= f.password_field :password, autocomplete: "new-password" %>
18 | <% if @minimum_password_length %>
19 |
20 | <%= @minimum_password_length %> characters minimum
21 | <% end %>
22 |
23 |
24 |
25 | <%= f.label :password_confirmation %>
26 | <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
27 |
28 |
29 |
30 | <%= f.label :current_password %> (we need your current password to confirm your changes)
31 | <%= f.password_field :current_password, autocomplete: "current-password" %>
32 |
33 |
34 |
35 | <%= f.submit "Update" %>
36 |
37 | <% end %>
38 |
39 | Cancel my account
40 |
41 | Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
42 |
43 | <%= link_to "Back", :back %>
44 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/registrations/new.html.erb:
--------------------------------------------------------------------------------
1 | Sign up
2 |
3 | <%= form_for(resource, html: {'data-turbo' => "false"}, as: resource_name, url: registration_path(resource_name)) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
9 |
10 |
11 |
12 | <%= f.label :password %>
13 | <% if @minimum_password_length %>
14 | (<%= @minimum_password_length %> characters minimum)
15 | <% end %>
16 | <%= f.password_field :password, autocomplete: "new-password" %>
17 |
18 |
19 |
20 | <%= f.label :password_confirmation %>
21 | <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
22 |
23 |
24 |
25 | <%= f.submit "Sign up" %>
26 |
27 | <% end %>
28 |
29 | <%= render "devise/shared/links" %>
30 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 | Log in
2 |
3 | <%= form_for(resource, html: {'data-turbo' => "false"}, as: resource_name, url: session_path(resource_name)) do |f| %>
4 |
5 | <%= f.label :email %>
6 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
7 |
8 |
9 |
10 | <%= f.label :password %>
11 | <%= f.password_field :password, autocomplete: "current-password" %>
12 |
13 |
14 | <% if devise_mapping.rememberable? %>
15 |
16 | <%= f.check_box :remember_me %>
17 | <%= f.label :remember_me %>
18 |
19 | <% end %>
20 |
21 |
22 | <%= f.submit "Log in" %>
23 |
24 | <% end %>
25 |
26 | <%= render "devise/shared/links" %>
27 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/shared/_error_messages.html.erb:
--------------------------------------------------------------------------------
1 | <% if resource.errors.any? %>
2 |
3 |
4 | <%= I18n.t("errors.messages.not_saved",
5 | count: resource.errors.count,
6 | resource: resource.class.model_name.human.downcase)
7 | %>
8 |
9 |
10 | <% resource.errors.full_messages.each do |message| %>
11 | <%= message %>
12 | <% end %>
13 |
14 |
15 | <% end %>
16 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/shared/_links.html.erb:
--------------------------------------------------------------------------------
1 | <%- if controller_name != 'sessions' %>
2 | <%= link_to "Log in", new_session_path(resource_name) %>
3 | <% end %>
4 |
5 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
6 | <%= link_to "Sign up", new_registration_path(resource_name) %>
7 | <% end %>
8 |
9 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
10 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
11 | <% end %>
12 |
13 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
14 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
15 | <% end %>
16 |
17 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
18 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
19 | <% end %>
20 |
21 | <%- if devise_mapping.omniauthable? %>
22 | <%- resource_class.omniauth_providers.each do |provider| %>
23 | <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %>
24 | <% end %>
25 | <% end %>
26 |
--------------------------------------------------------------------------------
/dummy/app/views/devise/unlocks/new.html.erb:
--------------------------------------------------------------------------------
1 | Resend unlock instructions
2 |
3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
9 |
10 |
11 |
12 | <%= f.submit "Resend unlock instructions" %>
13 |
14 | <% end %>
15 |
16 | <%= render "devise/shared/links" %>
17 |
--------------------------------------------------------------------------------
/dummy/app/views/layouts/_flash_notices.erb:
--------------------------------------------------------------------------------
1 | <%= turbo_frame_tag "flash_notices" do %>
2 | <% unless notice.nil? %>
3 |
4 | <%= notice %>
5 |
6 | <% end %>
7 | <% unless alert.nil? %>
8 |
9 | <%= alert %>
10 |
11 | <% end %>
12 | <% end %>
13 |
--------------------------------------------------------------------------------
/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dummy
5 |
6 | <%= csrf_meta_tags %>
7 | <%= csp_meta_tag %>
8 |
9 | <%= stylesheet_link_tag "application" %>
10 | <%= javascript_importmap_tags %>
11 |
12 |
13 |
14 |
15 |
16 | <% if user_signed_in? %>
17 |
18 | Logged in as
19 |
20 | <%= current_user.email %>
21 |
22 |
23 |
24 | <%= button_to "Logout", destroy_user_session_path, method: :delete, :class => 'dropdown-item' %>
25 |
26 | <% else %>
27 | <%= link_to "Sign up", new_user_registration_path, :class => 'dropdown-item' %>
28 |
29 | <%= link_to "Login", new_user_session_path, :class => 'dropdown-item' %>
30 | <% end %>
31 |
32 | <%= render partial: 'layouts/flash_notices' %>
33 |
34 | <%= yield %>
35 |
36 |
37 |
--------------------------------------------------------------------------------
/dummy/app/views/welcome/index.erb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/app/views/welcome/index.erb
--------------------------------------------------------------------------------
/dummy/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'bundle' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | require "rubygems"
12 |
13 | m = Module.new do
14 | module_function
15 |
16 | def invoked_as_script?
17 | File.expand_path($0) == File.expand_path(__FILE__)
18 | end
19 |
20 | def env_var_version
21 | ENV["BUNDLER_VERSION"]
22 | end
23 |
24 | def cli_arg_version
25 | return unless invoked_as_script? # don't want to hijack other binstubs
26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27 | bundler_version = nil
28 | update_index = nil
29 | ARGV.each_with_index do |a, i|
30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31 | bundler_version = a
32 | end
33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34 | bundler_version = $1
35 | update_index = i
36 | end
37 | bundler_version
38 | end
39 |
40 | def gemfile
41 | gemfile = ENV["BUNDLE_GEMFILE"]
42 | return gemfile if gemfile && !gemfile.empty?
43 |
44 | File.expand_path("../../Gemfile", __FILE__)
45 | end
46 |
47 | def lockfile
48 | lockfile =
49 | case File.basename(gemfile)
50 | when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51 | else "#{gemfile}.lock"
52 | end
53 | File.expand_path(lockfile)
54 | end
55 |
56 | def lockfile_version
57 | return unless File.file?(lockfile)
58 | lockfile_contents = File.read(lockfile)
59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60 | Regexp.last_match(1)
61 | end
62 |
63 | def bundler_requirement
64 | @bundler_requirement ||=
65 | env_var_version || cli_arg_version ||
66 | bundler_requirement_for(lockfile_version)
67 | end
68 |
69 | def bundler_requirement_for(version)
70 | return "#{Gem::Requirement.default}.a" unless version
71 |
72 | bundler_gem_version = Gem::Version.new(version)
73 |
74 | requirement = bundler_gem_version.approximate_recommendation
75 |
76 | return requirement unless Gem.rubygems_version < Gem::Version.new("2.7.0")
77 |
78 | requirement += ".a" if bundler_gem_version.prerelease?
79 |
80 | requirement
81 | end
82 |
83 | def load_bundler!
84 | ENV["BUNDLE_GEMFILE"] ||= gemfile
85 |
86 | activate_bundler
87 | end
88 |
89 | def activate_bundler
90 | gem_error = activation_error_handling do
91 | gem "bundler", bundler_requirement
92 | end
93 | return if gem_error.nil?
94 | require_error = activation_error_handling do
95 | require "bundler/version"
96 | end
97 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
98 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
99 | exit 42
100 | end
101 |
102 | def activation_error_handling
103 | yield
104 | nil
105 | rescue StandardError, LoadError => e
106 | e
107 | end
108 | end
109 |
110 | m.load_bundler!
111 |
112 | if m.invoked_as_script?
113 | load Gem.bin_path("bundler", "bundle")
114 | end
115 |
--------------------------------------------------------------------------------
/dummy/bin/importmap:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require_relative "../config/application"
4 | require "importmap/commands"
5 |
--------------------------------------------------------------------------------
/dummy/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path("../config/application", __dir__)
3 | require_relative "../config/boot"
4 | require "rails/commands"
5 |
--------------------------------------------------------------------------------
/dummy/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative "../config/boot"
3 | require "rake"
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/dummy/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require "fileutils"
3 |
4 | # path to your application root.
5 | APP_ROOT = File.expand_path("..", __dir__)
6 |
7 | def system!(*args)
8 | system(*args) || abort("\n== Command #{args} failed ==")
9 | end
10 |
11 | FileUtils.chdir APP_ROOT do
12 | # This script is a way to set up or update your development environment automatically.
13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14 | # Add necessary setup steps to this file.
15 |
16 | puts "== Installing dependencies =="
17 | system! "gem install bundler --conservative"
18 | system("bundle check") || system!("bundle install")
19 |
20 | # puts "\n== Copying sample files =="
21 | # unless File.exist?("config/database.yml")
22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml"
23 | # end
24 |
25 | puts "\n== Preparing database =="
26 | system! "bin/rails db:prepare"
27 |
28 | puts "\n== Removing old logs and tempfiles =="
29 | system! "bin/rails log:clear tmp:clear"
30 |
31 | puts "\n== Restarting application server =="
32 | system! "bin/rails restart"
33 | end
34 |
--------------------------------------------------------------------------------
/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative "config/environment"
4 |
5 | run Rails.application
6 | Rails.application.load_server
7 |
--------------------------------------------------------------------------------
/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative "boot"
2 |
3 | require "rails/all"
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module Dummy
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 7.0
13 |
14 | # Configuration for the application, engines, and railties goes here.
15 | #
16 | # These settings can be overridden in specific environments using the files
17 | # in config/environments, which are processed later.
18 | #
19 | # config.time_zone = "Central Time (US & Canada)"
20 | # config.eager_load_paths << Rails.root.join("extras")
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
2 |
3 | require "bundler/setup" # Set up gems listed in the Gemfile.
4 | # require "bootsnap/setup" # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/dummy/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: redis
3 | url: redis://localhost:6379/1
4 |
5 | test:
6 | adapter: test
7 |
8 | production:
9 | adapter: redis
10 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
11 | channel_prefix: dummy_production
12 |
--------------------------------------------------------------------------------
/dummy/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | 3Ey+ttsWUTMKYuXjx0d9Wjt6U3X0nSlaNRd3bFUg3/h9PSO+xHYcdvut9j9HQHJxx1vAaUmHuKJFrB6HCTI0AaFg+02eEdGnoZkOVAnK1MHd5rn+6lbfMzS73sikqK4jEyjsgBY9TcOc+JMF4ORY+a8qsna11qLeulYgLVPTOx5D4RSefy8BNZwg1i/+o+7Vfy7x6kiY/wov4iS5FXYW6ms59gps5Q6suVQ7OOR/xBjJcueJHcqobVGdRaEYfy2Vswwlo7SNNLZYRhirjAegl9n85Z9UniGhIIRLXjmwY+Go+XuLXDQFitYOyQxFnvg8fOV67MGVVWxLmHE2oBTeIdpeBlat50U3OXVNBD5LVc8+1LpZs4jRV26lIm0Hjm1+dpxe41YmOgE/Yed6k6A50MVi6ZakyAue22ms--/1rv47DKOUf79Eha--MVryG2Qes9KVlvuzQrS8Hw==
--------------------------------------------------------------------------------
/dummy/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 9.3 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On macOS with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On macOS with MacPorts:
8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
9 | # On Windows:
10 | # gem install pg
11 | # Choose the win32 build.
12 | # Install PostgreSQL and put its /bin directory on your path.
13 | #
14 | # Configure Using Gemfile
15 | # gem "pg"
16 | #
17 | default: &default
18 | adapter: postgresql
19 | encoding: unicode
20 | # For details on connection pooling, see Rails configuration guide
21 | # https://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
23 |
24 | development:
25 | <<: *default
26 | database: hot_glue_dummy_development
27 |
28 | # The specified database role being used to connect to postgres.
29 | # To create additional roles in postgres see `$ createuser --help`.
30 | # When left blank, postgres will use the default role. This is
31 | # the same name as the operating system user running Rails.
32 | #username: dummy
33 |
34 | # The password associated with the postgres role (username).
35 | #password:
36 |
37 | # Connect on a TCP socket. Omitted by default since the client uses a
38 | # domain socket that doesn't need configuration. Windows does not have
39 | # domain sockets, so uncomment these lines.
40 | #host: localhost
41 |
42 | # The TCP port the server listens on. Defaults to 5432.
43 | # If your server runs on a different port number, change accordingly.
44 | #port: 5432
45 |
46 | # Schema search path. The server defaults to $user,public
47 | #schema_search_path: myapp,sharedapp,public
48 |
49 | # Minimum log levels, in increasing order:
50 | # debug5, debug4, debug3, debug2, debug1,
51 | # log, notice, warning, error, fatal, and panic
52 | # Defaults to warning.
53 | #min_messages: notice
54 |
55 | # Warning: The database defined as "test" will be erased and
56 | # re-generated from your development database when you run "rake".
57 | # Do not set this db to the same as development or production.
58 | test:
59 | <<: *default
60 | database: hot_glue_dummy_test
61 |
--------------------------------------------------------------------------------
/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative "application"
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # In the development environment your application's code is reloaded any time
7 | # it changes. This slows down response time but is perfect for development
8 | # since you don't have to restart the web server when you make code changes.
9 | config.cache_classes = false
10 |
11 | # Do not eager load code on boot.
12 | config.eager_load = false
13 |
14 | # Show full error reports.
15 | config.consider_all_requests_local = true
16 |
17 | # Enable server timing
18 | config.server_timing = true
19 |
20 | # Enable/disable caching. By default caching is disabled.
21 | # Run rails dev:cache to toggle caching.
22 | if Rails.root.join("tmp/caching-dev.txt").exist?
23 | config.action_controller.perform_caching = true
24 | config.action_controller.enable_fragment_cache_logging = true
25 |
26 | config.cache_store = :memory_store
27 | config.public_file_server.headers = {
28 | "Cache-Control" => "public, max-age=#{2.days.to_i}"
29 | }
30 | else
31 | config.action_controller.perform_caching = false
32 |
33 | config.cache_store = :null_store
34 | end
35 |
36 | # Store uploaded files on the local file system (see config/storage.yml for options).
37 | config.active_storage.service = :local
38 |
39 | # Don't care if the mailer can't send.
40 | config.action_mailer.raise_delivery_errors = false
41 |
42 | config.action_mailer.perform_caching = false
43 |
44 | # Print deprecation notices to the Rails logger.
45 | config.active_support.deprecation = :log
46 |
47 | # Raise exceptions for disallowed deprecations.
48 | config.active_support.disallowed_deprecation = :raise
49 |
50 | # Tell Active Support which deprecation messages to disallow.
51 | config.active_support.disallowed_deprecation_warnings = []
52 |
53 | # Raise an error on page load if there are pending migrations.
54 | config.active_record.migration_error = :page_load
55 |
56 | # Highlight code that triggered database queries in logs.
57 | config.active_record.verbose_query_logs = true
58 |
59 | # Suppress logger output for asset requests.
60 | config.assets.quiet = true
61 |
62 | # Raises error for missing translations.
63 | # config.i18n.raise_on_missing_translations = true
64 |
65 | # Annotate rendered view with file names.
66 | # config.action_view.annotate_rendered_view_with_filenames = true
67 |
68 | # Uncomment if you wish to allow Action Cable access from any origin.
69 | # config.action_cable.disable_request_forgery_protection = true
70 | end
71 |
--------------------------------------------------------------------------------
/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # Code is not reloaded between requests.
7 | config.cache_classes = true
8 |
9 | # Eager load code on boot. This eager loads most of Rails and
10 | # your application in memory, allowing both threaded web servers
11 | # and those relying on copy on write to perform better.
12 | # Rake tasks automatically ignore this option for performance.
13 | config.eager_load = true
14 |
15 | # Full error reports are disabled and caching is turned on.
16 | config.consider_all_requests_local = false
17 | config.action_controller.perform_caching = true
18 |
19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
21 | # config.require_master_key = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
26 |
27 | # Compress CSS using a preprocessor.
28 | # config.assets.css_compressor = :sass
29 |
30 | # Do not fallback to assets pipeline if a precompiled asset is missed.
31 | config.assets.compile = false
32 |
33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
34 | # config.asset_host = "http://assets.example.com"
35 |
36 | # Specifies the header that your server uses for sending files.
37 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
38 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
39 |
40 | # Store uploaded files on the local file system (see config/storage.yml for options).
41 | config.active_storage.service = :local
42 |
43 | # Mount Action Cable outside main process or domain.
44 | # config.action_cable.mount_path = nil
45 | # config.action_cable.url = "wss://example.com/cable"
46 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
47 |
48 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
49 | # config.force_ssl = true
50 |
51 | # Include generic and useful information about system operation, but avoid logging too much
52 | # information to avoid inadvertent exposure of personally identifiable information (PII).
53 | config.log_level = :info
54 |
55 | # Prepend all log lines with the following tags.
56 | config.log_tags = [ :request_id ]
57 |
58 | # Use a different cache store in production.
59 | # config.cache_store = :mem_cache_store
60 |
61 | # Use a real queuing backend for Active Job (and separate queues per environment).
62 | # config.active_job.queue_adapter = :resque
63 | # config.active_job.queue_name_prefix = "dummy_production"
64 |
65 | config.action_mailer.perform_caching = false
66 |
67 | # Ignore bad email addresses and do not raise email delivery errors.
68 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
69 | # config.action_mailer.raise_delivery_errors = false
70 |
71 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
72 | # the I18n.default_locale when a translation cannot be found).
73 | config.i18n.fallbacks = true
74 |
75 | # Don't log any deprecations.
76 | config.active_support.report_deprecations = false
77 |
78 | # Use default logging formatter so that PID and timestamp are not suppressed.
79 | config.log_formatter = ::Logger::Formatter.new
80 |
81 | # Use a different logger for distributed setups.
82 | # require "syslog/logger"
83 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
84 |
85 | if ENV["RAILS_LOG_TO_STDOUT"].present?
86 | logger = ActiveSupport::Logger.new(STDOUT)
87 | logger.formatter = config.log_formatter
88 | config.logger = ActiveSupport::TaggedLogging.new(logger)
89 | end
90 |
91 | # Do not dump schema after migrations.
92 | config.active_record.dump_schema_after_migration = false
93 | end
94 |
--------------------------------------------------------------------------------
/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/integer/time"
2 |
3 | # The test environment is used exclusively to run your application's
4 | # test suite. You never need to work with it otherwise. Remember that
5 | # your test database is "scratch space" for the test suite and is wiped
6 | # and recreated between test runs. Don't rely on the data there!
7 |
8 | Rails.application.configure do
9 | # Settings specified here will take precedence over those in config/application.rb.
10 |
11 | # Turn false under Spring and add config.action_view.cache_template_loading = true.
12 | config.cache_classes = true
13 |
14 | # Eager loading loads your whole application. When running a single test locally,
15 | # this probably isn't necessary. It's a good idea to do in a continuous integration
16 | # system, or in some way before deploying your code.
17 | config.eager_load = ENV["CI"].present?
18 |
19 | # Configure public file server for tests with Cache-Control for performance.
20 | config.public_file_server.enabled = true
21 | config.public_file_server.headers = {
22 | "Cache-Control" => "public, max-age=#{1.hour.to_i}"
23 | }
24 |
25 | # Show full error reports and disable caching.
26 | config.consider_all_requests_local = true
27 | config.action_controller.perform_caching = false
28 | config.cache_store = :null_store
29 |
30 | # Raise exceptions instead of rendering exception templates.
31 | config.action_dispatch.show_exceptions = false
32 |
33 | # Disable request forgery protection in test environment.
34 | config.action_controller.allow_forgery_protection = false
35 |
36 | # Store uploaded files on the local file system in a temporary directory.
37 | config.active_storage.service = :test
38 |
39 | config.action_mailer.perform_caching = false
40 |
41 | # Tell Action Mailer not to deliver emails to the real world.
42 | # The :test delivery method accumulates sent emails in the
43 | # ActionMailer::Base.deliveries array.
44 | config.action_mailer.delivery_method = :test
45 |
46 | # Print deprecation notices to the stderr.
47 | config.active_support.deprecation = :stderr
48 |
49 | # Raise exceptions for disallowed deprecations.
50 | config.active_support.disallowed_deprecation = :raise
51 |
52 | # Tell Active Support which deprecation messages to disallow.
53 | config.active_support.disallowed_deprecation_warnings = []
54 |
55 | # Raises error for missing translations.
56 | # config.i18n.raise_on_missing_translations = true
57 |
58 | # Annotate rendered view with file names.
59 | # config.action_view.annotate_rendered_view_with_filenames = true
60 | end
61 |
--------------------------------------------------------------------------------
/dummy/config/hot_glue.yml:
--------------------------------------------------------------------------------
1 | ---
2 | :layout: bootstrap
3 | :markup: erb
4 | :default_boolean_display: radio
5 |
6 | :sample_file_path: spec/files/computer_code.jpg
7 |
--------------------------------------------------------------------------------
/dummy/config/importmap.rb:
--------------------------------------------------------------------------------
1 | # Pin npm packages by running ./bin/importmap
2 |
3 | pin "application", preload: true
4 | pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
5 |
--------------------------------------------------------------------------------
/dummy/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
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 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in the app/assets
11 | # folder are already added.
12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
13 |
--------------------------------------------------------------------------------
/dummy/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy.
4 | # See the Securing Rails Applications Guide for more information:
5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header
6 |
7 | # Rails.application.configure do
8 | # config.content_security_policy do |policy|
9 | # policy.default_src :self, :https
10 | # policy.font_src :self, :https, :data
11 | # policy.img_src :self, :https, :data
12 | # policy.object_src :none
13 | # policy.script_src :self, :https
14 | # policy.style_src :self, :https
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 | #
19 | # # Generate session nonces for permitted importmap and inline scripts
20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
21 | # config.content_security_policy_nonce_directives = %w(script-src)
22 | #
23 | # # Report violations without enforcing the policy.
24 | # # config.content_security_policy_report_only = true
25 | # end
26 |
--------------------------------------------------------------------------------
/dummy/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure parameters to be filtered from the log file. Use this to limit dissemination of
4 | # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
5 | # notations and behaviors.
6 | Rails.application.config.filter_parameters += [
7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
8 | ]
9 |
--------------------------------------------------------------------------------
/dummy/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, "\\1en"
8 | # inflect.singular /^(ox)en/i, "\\1"
9 | inflect.irregular "human", "humans"
10 | # inflect.uncountable %w( fish sheep )
11 | end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym "RESTful"
16 | # end
17 |
--------------------------------------------------------------------------------
/dummy/config/initializers/permissions_policy.rb:
--------------------------------------------------------------------------------
1 | # Define an application-wide HTTP permissions policy. For further
2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy
3 | #
4 | # Rails.application.config.permissions_policy do |f|
5 | # f.camera :none
6 | # f.gyroscope :none
7 | # f.microphone :none
8 | # f.usb :none
9 | # f.fullscreen :self
10 | # f.payment :self, "https://secure.example.com"
11 | # end
12 |
--------------------------------------------------------------------------------
/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 https://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/dummy/config/puma.rb:
--------------------------------------------------------------------------------
1 | # Puma can serve each request in a thread from an internal thread pool.
2 | # The `threads` method setting takes two numbers: a minimum and maximum.
3 | # Any libraries that use thread pools should be configured to match
4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
5 | # and maximum; this matches the default thread size of Active Record.
6 | #
7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
9 | threads min_threads_count, max_threads_count
10 |
11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before
12 | # terminating a worker in development environments.
13 | #
14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
15 |
16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
17 | #
18 | port ENV.fetch("PORT") { 3000 }
19 |
20 | # Specifies the `environment` that Puma will run in.
21 | #
22 | environment ENV.fetch("RAILS_ENV") { "development" }
23 |
24 | # Specifies the `pidfile` that Puma will use.
25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
26 |
27 | # Specifies the number of `workers` to boot in clustered mode.
28 | # Workers are forked web server processes. If using threads and workers together
29 | # the concurrency of the application would be max `threads` * `workers`.
30 | # Workers do not work on JRuby or Windows (both of which do not support
31 | # processes).
32 | #
33 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
34 |
35 | # Use the `preload_app!` method when specifying a `workers` number.
36 | # This directive tells Puma to first boot the application and load code
37 | # before forking the application. This takes advantage of Copy On Write
38 | # process behavior so workers use less memory.
39 | #
40 | # preload_app!
41 |
42 | # Allow puma to be restarted by `bin/rails restart` command.
43 | plugin :tmp_restart
44 |
--------------------------------------------------------------------------------
/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | devise_for :users
3 |
4 | root to: "welcome#index"
5 | resources :abcs
6 | resources :ghis
7 | resources :dfgs
8 | resources :jkls
9 | resources :cantelopes
10 |
11 | resources :pets
12 | resources :humans
13 | resources :users
14 | end
15 |
--------------------------------------------------------------------------------
/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 bin/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-<%= Rails.env %>
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-<%= Rails.env %>
23 |
24 | # Use bin/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-<%= Rails.env %>
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20210306223300_create_dfgs.rb:
--------------------------------------------------------------------------------
1 | class CreateDfgs < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :dfgs do |t|
4 | t.integer :user_id
5 | t.string :name
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20210306223305_create_ghis.rb:
--------------------------------------------------------------------------------
1 | class CreateGhis < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :ghis do |t|
4 | t.integer :dfg_id
5 | t.integer :xyz_id
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20210306223309_create_jkls.rb:
--------------------------------------------------------------------------------
1 | class CreateJkls < ActiveRecord::Migration[6.1]
2 | def change
3 | create_enum :genre, %w[Fiction Nonfiction Mystery Romance Novel]
4 |
5 | create_table :jkls do |t|
6 | t.integer :hgi_id
7 |
8 | t.string :name
9 | t.string :blurb
10 | t.text :long_description
11 | t.float :cost
12 | t.integer :how_many_printed
13 | t.datetime :approved_at
14 | t.date :release_on
15 | t.time :time_of_day
16 | t.boolean :selected
17 | t.enum :genre, enum_type: :genre
18 | t.timestamps
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20210306223701_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DeviseCreateUsers < ActiveRecord::Migration[6.1]
4 | def change
5 | create_table :users do |t|
6 | ## Database authenticatable
7 | t.string :email, null: false, default: ""
8 | t.string :encrypted_password, null: false, default: ""
9 |
10 | ## Recoverable
11 | t.string :reset_password_token
12 | t.datetime :reset_password_sent_at
13 |
14 | ## Rememberable
15 | t.datetime :remember_created_at
16 |
17 | ## Trackable
18 | # t.integer :sign_in_count, default: 0, null: false
19 | # t.datetime :current_sign_in_at
20 | # t.datetime :last_sign_in_at
21 | # t.string :current_sign_in_ip
22 | # t.string :last_sign_in_ip
23 |
24 | ## Confirmable
25 | # t.string :confirmation_token
26 | # t.datetime :confirmed_at
27 | # t.datetime :confirmation_sent_at
28 | # t.string :unconfirmed_email # Only if using reconfirmable
29 |
30 | ## Lockable
31 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
32 | # t.string :unlock_token # Only if unlock strategy is :email or :both
33 | # t.datetime :locked_at
34 |
35 | t.integer :family_id
36 | t.timestamps null: false
37 | end
38 |
39 | add_index :users, :email, unique: true
40 | add_index :users, :reset_password_token, unique: true
41 | # add_index :users, :confirmation_token, unique: true
42 | # add_index :users, :unlock_token, unique: true
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20210306225506_create_xyzs.rb:
--------------------------------------------------------------------------------
1 | class CreateXyzs < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :xyzs do |t|
4 | t.integer :nothing_id
5 | t.integer :user_id
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20211226155351_create_abcs.rb:
--------------------------------------------------------------------------------
1 | class CreateAbcs < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :abcs do |t|
4 | t.string :name
5 |
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20211226165050_create_hgis.rb:
--------------------------------------------------------------------------------
1 | class CreateHgis < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :hgis do |t|
4 | t.string :name
5 | t.integer :how_many
6 | t.text :hello
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220201164536_add_cantelope_id_to_dfgs.rb:
--------------------------------------------------------------------------------
1 | class AddCantelopeIdToDfgs < ActiveRecord::Migration[6.1]
2 | def change
3 |
4 | add_column :dfgs, :cantelope_id, :integer
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220201165048_create_cantelopes.rb:
--------------------------------------------------------------------------------
1 | class CreateCantelopes < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :cantelopes do |t|
4 |
5 | t.string :name
6 | t.string :_a_show_only_field
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220318093158_create_pets.rb:
--------------------------------------------------------------------------------
1 | class CreatePets < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :pets do |t|
4 | t.string :name
5 | t.integer :human_id
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220318093211_create_human.rb:
--------------------------------------------------------------------------------
1 | class CreateHuman < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :humans do |t|
4 | t.string :name
5 |
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220318093221_create_appointments.rb:
--------------------------------------------------------------------------------
1 | class CreateAppointments < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :appointments do |t|
4 | t.integer :pet_id
5 |
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220320194207_create_atw_to_labels.rb:
--------------------------------------------------------------------------------
1 | class CreateAtwToLabels < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :atw_to_labels do |t|
4 | t.string :to_label
5 | t.integer :xyz_id
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220320200217_create_atw_full_names.rb:
--------------------------------------------------------------------------------
1 | class CreateAtwFullNames < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :atw_full_names do |t|
4 | t.string :full_name
5 | t.integer :xyz_id
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220320200230_create_atw_display_names.rb:
--------------------------------------------------------------------------------
1 | class CreateAtwDisplayNames < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :atw_display_names do |t|
4 | t.string :display_name
5 | t.integer :xyz_id
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220320214017_create_borkeds.rb:
--------------------------------------------------------------------------------
1 | class CreateBorkeds < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :borkeds do |t|
4 | t.integer :xyz_id
5 |
6 | t.integer :missing_label_table_id
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220320223316_create_missing_label_tables.rb:
--------------------------------------------------------------------------------
1 | class CreateMissingLabelTables < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :missing_label_tables do |t|
4 |
5 | t.timestamps
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220323000346_create_families.rb:
--------------------------------------------------------------------------------
1 | class CreateFamilies < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :families do |t|
4 | t.string :name
5 |
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20220323000410_create_visits.rb:
--------------------------------------------------------------------------------
1 | class CreateVisits < ActiveRecord::Migration[6.1]
2 | def change
3 | create_table :visits do |t|
4 | t.string :name
5 | t.integer :user_id
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/dummy/db/migrate/20230317162618_create_active_storage_tables.active_storage.rb:
--------------------------------------------------------------------------------
1 | # This migration comes from active_storage (originally 20170806125915)
2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3 | def change
4 | # Use Active Record's configured type for primary and foreign keys
5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types
6 |
7 | create_table :active_storage_blobs, id: primary_key_type do |t|
8 | t.string :key, null: false
9 | t.string :filename, null: false
10 | t.string :content_type
11 | t.text :metadata
12 | t.string :service_name, null: false
13 | t.bigint :byte_size, null: false
14 | t.string :checksum
15 |
16 | if connection.supports_datetime_with_precision?
17 | t.datetime :created_at, precision: 6, null: false
18 | else
19 | t.datetime :created_at, null: false
20 | end
21 |
22 | t.index [ :key ], unique: true
23 | end
24 |
25 | create_table :active_storage_attachments, id: primary_key_type do |t|
26 | t.string :name, null: false
27 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
28 | t.references :blob, null: false, type: foreign_key_type
29 |
30 | if connection.supports_datetime_with_precision?
31 | t.datetime :created_at, precision: 6, null: false
32 | else
33 | t.datetime :created_at, null: false
34 | end
35 |
36 | t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
37 | t.foreign_key :active_storage_blobs, column: :blob_id
38 | end
39 |
40 | create_table :active_storage_variant_records, id: primary_key_type do |t|
41 | t.belongs_to :blob, null: false, index: false, type: foreign_key_type
42 | t.string :variation_digest, null: false
43 |
44 | t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
45 | t.foreign_key :active_storage_blobs, column: :blob_id
46 | end
47 | end
48 |
49 | private
50 | def primary_and_foreign_key_types
51 | config = Rails.configuration.generators
52 | setting = config.options[config.orm][:primary_key_type]
53 | primary_key_type = setting || :primary_key
54 | foreign_key_type = setting || :bigint
55 | [primary_key_type, foreign_key_type]
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/dummy/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }])
7 | # Character.create(name: "Luke", movie: movies.first)
8 |
--------------------------------------------------------------------------------
/dummy/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/lib/assets/.keep
--------------------------------------------------------------------------------
/dummy/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/lib/tasks/.keep
--------------------------------------------------------------------------------
/dummy/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/log/.keep
--------------------------------------------------------------------------------
/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/dummy/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/dummy/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/public/favicon.ico
--------------------------------------------------------------------------------
/dummy/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/dummy/spec/factories/abc_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :abc do
3 | name { FFaker.name }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/cantelope_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :cantelope, class: Fruits::Cantelope do
3 | name { FFaker.name }
4 | _a_show_only_field { FFaker.name }
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/dummy/spec/factories/dfg_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :dfg do
3 | user { build(:user) }
4 | name { FFaker.name }
5 | cantelope { build(:cantelope) }
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/dummy/spec/factories/family_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :family do
3 | name { FFaker.name }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/ghi_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :ghi do
3 |
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/hgi_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :hgi do
3 | name { FFaker::Name }
4 | how_many {rand(4)}
5 | hello { FFaker::Name }
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/dummy/spec/factories/human_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :human do
3 | name {"xyz"}
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/jkl_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :jkl do
3 |
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/pet_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :pet do
3 | human {create(:human)}
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/factories/user_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | email { FFaker::Internet.email }
4 | password { "password" }
5 | password_confirmation { "password" }
6 | family { build(:family) }
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/dummy/spec/factories/xyz_factory.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :xyz do
3 | user { build(:user) }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/spec/files/computer_code.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/spec/files/computer_code.jpg
--------------------------------------------------------------------------------
/dummy/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | require 'spec_helper'
3 | ENV['RAILS_ENV'] ||= 'test'
4 | require_relative '../config/environment'
5 | # Prevent database truncation if the environment is production
6 | abort("The Rails environment is running in production mode!") if Rails.env.production?
7 | require 'rspec/rails'
8 | require 'support/capybara_login.rb'
9 |
10 | puts "reloading app..."
11 | def reload!(print = true)
12 | puts 'Reloading ...' if print
13 | # Main project directory.
14 | root_dir = File.expand_path('..', __dir__)
15 | # Directories within the project that should be reloaded.
16 | reload_dirs = %w{lib}
17 | # Loop through and reload every file in all relevant project directories.
18 | reload_dirs.each do |dir|
19 | Dir.glob("#{root_dir}/#{dir}/**/*.rb").each { |f| load(f) }
20 | end
21 | # Return true when complete.
22 | true
23 | end
24 | reload!
25 |
26 | puts "finished reloading app..."
27 |
28 |
29 | # Add additional requires below this line. Rails is not loaded until this point!
30 |
31 | # Requires supporting ruby files with custom matchers and macros, etc, in
32 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
33 | # run as spec files by default. This means that files in spec/support that end
34 | # in _spec.rb will both be required and run as specs, causing the specs to be
35 | # run twice. It is recommended that you do not name files matching this glob to
36 | # end with _spec.rb. You can configure this pattern with the --pattern
37 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
38 | #
39 | # The following line is provided for convenience purposes. It has the downside
40 | # of increasing the boot-up time by auto-requiring all files in the support
41 | # directory. Alternatively, in the individual `*_spec.rb` files, manually
42 | # require only the support files necessary.
43 | #
44 | # Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
45 |
46 | # Checks for pending migrations and applies them before tests are run.
47 | # If you are not using ActiveRecord, you can remove these lines.
48 | begin
49 | ActiveRecord::Migration.maintain_test_schema!
50 | rescue ActiveRecord::PendingMigrationError => e
51 | puts e.to_s.strip
52 | exit 1
53 | end
54 | RSpec.configure do |config|
55 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
56 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
57 |
58 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
59 | # examples within a transaction, remove the following line or assign false
60 | # instead of true.
61 | config.use_transactional_fixtures = true
62 |
63 | # You can uncomment this line to turn off ActiveRecord support entirely.
64 | # config.use_active_record = false
65 |
66 | # RSpec Rails can automatically mix in different behaviours to your tests
67 | # based on their file location, for example enabling you to call `get` and
68 | # `post` in specs under `spec/controllers`.
69 | #
70 | # You can disable this behaviour by removing the line below, and instead
71 | # explicitly tag your specs with their type, e.g.:
72 | #
73 | # RSpec.describe UsersController, type: :controller do
74 | # # ...
75 | # end
76 | #
77 | # The different available types are documented in the features, such as in
78 | # https://relishapp.com/rspec/rspec-rails/docs
79 | config.infer_spec_type_from_file_location!
80 |
81 | # Filter lines from Rails gems in backtraces.
82 | config.filter_rails_from_backtrace!
83 | # arbitrary gems may also be filtered via:
84 | # config.filter_gems_from_backtrace("gem name")
85 | config.include FactoryBot::Syntax::Methods
86 |
87 | end
88 |
89 | Capybara.default_driver = :selenium_chrome_headless
90 |
--------------------------------------------------------------------------------
/dummy/spec/support/capybara_login.rb:
--------------------------------------------------------------------------------
1 | def login_as(user)
2 | visit '/users/sign_in'
3 | within("#new_user") do
4 | fill_in 'Email', with: user.email
5 | fill_in 'Password', with: 'password'
6 | end
7 | click_button 'Log in'
8 | end
9 |
--------------------------------------------------------------------------------
/dummy/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/storage/.keep
--------------------------------------------------------------------------------
/dummy/test/application_system_test_case.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
5 | end
6 |
--------------------------------------------------------------------------------
/dummy/test/channels/application_cable/connection_test.rb:
--------------------------------------------------------------------------------
1 | require "test_helper"
2 |
3 | class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
4 | # test "connects with cookies" do
5 | # cookies.signed[:user_id] = 42
6 | #
7 | # connect
8 | #
9 | # assert_equal connection.user_id, "42"
10 | # end
11 | end
12 |
--------------------------------------------------------------------------------
/dummy/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/controllers/.keep
--------------------------------------------------------------------------------
/dummy/test/fixtures/files/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/fixtures/files/.keep
--------------------------------------------------------------------------------
/dummy/test/helpers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/helpers/.keep
--------------------------------------------------------------------------------
/dummy/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/integration/.keep
--------------------------------------------------------------------------------
/dummy/test/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/mailers/.keep
--------------------------------------------------------------------------------
/dummy/test/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/models/.keep
--------------------------------------------------------------------------------
/dummy/test/system/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/test/system/.keep
--------------------------------------------------------------------------------
/dummy/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] ||= "test"
2 | require_relative "../config/environment"
3 | require "rails/test_help"
4 |
5 | class ActiveSupport::TestCase
6 | # Run tests in parallel with specified workers
7 | parallelize(workers: :number_of_processors)
8 |
9 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
10 | fixtures :all
11 |
12 | # Add more helper methods to be used by all tests here...
13 | end
14 |
--------------------------------------------------------------------------------
/dummy/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/vendor/.keep
--------------------------------------------------------------------------------
/dummy/vendor/javascript/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/dummy/vendor/javascript/.keep
--------------------------------------------------------------------------------
/hot_glue.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("lib", __dir__)
2 |
3 | # Maintain your gem's version:
4 | require "hotglue/version"
5 |
6 | # Describe your gem and declare its dependencies:
7 | Gem::Specification.new do |spec|
8 | spec.name = "hot-glue"
9 | spec.version = HotGlue::Version::CURRENT
10 | spec.license = 'Nonstandard'
11 | spec.date = Time.now.strftime("%Y-%m-%d")
12 | spec.summary = "A gem to build Turbo Rails scaffolding."
13 | spec.description = "Simple, plug & play Rails scaffold building companion for Turbo-Rails and Hotwire"
14 | spec.authors = ["Jason Fleetwood-Boldt"]
15 | spec.email = 'hello@jfbcodes.com'
16 |
17 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18 | files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|dummy)}) || f.match(%r{(gemspec|gem)$}) }
19 | files
20 | end
21 |
22 | spec.add_runtime_dependency "rails", '> 5.1'
23 | spec.homepage = 'https://heliosdev.shop/p/hot-glue?utm_source=rubygems.org&utm_campaign=rubygems_link'
24 | spec.metadata = { "source_code_uri" => "https://github.com/hot-glue-for-rails/hot-glue",
25 | "homepage" => "https://heliosdev.shop/hot-glue",
26 | "funding" => "https://school.jfbcodes.com/8188" }
27 |
28 | spec.add_runtime_dependency('kaminari', '~> 1.2')
29 | # spec.add_runtime_dependency('sass-rails')
30 |
31 | spec.add_dependency 'ffaker', "~> 2.16"
32 | # spec.add_runtime_dependency "turbo-rails"
33 |
34 | spec.post_install_message = <<~MSG
35 | ---------------------------------------------
36 | Welcome to Hot Glue - A Scaffold Building Companion for Hotwire + Turbo-Rails
37 | For license options visit https://heliosdev.shop/hot-glue-license
38 | ---------------------------------------------
39 | MSG
40 | end
41 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/default_config_loader.rb:
--------------------------------------------------------------------------------
1 | module DefaultConfigLoader
2 |
3 |
4 | def default_configs
5 | @yaml_from_config ||= YAML.load(File.read("config/hot_glue.yml"))
6 | end
7 |
8 |
9 | def get_default_from_config(key: )
10 | default_configs[key]
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/direct_upload_install_generator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module HotGlue
4 | class DirectUploadInstallGenerator < Rails::Generators::Base
5 | source_root File.expand_path('templates', __dir__)
6 |
7 | def filepath_prefix
8 | # todo: inject the context
9 | 'spec/dummy/' if $INTERNAL_SPECS
10 | end
11 |
12 | def initialize(*args) #:nodoc:
13 | super
14 |
15 | if Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }['importmap-rails'] # impomrtmaps
16 |
17 | file_contents = File.read("#{filepath_prefix}app/javascript/application.js")
18 |
19 | if !file_contents.include?("//= require activestorage")
20 | file_contents << "//= require activestorage"
21 | File.write("#{filepath_prefix}app/javascript/application.js", file_contents)
22 | puts " HOTGLUE --> added to #{filepath_prefix}app/javascript/application.js: `//= require activestorage"
23 | else
24 | puts " HOTGLUE --> #{filepath_prefix}app/javascript/application.js already contains `//= require activestorage`"
25 | end
26 |
27 | elsif Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }['jsbundling-rails']
28 | file_contents = File.read("#{filepath_prefix}app/javascript/application.js")
29 |
30 | if !file_contents.include?("ActiveStorage.start()")
31 | file_contents << "import * as ActiveStorage from \"@rails/activestorage\"
32 | ActiveStorage.start()"
33 | File.write("#{filepath_prefix}app/javascript/application.js", file_contents)
34 | puts " HOTGLUE --> added to #{filepath_prefix}app/javascript/application.js: `ActiveStorage.start()"
35 | else
36 | puts " HOTGLUE --> #{filepath_prefix}app/javascript/application.js already contains `ActiveStorage.start()`"
37 | end
38 |
39 |
40 | else
41 | puts " HOTGLUE --> could not detect either importmap-rails or jsbundling-rails app"
42 | end
43 | end
44 | end
45 | end
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/dropzone_install_generator.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class DropzoneInstallGenerator < Rails::Generators::Base
3 | source_root File.expand_path('templates', __dir__)
4 |
5 | def filepath_prefix
6 | # todo: inject the context
7 | 'spec/dummy/' if $INTERNAL_SPECS
8 | end
9 |
10 |
11 | def initialize(*args) #:nodoc:
12 | super
13 | system("./bin/rails generate stimulus Dropzone")
14 | copy_file "javascript/dropzone_controller.js", "#{filepath_prefix}app/javascript/controllers/dropzone_controller.js"
15 | puts "HOT GLUE --> copying dropzone stimulus controller into app/javascript/controllers/dropzone_controller.js"
16 |
17 |
18 | if File.exist?("#{filepath_prefix}app/assets/stylesheets/application.bootstrap.scss")
19 | scss_file = "#{filepath_prefix}app/assets/stylesheets/application.bootstrap.scss"
20 | elsif File.exist?("#{filepath_prefix}app/assets/stylesheets/application.scss")
21 | scss_file = "#{filepath_prefix}app/assets/stylesheets/application.scss"
22 | else
23 | raise HotGlue::Error, "Could not detect your stylesheet, aborting..."
24 | end
25 |
26 | file_contents = File.read(scss_file)
27 |
28 | if !file_contents.include?("@import \"dropzone/dist/dropzone\"")
29 | file_contents << "\n@import \"dropzone/dist/dropzone\";\n@import \"dropzone/dist/basic\";"
30 |
31 |
32 | File.write(scss_file, file_contents)
33 | puts " HOTGLUE --> added to #{scss_file}: @import dropzone ... "
34 | else
35 | puts " HOTGLUE --> #{scss_file} already contains @import dropzone"
36 | end
37 | end
38 | end
39 | end
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/field_factory.rb:
--------------------------------------------------------------------------------
1 | require_relative "fields/association_field"
2 | require_relative "fields/boolean_field"
3 | require_relative "fields/date_field"
4 | require_relative "fields/date_time_field"
5 | require_relative "fields/enum_field"
6 | require_relative "fields/float_field"
7 | require_relative "fields/integer_field"
8 | require_relative "fields/string_field"
9 | require_relative "fields/text_field"
10 | require_relative "fields/time_field"
11 | require_relative "fields/uuid_field"
12 | require_relative "fields/attachment_field"
13 | require_relative "fields/related_set_field"
14 |
15 | class FieldFactory
16 | attr_accessor :field, :class_name
17 | def initialize(type: , name: , generator: )
18 | field_class = case type
19 | when :integer
20 | if name.to_s.ends_with?("_id")
21 | AssociationField
22 | else
23 | IntegerField
24 | end
25 | when :uuid
26 | UUIDField
27 | when :string
28 | StringField
29 | when :text
30 | TextField
31 | when :float
32 | FloatField
33 | when :decimal
34 | FloatField
35 | when :datetime
36 | DateTimeField
37 | when :date
38 | DateField
39 | when :time
40 | TimeField
41 | when :boolean
42 | BooleanField
43 | when :enum
44 | EnumField
45 | when :attachment
46 | AttachmentField
47 | when :related_set
48 | RelatedSetField
49 | end
50 | @class_name = class_name
51 |
52 | if field_class.nil?
53 | raise "Field type could be identified #{name} "
54 | end
55 |
56 | @field = field_class.new(scaffold: generator, name: name)
57 | # layout_strategy: generator.layout_strategy,
58 | # form_placeholder_labels: generator.form_placeholder_labels,
59 | # form_labels_position: generator.form_labels_position,
60 | # ownership_field: generator.ownership_field,
61 | # hawk_keys: generator.hawk_keys,
62 | # auth: generator.auth,
63 | # class_name: generator.singular_class,
64 | # alt_lookup: generator.alt_lookups[name] || nil,
65 | # singular: generator.singular,
66 | # self_auth: generator.self_auth,
67 | # update_show_only: generator.update_show_only,
68 | # attachment_data: generator.attachments[name.to_sym],
69 | # sample_file_path: generator.sample_file_path,
70 | # modify_as: generator.modify_as[name.to_sym] || nil,
71 | # plural: generator.plural,
72 | # display_as: generator.display_as[name.to_sym] || nil,
73 | # default_boolean_display: generator.default_boolean_display,
74 | # namespace: generator.namespace_value,
75 | # pundit: generator.pundit )
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/attachment_field.rb:
--------------------------------------------------------------------------------
1 | class AttachmentField < Field
2 | attr_accessor :attachment_data
3 | def initialize(scaffold:, name:)
4 | super
5 |
6 | @attachment_data = attachment_data
7 | end
8 |
9 | def spec_setup_let_arg
10 | nil
11 | end
12 |
13 | def spec_list_view_natural_assertion
14 | "within('div.#{singular}--#{name}') do
15 | img = page.find('img')
16 | expect(img['src']).to end_with('glass_button.png')
17 | end"
18 |
19 | # "expect(page).to have_content(#{singular}#{1}.#{name})"
20 | end
21 |
22 |
23 | def spec_setup_and_change_act(which_partial = nil)
24 | " attach_file(\"#{singular}[#{name.to_s}]\", \"#{sample_file_path}\")"
25 | end
26 |
27 | def thumbnail
28 | attachment_data[:thumbnail]
29 | end
30 |
31 | def form_field_output
32 | direct = attachment_data[:direct_upload]
33 | dropzone = attachment_data[:dropzone]
34 | field_result = (thumbnail ? "<%= #{singular}.#{name}.attached? ? image_tag(#{singular}.#{name}.variant(:#{thumbnail})) : '' %>" : "") +
35 | " \n" + (update_show_only.include?(name) ? "" : "<%= f.file_field :#{name} #{', direct_upload: true ' if direct}#{', "data-dropzone-target": "input"' if dropzone}%>")
36 |
37 | if dropzone
38 | field_result = "\n "+ field_result + "\n
"
39 | end
40 | return field_result
41 | end
42 |
43 | def line_field_output
44 | thumbnail = attachment_data[:thumbnail]
45 |
46 | (thumbnail ? "<%= #{singular}.#{name}.attached? ? image_tag(#{singular}.#{name}.variant(:#{thumbnail})) : '' %>" : "")
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/date_field.rb:
--------------------------------------------------------------------------------
1 | class DateField < Field
2 | def spec_setup_and_change_act(which_partial = nil)
3 | " " + "new_#{name} = Date.current + (rand(100).days) \n" +
4 | ' ' + "find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
5 | end
6 |
7 | def spec_setup_let_arg
8 | "#{name}: Date.current + rand(50).days"
9 | end
10 |
11 |
12 | def form_field_output
13 | parts = name.to_s.split('_')
14 | camelcase_name = parts.map(&:capitalize).join
15 | "<%= date_field_localized(f, :#{name}, #{singular}.#{name}, label: '#{ name.to_s.humanize }'" + (stimmify ? ", html: {'data-#{@stimmify}-target': '#{camelcase_name}'}" : "") + ") %>"
16 | end
17 |
18 | def line_field_output
19 | "<% unless #{singular}.#{name}.nil? %>
20 | <%= #{singular}.#{name} %>
21 | <% else %>
22 | MISSING
23 | <% end %>"
24 | end
25 |
26 | def search_field_output
27 | " "+
28 | "\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['is on', 'is_on'], " +
29 | "\n ['is between', 'is_between'], ['is on or after', 'is_on_or_after'], " +
30 | "\n ['is before or on', 'is_before_or_on'], ['not on', 'not_on']], @q[\'0\']['#{name}_match'] ), {} ," +
31 | "\n { class: 'form-control match', 'data-action': 'change->date-range-picker#matchSelection' } %>"+
32 | "\n <%= date_field_localized f, 'q[0][#{name}_search_start]', @q[\'0\'][:#{name}_search_start], autocomplete: 'off', size: 40, class: 'form-control', type: 'text', placeholder: 'start', 'data-date-range-picker-target': 'start' %>" +
33 | "\n <%= date_field_localized f, 'q[0][#{name}_search_end]', @q[\'0\'][:#{name}_search_end], autocomplete: 'off', size: 40, class: 'form-control', type: 'text', placeholder: 'end' , 'data-date-range-picker-target': 'end'%>" +
34 | "\n
"
35 | end
36 |
37 |
38 | def where_query_statement
39 | ".where(*#{name}_query)"
40 | end
41 |
42 | def load_all_query_statement
43 | "#{name}_query = date_query_constructor(:#{name}, @q['0'][:#{name}_match], @q['0'][:#{name}_search_start], @q['0'][:#{name}_search_end])"
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/date_time_field.rb:
--------------------------------------------------------------------------------
1 | class DateTimeField < Field
2 | def spec_random_data
3 | Time.now + rand(1..5).days
4 | end
5 |
6 |
7 | def form_show_only_output
8 | viewable_output
9 | end
10 |
11 |
12 | def spec_setup_and_change_act(which_partial = nil)
13 | " " + "new_#{name} = DateTime.current + 1.year \n" +
14 | ' ' + "find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
15 |
16 | end
17 |
18 | def spec_make_assertion
19 | if !modify_binary?
20 | "expect(page).to have_content(new_#{name}.in_time_zone(testing_timezone).strftime('%m/%d/%Y @ %l:%M %p %Z').gsub(' ', ' '))"
21 | else
22 | "expect(page).to have_content('#{modify_as[:binary][:truthy]}'"
23 | end
24 | end
25 |
26 | def spec_setup_let_arg
27 | "#{name}: DateTime.current + 1.day"
28 | end
29 |
30 | def spec_list_view_assertion
31 | if modify_binary?
32 | "expect(page).to have_content('#{modify_as[:binary][:truthy]}')"
33 | else
34 | spec_list_view_natural_assertion
35 | end
36 | end
37 |
38 | def spec_list_view_natural_assertion
39 | "expect(page).to have_content(#{singular}#{1}.#{name}.in_time_zone(testing_timezone).strftime('%m/%d/%Y @ %l:%M %p %Z').gsub(' ', ' '))"
40 | end
41 |
42 | def form_field_output
43 | "<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.in_time_zone(current_timezone), class: '#{@layout_strategy.form_input_class}' ) %><%= current_timezone %>"
44 | end
45 |
46 | def viewable_output
47 | if modify_binary?
48 | modified_display_output
49 | else
50 | "<% unless #{singular}.#{name}.nil? %>
51 | <%= #{singular}.#{name}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p %Z') %>
52 | <% else %>
53 | MISSING
54 | <% end %>"
55 | end
56 | end
57 |
58 |
59 |
60 |
61 | def search_field_output
62 | if !modify_binary?
63 |
64 | " "+
65 | "\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['is on', 'is_on'], " +
66 | "\n ['is between', 'is_between'], ['is on or after', 'is_on_or_after'], " +
67 | "\n ['is before or on', 'is_before_or_on'], ['not on', 'not_on']], @q[\'0\']['#{name}_match'] ), {} ," +
68 | "\n { class: 'form-control match', 'data-action': 'change->date-range-picker#matchSelection' } %>"+
69 | "\n <%= datetime_local_field 'q[0]', '#{name}_search_start', {value: @q[\'0\'][:#{name}_search_start], autocomplete: 'off', size: 40, class: 'form-control', placeholder: 'start', 'data-date-range-picker-target': 'start' } %>" +
70 | "\n <%= datetime_local_field 'q[0]', '#{name}_search_end', {value: @q[\'0\'][:#{name}_search_end], autocomplete: 'off', size: 40, class: 'form-control', placeholder: 'end' , 'data-date-range-picker-target': 'end' } %>" +
71 | "\n
"
72 | else
73 | " <%= f.radio_button('q[0][#{name}_match]', '-1', checked: @q[\'0\'][:#{name}_match]=='-1' ? 'checked' : '', class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
74 | " <%= f.label('All', value: '-1', for: 'q[0][#{name}_match]_-1' ) %>\n" +
75 | " <%= f.radio_button('q[0][#{name}_match]', '0', checked: @q[\'0\'][:#{name}_match]=='0' ? 'checked' : '', class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
76 | " <%= f.label('#{modify_as[:binary][:falsy]}', value: '0', for: 'q[0][#{name}_match]_0') %>\n" +
77 | " <%= f.radio_button('q[0][#{name}_match]', '1', checked: @q[\'0\'][:#{name}_match]=='1' ? 'checked' : '', class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
78 | " <%= f.label('#{modify_as[:binary][:truthy]}', value: '1', for: 'q[0][#{name}_match]_1') %>\n" +
79 | " "
80 | end
81 | end
82 |
83 |
84 | def where_query_statement
85 | ".where(#{name}_query)"
86 | end
87 |
88 | def load_all_query_statement
89 | if !modify_binary?
90 | "#{name}_query = date_query_constructor(:#{name}, @q['0'][:#{name}_match], @q['0'][:#{name}_search_start], @q['0'][:#{name}_search_end])"
91 | else
92 | "#{name}_query = boolean_modified_datetime_constructor(:#{name}, @q['0'][:#{name}_match])"
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/enum_field.rb:
--------------------------------------------------------------------------------
1 | class EnumField < Field
2 | def spec_setup_and_change_act(which_partial = nil)
3 | # what is the enum name
4 | " list_of_#{enum_type} = #{class_name}.defined_enums['#{name}'].keys \n" +
5 | " " + "new_#{name} = list_of_#{enum_type}[rand(list_of_#{enum_type}.length)].to_s \n" +
6 | ' find("select[name=\'' + singular + '[' + name + ']\'] option[value=\'#{new_' + name + '}\']").select_option'
7 | end
8 |
9 | def enum_type
10 | eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
11 | end
12 |
13 | def spec_make_assertion
14 | if(eval("#{class_name}.respond_to?(:#{name}_labels)"))
15 | "expect(page).to have_content(#{singular_class}.#{name}_labels[new_#{name}])"
16 | else
17 | "expect(page).to have_content(new_#{name})"
18 | end
19 | end
20 |
21 | def spec_setup_let_args
22 | super
23 | end
24 |
25 | def spec_list_view_assertion
26 | if(eval("#{class_name}.respond_to?(:#{name}_labels)"))
27 | "expect(page).to have_content(#{class_name}.#{name}_labels[#{singular}#{1}.#{name}])"
28 | else
29 | "expect(page).to have_content(#{singular}1.#{name})"
30 | end
31 | end
32 |
33 | def form_field_output
34 | if @stimmify
35 | col_target = HotGlue.to_camel_case(name.to_s.gsub("_", " "))
36 | data_attr = ", data: {'#{@stimmify}-target': '#{col_target}'} "
37 | end
38 |
39 | enum_type = eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
40 |
41 | if eval("defined? #{class_name}.#{enum_type}_labels") == "method"
42 | enum_definer = "#{class_name}.#{enum_type}_labels"
43 | else
44 | enum_definer = "#{class_name}.defined_enums['#{name}']"
45 | end
46 |
47 | res = "<%= f.collection_select(:#{name}, enum_to_collection_select(#{enum_definer}), :key, :value, {include_blank: true, selected: #{singular}.#{name} }, class: 'form-control' #{data_attr} )%>"
48 |
49 |
50 | if modify_as && modify_as[:enum] == :partials
51 | res << partial_render
52 | end
53 | res
54 | end
55 |
56 | def line_field_output
57 | enum_type = eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
58 |
59 | if eval("defined? #{class_name}.#{enum_type}_labels") == "method"
60 | enum_definer = "#{class_name}.#{enum_type}_labels"
61 | else
62 | enum_definer = "#{class_name}.defined_enums['#{name}']"
63 | end
64 |
65 | res = "
66 | <% if #{singular}.#{name}.nil? %>
67 | Missing #{name}
68 | <% else %>"
69 |
70 | if modify_as && modify_as[:enum] == :partials
71 | res << partial_render
72 | else
73 | res << "<%= #{enum_definer}[#{singular}.#{name}.to_sym] %>"
74 | end
75 |
76 | res << "<% end %>"
77 | res
78 | end
79 |
80 | def partial_render
81 | "<% if #{singular}.#{name} %><%= render partial: \"#{namespace + "/" if namespace}#{plural}/\#{#{singular}.#{name}}\", locals: { #{singular}: #{singular} } %><% end %>"
82 | end
83 |
84 |
85 | def form_show_only_output
86 | viewable_output
87 | end
88 |
89 |
90 | def search_field_output
91 | enum_type = eval("#{class_name}.columns.select{|x| x.name == '#{name}'}[0].sql_type")
92 | if eval("defined? #{class_name}.#{enum_type}_labels") == "method"
93 | enum_definer = "#{class_name}.#{enum_type}_labels"
94 | else
95 | enum_definer = "#{class_name}.defined_enums['#{name}']"
96 | end
97 |
98 | "<%= f.collection_select(\'q[0][#{name}_search]\', enum_to_collection_select(#{enum_definer}), :key, :value, {include_blank: true, selected: @q['0']['#{name}_search'] }, class: 'form-control') %>"
99 | end
100 |
101 |
102 | def where_query_statement
103 | ".where(*#{name}_query)"
104 | end
105 |
106 | def load_all_query_statement
107 | "#{name}_query = enum_constructor(:#{name}, @q['0'][:#{name}_search])"
108 | end
109 | end
110 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/float_field.rb:
--------------------------------------------------------------------------------
1 | class FloatField < Field
2 | def spec_setup_and_change_act(which_partial = nil)
3 | " " + "new_#{name} = rand(10) \n" +
4 | " find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
5 |
6 | end
7 |
8 |
9 | def spec_setup_let_arg
10 | "#{name}: rand(1)*10000"
11 | end
12 |
13 | def form_field_output
14 | field_output(nil, 5)
15 | end
16 |
17 | # def line_field_output
18 | # width = (limit && limit < 40) ? limit : (40)
19 | #
20 | # "<%= #{singular}.#{name} %>"
21 | # end
22 |
23 | def search_field_output
24 | ""
25 | end
26 |
27 |
28 | def where_query_statement
29 | end
30 |
31 | def load_all_query_statement
32 | raise "Float field search not implemented"
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/integer_field.rb:
--------------------------------------------------------------------------------
1 | class IntegerField < Field
2 | def spec_random_data
3 | rand(1...1000)
4 | end
5 |
6 | def spec_setup_and_change_act(which_partial = nil)
7 | if name.to_s.ends_with?("_id")
8 | capybara_block_for_association(name_name: name, which_partial: which_partial)
9 | else
10 | " new_#{name} = rand(10) \n" +
11 | " find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
12 | end
13 | end
14 |
15 | def spec_make_assertion
16 | "expect(page).to have_content(new_#{name})"
17 | end
18 |
19 | def spec_setup_let_arg
20 | "#{name}: rand(100)"
21 | end
22 |
23 | def spec_list_view_assertion
24 | "expect(page).to have_content(#{singular}#{1}.#{name})"
25 | end
26 |
27 | def form_field_output
28 | " <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: 4, class: 'form-control', type: 'number'" + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + " %>\n " + "\n"
29 | end
30 |
31 | def search_field_output
32 | " " +
33 | "\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['=', '='], " +
34 | "\n ['≥', '≥'], ['>', '>'], " +
35 | "\n ['≤', '≤'], ['<', '<']], @q[\'0\']['#{name}_match'] ), {} ," +
36 | "\n { class: 'form-control match' } %>"+
37 | "\n <%= f.text_field 'q[0][#{name}_search]', {value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 4, class: 'form-control', type: 'number'} %>" +
38 | "\n
"
39 | end
40 |
41 |
42 | def where_query_statement
43 | ".where(\"#{name} \#{#{name}_query }\")"
44 | end
45 |
46 | def load_all_query_statement
47 | "#{name}_query = integer_query_constructor(@q['0'][:#{name}_match], @q['0'][:#{name}_search])"
48 | end
49 |
50 | def code_to_reset_match_if_search_is_blank
51 | " @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
52 | end
53 |
54 | end
55 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/related_set_field.rb:
--------------------------------------------------------------------------------
1 | class RelatedSetField < Field
2 |
3 | attr_accessor :assoc_name, :assoc_class, :assoc
4 |
5 | def initialize( scaffold: , name: )
6 | super
7 |
8 | @related_set_model = eval("#{class_name}.reflect_on_association(:#{name})")
9 |
10 | if @related_set_model.nil?
11 | raise "You specified a related set #{name} but there is no association on #{singular_class} for #{name}; please add a `has_and_belongs_to_many :#{name}` OR a `has_many :#{name}, through: ...` to the #{singular_class} model"
12 |
13 | # exit_message = "*** Oops: The model #{class_name} is missing an association for :#{assoc_name} or the model #{assoc_name.titlecase} doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; or add to #{class_name} `belongs_to :#{assoc_name}`. To make a controller that can read all records, specify with --god."
14 | puts exit_message
15 | raise(HotGlue::Error, exit_message)
16 | end
17 |
18 | @assoc_class = eval(@related_set_model.try(:class_name))
19 |
20 | name_list = [:name, :to_label, :full_name, :display_name, :email]
21 |
22 | if assoc_class && name_list.collect{ |field|
23 | assoc_class.respond_to?(field.to_s) || assoc_class.instance_methods.include?(field)
24 | }.none?
25 | exit_message = "Oops: Missing a label for `#{assoc_class}`. Can't find any column to use as the display label for the #{@assoc_name} association on the #{class_name} model. TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name 5) email. You can implement any of these directly on your`#{assoc_class}` model (can be database fields or model methods) or alias them to field you want to use as your display label. Then RERUN THIS GENERATOR. (Field used will be chosen based on rank here.)"
26 | raise(HotGlue::Error, exit_message)
27 | end
28 |
29 | end
30 |
31 |
32 | def form_field_output
33 | disabled_syntax = +""
34 |
35 | if pundit
36 | disabled_syntax << ", {disabled: ! #{class_name}Policy.new(#{auth}, @#{singular}).role_ids_able?}"
37 | end
38 | " <%= f.collection_check_boxes :#{association_ids_method}, #{association_class_name}.all, :id, :label, {}#{disabled_syntax} do |m| %>
39 | <%= m.check_box %> <%= m.label %>
40 | <% end %>"
41 | end
42 |
43 | def association_ids_method
44 | eval("#{class_name}.reflect_on_association(:#{name})").class_name.underscore + "_ids"
45 | end
46 |
47 | def association_class_name
48 | eval("#{class_name}.reflect_on_association(:#{name})").class_name
49 | end
50 |
51 | def viewable_output
52 | "<%= #{singular}.#{name}.collect(&:label).join(\", \") %>"
53 | end
54 | end
55 |
56 |
57 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/string_field.rb:
--------------------------------------------------------------------------------
1 | class StringField < Field
2 | def spec_random_data
3 | FFaker::AnimalUS.common_name
4 | end
5 |
6 | def spec_setup_and_change_act(which_partial = nil)
7 | faker_string =
8 | if name.to_s.include?('email')
9 | "FFaker::Internet.email"
10 | elsif name.to_s.include?('domain')
11 | "FFaker::Internet.domain_name"
12 | elsif name.to_s.include?('ip_address') || name.to_s.ends_with?('_ip')
13 | "FFaker::Internet.ip_v4_address"
14 | else
15 | "FFaker::Movie.title"
16 | end
17 |
18 | return " " + "new_#{name} = #{faker_string} \n" +
19 | " find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
20 | end
21 |
22 | def spec_setup_let_arg
23 | if name.to_s.include?('email')
24 | "#{name}: FFaker::Internet.email"
25 | elsif name.to_s.include?('domain')
26 | "#{name}: FFaker::Internet.domain_name"
27 | elsif name.to_s.include?('ip_address') || name.to_s.ends_with?('_ip')
28 | "#{name}: FFaker::Internet.ip_v4_address"
29 | else
30 | "#{name}: FFaker::Movie.title"
31 | end
32 | end
33 |
34 | def form_field_output
35 | if sql_type == "varchar" || sql_type == "character varying"
36 | field_output(nil, limit || 40)
37 | else
38 | text_area_output( 65536)
39 | end
40 | end
41 |
42 | # TODO: dry with text_field.rb
43 | def text_result(col, sql_type, limit)
44 | if sql_type == "varchar"
45 | field_output( nil, limit)
46 | else
47 | text_area_output( 65536)
48 | end
49 | end
50 |
51 | def search_field_output
52 | "<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match' } %>"+
53 | "<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text' %>"
54 | end
55 |
56 |
57 | def where_query_statement
58 | ".where('#{name} ILIKE ?', #{name}_query)"
59 | end
60 |
61 | def load_all_query_statement
62 | "#{name}_query = string_query_constructor(@q['0'][:#{name}_match], @q['0'][:#{name}_search])"
63 | end
64 |
65 | def code_to_reset_match_if_search_is_blank
66 | " @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
67 | end
68 | end
69 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/text_field.rb:
--------------------------------------------------------------------------------
1 | class TextField < Field
2 | def spec_random_data
3 | FFaker::AnimalUS.common_name
4 | end
5 |
6 | def spec_setup_and_change_act(which_partial = nil)
7 | " " + "new_#{name} = FFaker::Lorem.paragraphs(1).join("") \n" +
8 | " find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
9 | end
10 |
11 | def spec_setup_let_arg
12 | "#{name}: FFaker::Lorem.paragraphs(10).join(" ")"
13 | end
14 |
15 | def form_field_output
16 | if sql_type == "varchar" || sql_type == "character varying"
17 | field_output( nil, limit || 40)
18 | else
19 | text_area_output( 65536, extra_classes: (modify_as == {tinymce: 1} ? " tinymce" : "" ))
20 | end
21 | end
22 |
23 | # TODO: dry with string_field.rb
24 | def text_result( sql_type, limit)
25 | if sql_type == "varchar"
26 | field_output( nil, limit)
27 | else
28 | text_area_output( 65536)
29 | end
30 | end
31 |
32 |
33 | def search_field_output
34 | "<%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['contains', 'contains'], ['is exactly', 'is_exactly'], ['starts with', 'starts_with'], ['ends with', 'ends_with']], @q[\'0\']['#{name}_match'] ), {} , { class: 'form-control match' } %>"+
35 | "<%= f.text_field 'q[0][#{name}_search]', value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 40, class: 'form-control', type: 'text' %>"
36 | end
37 |
38 |
39 | def where_query_statement
40 | ".where('#{name} ILIKE ?', #{name}_query)"
41 | end
42 |
43 | def load_all_query_statement
44 | "#{name}_query = string_query_constructor(@q['0'][:#{name}_match], @q['0'][:#{name}_search])"
45 | end
46 |
47 | def code_to_reset_match_if_search_is_blank
48 | " @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
49 | end
50 |
51 | end
52 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/time_field.rb:
--------------------------------------------------------------------------------
1 | class TimeField < Field
2 |
3 | def spec_setup_let_arg
4 | "#{name}: Time.current + rand(5000).seconds"
5 | end
6 |
7 | def form_field_output
8 | "<%= time_field_localized(f, :#{name}, #{singular}.#{name}, label: '#{ name.to_s.humanize }') %>"
9 | end
10 |
11 | def line_field_output
12 | "<% unless #{singular}.#{name}.nil? %>
13 | <%= #{singular}.#{name}.in_time_zone(current_timezone).strftime('%l:%M %p ') %>
14 | <% else %>
15 | MISSING
16 | <% end %>"
17 | end
18 |
19 | def spec_setup_and_change_act(which_partial = nil)
20 | " new_#{name} = Time.current + 5.seconds \n" +
21 | ' ' + "find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
22 |
23 | end
24 |
25 | def spec_make_assertion
26 | "expect(page).to have_content(new_#{name}.strftime('%l:%M %p').strip)"
27 | end
28 |
29 | def spec_list_view_assertion
30 | # "expect(page).to have_content(#{singular}#{1}.#{name})"
31 | end
32 |
33 | def search_field_output
34 | " "+
35 | "\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['is at exactly', 'is_at_exactly']], @q[\'0\']['#{name}_match']), {} ," +
36 | "\n { class: 'form-control match', 'data-action': 'change->time-range-picker#matchSelection' } %>"+
37 | "\n <%= time_field_localized f, 'q[0][#{name}_search_start]', @q[\'0\'][:#{name}_search_start], autocomplete: 'off', size: 40, class: 'form-control', type: 'text', placeholder: 'start', 'data-time-range-picker-target': 'start' %>" +
38 | "\n <%= time_field_localized f, 'q[0][#{name}_search_end]', @q[\'0\'][:#{name}_search_end], autocomplete: 'off', size: 40, class: 'form-control', type: 'text', placeholder: 'end' , 'data-time-range-picker-target': 'end' %>" +
39 | "\n
"
40 | end
41 |
42 |
43 | def where_query_statement
44 | ".where(*#{name}_query)"
45 | end
46 |
47 | def load_all_query_statement
48 | "#{name}_query = time_query_constructor(:#{name}, @q['0'][:#{name}_match], @q['0'][:#{name}_search_start], @q['0'][:#{name}_search_end])"
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/fields/uuid_field.rb:
--------------------------------------------------------------------------------
1 | class UUIDField < AssociationField
2 | def spec_setup_let_arg
3 | "#{name.to_s.gsub('_id','')}: #{name.to_s.gsub('_id','')}1"
4 | end
5 |
6 | def spec_list_view_assertion
7 | assoc_name = name.to_s.gsub('_id','')
8 | association = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
9 | "expect(page).to have_content(#{singular}#{1}.#{assoc_name}.#{HotGlue.derrive_reference_name(association.class_name)})"
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/flash_notices_install_generator.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class FlashNoticesInstallGenerator < Rails::Generators::Base
3 | source_root File.expand_path('templates', __dir__)
4 |
5 | def filepath_prefix
6 | # todo: inject the context
7 | 'spec/dummy/' if $INTERNAL_SPECS
8 | end
9 |
10 |
11 | def initialize(*args) #:nodoc:
12 | super
13 | copy_file "erb/_flash_notices.erb", "#{'spec/dummy/' if Rails.env.test?}app/views/layouts/_flash_notices.erb"
14 |
15 | end
16 | end
17 | end
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/hot_glue.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module HotGlue
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/layout_strategy/base.rb:
--------------------------------------------------------------------------------
1 | module LayoutStrategy
2 | class Base
3 | attr_accessor :builder
4 | def initialize(scaffold_builder)
5 | @builder = scaffold_builder
6 | end
7 |
8 | def button_applied_classes; end
9 | def column_classes_for_button_column; ""; end
10 | def button_classes; ""; end
11 | def button_column_style; "" ; end
12 | def button_style ; ""; end
13 | def column_headings_col_style; "" ; end
14 | def column_width; ""; end
15 | def column_classes_for_line_fields; ""; end
16 | def column_classes_for_form_fields; ""; end
17 | def column_classes_for_column_headings; ""; end
18 | def col_width; 100; end
19 | def container_name; ""; end
20 | def downnest_style ; ""; end
21 | def downnest_column_style ; "" ; end
22 | def each_col
23 | return col_width if builder.columns.count == 0
24 | (col_width/(builder.columns.count)).to_i
25 | end
26 | def list_classes; ""; end
27 | def magic_button_classes; ""; end
28 | def row_classes; ""; end
29 | def row_heading_classes; ""; end
30 | def page_begin; ' '; end
31 | def page_end ; '
'; end
32 | def style_with_flex_basis(x); "" ; end
33 | def form_checkbox_input_class; ""; end
34 | def form_checkbox_label_class; ""; end
35 | def form_checkbox_wrapper_class; ""; end
36 |
37 | def search_opening
38 | ""
39 | end
40 |
41 | def form_input_class
42 | ""
43 | end
44 |
45 | def search_closing
46 | ""
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/layout_strategy/bootstrap.rb:
--------------------------------------------------------------------------------
1 | class LayoutStrategy::Bootstrap < LayoutStrategy::Base
2 | def button_classes # column classes
3 | " " + "col-sm-#{builder.layout_object[:columns][:button_columns]}"
4 | end
5 |
6 | def button_applied_classes
7 | "btn btn-sm"
8 | end
9 |
10 | def magic_button_classes
11 | "btn-secondary"
12 | end
13 |
14 |
15 | def column_classes_for_button_column
16 | "col-md-#{builder.layout_object[:buttons][:size]}"
17 | end
18 |
19 |
20 | def column_classes_for_form_fields(size = nil)
21 | "col-md-#{size || builder.layout_object[:columns][:size_each]}"
22 | end
23 |
24 | def column_classes_for_column_headings(size = nil)
25 | column_classes_for_line_fields(size)
26 | end
27 |
28 | def container_name
29 | "container"
30 | end
31 |
32 | def column_classes_for_line_fields(size = nil)
33 | "col-sm-#{size || builder.layout_object[:columns][:size_each]}"
34 | end
35 |
36 | def column_width
37 | builder.layout_object[:columns][:size_each]
38 | end
39 |
40 | def downnest_portal_column_width(downnest)
41 | "col-sm-#{ builder.layout_object[:portals][downnest][:size] }"
42 | end
43 |
44 | def downnest_portal_stacked_column_width
45 | "col-sm-4"
46 | end
47 |
48 | def page_begin
49 | ' '
50 | end
51 |
52 | def row_classes
53 | "row hg-row"
54 | end
55 |
56 | def page_end
57 | '
'
58 | end
59 |
60 | def form_checkbox_input_class
61 | "form-check-input"
62 | end
63 |
64 | def form_checkbox_wrapper_class
65 | "form-check"
66 | end
67 |
68 | def form_checkbox_label_class
69 | "form-check-label"
70 | end
71 |
72 | def form_input_class
73 | "form-control"
74 | end
75 |
76 | def search_opening
77 | ''
78 | end
79 |
80 | def search_closing
81 | "
"
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/layout_strategy/hot_glue.rb:
--------------------------------------------------------------------------------
1 | class LayoutStrategy::HotGlue < LayoutStrategy::Base
2 | def button_column_style
3 | 'style="flex-basis: 150px'
4 | end
5 |
6 | def button_style
7 | 'style="flex-basis: ' + (100 - (column_width * builder.columns.count)).floor.to_s + '%;"'
8 | end
9 |
10 | def column_width
11 | each_col * builder.columns.count
12 | end
13 |
14 | def column_headings_col_style
15 | " style='flex-basis: #{column_width}%'"
16 | end
17 |
18 | def container_name
19 | "scaffold-container"
20 | end
21 |
22 | def downnest_column_style
23 | 'style="flex-basis: ' + each_downnest_width.to_s + '%;'
24 | end
25 |
26 | def downnest_style
27 | 'style="flex-basis: ' + each_downnest_width.to_s + '%"'
28 | end
29 |
30 | def each_downnest_width
31 | builder.downnest_children.count == 1 ? 33 : (53/builder.downnest_children.count).floor
32 | end
33 |
34 | def list_classes
35 | "scaffold-list"
36 | end
37 |
38 | def row_classes
39 | "scaffold-row"
40 | end
41 |
42 | def column_classes_for_form_fields(size = nil)
43 | "scaffold-cell"
44 | end
45 |
46 | def row_heading_classes
47 | "scaffold-heading-row"
48 | end
49 | def column_classes_for_line_fields(size = nil)
50 | "scaffold-cell"
51 | end
52 |
53 | def column_classes_for_column_headings(size = nil)
54 | "scaffold-cell"
55 | end
56 |
57 | def col_width
58 | downnest_size = case (builder.downnest_children.count)
59 | when 0
60 | downnest_size = 0
61 | when 1
62 | downnest_size = 40
63 |
64 | else
65 | downnest_size = 60
66 |
67 | end
68 | 100 - downnest_size - 5
69 | end
70 |
71 | def page_begin
72 | ''
73 | end
74 |
75 | def page_end
76 | '
'
77 | end
78 |
79 | def style_with_flex_basis(perc_width)
80 | " style='flex-basis: #{perc_width}%'"
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/layout_strategy/tailwind.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | class LayoutStrategy::Tailwind < LayoutStrategy::Base
4 | def button_classes; ""; end
5 | def button_column_style; "" ; end
6 | def button_style ; ""; end
7 | def column_headings_col_style; "" ; end
8 | def column_width; ""; end
9 | def column_classes_for_line_fields(size = nil); ""; end
10 | def column_classes_for_form_fields(size = nil); ""; end
11 | def column_classes_for_column_headings(size = nil); ""; end
12 | def col_width; 100; end
13 | def container_name; ""; end
14 | def downnest_style ; ""; end
15 | def downnest_column_style ; "" ; end
16 | def each_col
17 | return col_width if builder.columns.count == 0
18 | (col_width/(builder.columns.count)).to_i
19 | end
20 |
21 | def list_classes; "overflow-x-auto w-full"; end
22 | def row_classes; "grid grid-cols-4 gap-x-16 py-5 px-4 text-sm text-gray-700 border-b border-gray-200 dark:border-gray-700"; end
23 | def row_heading_classes; "grid grid-cols-4 gap-x-16 p-4 text-sm font-medium text-gray-900 bg-gray-100 border-t border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700 dark:text-white"; end
24 | def page_begin; ' '; end
25 | def page_end ; '
'; end
26 | def style_with_flex_basis(x); "" ; end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/markup_templates/base.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class TemplateBase
3 | def initialize(layout_strategy: )
4 | @layout_strategy = layout_strategy
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/nav_template_generator.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class NavTemplateGenerator < Rails::Generators::Base
3 | source_root File.expand_path('templates', __dir__)
4 | class_option :namespace, type: :string, default: nil
5 |
6 | def filepath_prefix
7 | # todo: inject the context
8 | 'spec/dummy/' if $INTERNAL_SPECS
9 | end
10 |
11 |
12 | def initialize(*args) #:nodoc:
13 | super
14 | @namespace = options['namespace']
15 | copy_file "erb/_nav.html.erb", "#{'spec/dummy/' if $INTERNAL_SPECS}app/views/#{@namespace ? @namespace + "/" : ""}_nav.html.erb"
16 |
17 | end
18 | end
19 | end
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/set_search_interface_install_generator.rb:
--------------------------------------------------------------------------------
1 |
2 |
3 | module HotGlue
4 | class SetSearchInterfaceInstallGenerator < Rails::Generators::Base
5 | source_root File.expand_path('templates', __dir__)
6 |
7 | def filepath_prefix
8 | # todo: inject the context
9 | 'spec/dummy/' if $INTERNAL_SPECS
10 | end
11 |
12 | def initialize(*args) #:nodoc:
13 | super
14 |
15 | ['date_range_picker','time_range_picker','search_form'].each do |file|
16 | system("./bin/rails generate stimulus #{file.titlecase.gsub(" ", "")}")
17 | copy_file "javascript/#{file}_controller.js", "#{filepath_prefix}app/javascript/controllers/#{file}.js"
18 | puts "HOT GLUE --> copying #{file} stimulus controller into app/javascript/controllers/#{file}.js"
19 |
20 | end
21 | end
22 | end
23 | end
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/base_controller.rb.erb:
--------------------------------------------------------------------------------
1 | class <%= controller_descends_from %> < ApplicationController
2 | end
3 |
4 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/capybara_login.rb:
--------------------------------------------------------------------------------
1 | def login_as(user)
2 | visit '/users/sign_in'
3 | within("#new_user") do
4 | fill_in 'Email', with: user.email
5 | fill_in 'Password', with: 'password'
6 | end
7 | click_button 'Log in'
8 | end
9 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/computer_code.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/lib/generators/hot_glue/templates/computer_code.jpg
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_edit.erb:
--------------------------------------------------------------------------------
1 | <\%= turbo_frame_tag "<%= @namespace %>__#{dom_id(<%= singular %>)}" do %>
2 |
3 | <\% if <%= singular %>.errors.any? %>
4 | <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
5 | <\% end %>
6 |
Editing <%= singular + " " if @include_object_names %><\%= <%= singular %>.<%= display_class %> %>
7 | <\%= form_with model: <%= singular %>,
8 | <% if @stimmify %> data: {controller: '<%= @stimmify %>' },
9 | <% end %>url: <%= form_path_edit_helper %><%= ", html: {'data-turbo': false}" if @big_edit %> do |f| %>
10 | <\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> \%>
11 | <% if @edit_within_form_partial %><\%= render partial: "edit_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
12 | <\% end %>
13 | <% if @edit_after_form_partial %><\%= render partial: "edit_after_form", locals: {<%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
14 |
15 | <\% end %>
16 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_flash_notices.erb:
--------------------------------------------------------------------------------
1 | <%= turbo_frame_tag "flash_notices" do %>
2 | <% unless notice.nil? && alert.nil? %>
3 |
4 |
<%= notice %>
5 |
<%= alert %>
6 | <% if defined?(resource) && resource %>
7 |
8 | <% resource.errors.full_messages.each do |message| %>
9 | <%= message %>
10 | <% end %>
11 |
12 | <% end %>
13 |
14 |
15 | <% end %>
16 | <% end %>
17 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_form.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= form_fields_html %>
3 |
4 |
5 | <\%= link_to "Cancel", <%=
6 | @nested_set.none? ? path_helper_plural : edit_parent_path_helper %>, {class: "btn btn-secondary"} %><% if @no_field_form %>
7 | <\%= f.hidden_field "_________" %><% end %>
8 | <\%= f.submit "Save", class: "btn btn-primary pull-right" %>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_line.erb:
--------------------------------------------------------------------------------
1 | <% if @turbo_streams %><\%= turbo_stream_from <%= singular %> %>
2 | <% end %><\%= turbo_frame_tag "<%= @namespace %>__#{ dom_id(<%= singular %>) }" do %>
3 |
4 | <\%= render partial: '<%= show_path_partial %>', locals: { <%= singular %>: <%= singular %><% if @nested_set.any? %>, <%= @nested_set.collect{|nest_arg| "#{nest_arg[:singular]}: #{ nest_arg[:singular] }"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|nest_arg| nest_arg[:singular] + "-\#{#{nest_arg[:singular]}.id}"}.join("__") %>"<% end %> } %>
5 |
6 | <\% end %>
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_list.erb:
--------------------------------------------------------------------------------
1 | <\%= turbo_frame_tag "<%= @namespace %>__<%= plural %>-list" <%= nested_for_turbo_id_list_constructor %> do %>
2 |
3 |
4 | <% unless @no_list || @no_list_label || (@nested_set.any? && !@nested_set.collect{|x| x[:optional]}.any?) %>
5 | <% unless list_label.nil? %>
6 | <%= list_label %>
7 | <% end %>
8 | <% end %>
9 |
10 | <% if @new_button_position == 'above' %>
11 | <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %>
<% end %>
12 | <% end %>
13 |
14 | <% unless @no_list %>
15 | <% unless @no_list_heading %>
16 |
17 | <%= list_column_headings %>
18 |
19 | <% if @downnest_object.any? && !@big_edit %>
20 | <% if !@stacked_downnesting %>
21 | <%= @layout_strategy.downnest_column_style %>
22 | <% @downnest_object.each do |downnest,i| %>
23 |
24 |
25 | <%= downnest.titleize %>
26 |
27 |
28 | <% end %>
29 | <% else %>
30 |
31 | <%= @layout_strategy.downnest_column_style %>
32 | <% @downnest_object.each do |downnest,i| %>
33 |
34 | <%= downnest.titleize %>
35 |
36 | <% end %>
37 |
38 | <% end %>
39 | <% end %>
40 |
41 | <% if @list_after_each_row_heading_partial %><\%= render partial: "list_after_each_row_heading" %><% end %>
42 |
43 |
>
44 |
45 |
46 | <% end %>
47 | <% if @search %>
48 | <%= @layout_strategy.search_opening %>
49 | <%= @template_builder.search_input_area %>
50 | <%= @layout_strategy.search_closing %>
51 | <% end %>
52 | <\% if <%= plural %>.empty? %>
53 |
54 | None
55 |
56 | <\% end %>
57 | <\% <%= plural %>.each do |<%= singular %>| %>
58 | <\%= render partial: '<%= line_path_partial %>', locals: {<%= singular %>: <%= singular %>}
59 | .merge(defined?(nested_for) ? {nested_for: nested_for} : {})
60 | <%= @nested_set.collect{|arg| " .merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join("\n") %>
61 | %>
62 | <\% end %>
63 | <% if @paginate_per_page_selector %>
64 | <\%= form_with url: '<%= path_helper_plural(top_level: false) %>', method: :get do |f| %>
65 | Show per page
66 | <\%= f.collection_select "per", [10, 25, 100], :to_s, :to_s, {prompt: true, selected: params[:per]}, {onChange: "this.form.submit();"} %>
67 | <\% end %>
68 | <% end %>
69 | <%= @no_paginate ? "" : paginate %>
70 | <% end %>
71 |
72 |
73 | <% if @new_button_position == 'below' %>
74 | <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %>
<% end %>
75 | <% end %>
76 |
77 | <\% end %>
78 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_nav.html.erb:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_new_button.erb:
--------------------------------------------------------------------------------
1 | <\%= turbo_frame_tag "<%= @namespace %>__<%= singular %>-new" do %>
2 |
3 | <\%= link_to "<%= @new_button_label %>", <%= new_path_name %>, disable_with: "Loading...", class: "new-<%= singular %>-button btn btn-primary pull-right <%= 'btn-sm' if @nested_set.any? %> " %>
4 |
5 | <\% end %>
6 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_new_form.erb:
--------------------------------------------------------------------------------
1 | <\%= turbo_frame_tag "<%= @namespace %>__<%= singular %>-new" do %>
2 |
3 | <%= @new_form_heading %>
4 |
5 | <\%= form_with model: <%= singular %>,
6 | <% if @stimmify %>data: {controller: '<%= @stimmify %>' },
7 | <% end %>url: <%= form_path_new_helper %>, method: :post<%= @display_edit_after_create ? ", html: {'data-turbo': false}" : "" %> do |f| \%>
8 | <\%= render partial: "<%= namespace_with_slash + @controller_build_folder %>/form",
9 | locals: { <%= singular %>: <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}}: {})" }.join %> \%>
10 |
11 | <% if @new_within_form_partial %><\%= render partial: "new_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
12 | <\% end %>
13 | <% if @new_after_form_partial %><\%= render partial: "new_after_form", locals: {<%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
14 | <\% end %>
15 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/_show.erb:
--------------------------------------------------------------------------------
1 | <%= all_line_fields %>
2 |
3 |
4 |
5 | <% if @downnest_children.any? && ! @big_edit %>
6 | <% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
7 | <% if @stacked_downnesting %><% end %>
8 | <% @downnest_object.each do |downnest, size| %>
9 | <% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
10 | <% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest}` found on `#{singular_class}`; please check relationship for has_many :#{downnest}"; end; %>
11 | <% downnest_class = downnest_object.class_name %>
12 | <% downnest_object_name = eval("#{downnest_class}.table_name") %>
13 | <% downnest_style = @layout_strategy.downnest_style %>
14 | <% if !@stacked_downnesting %>
><% end %>
15 | <% if @downnest_shows_headings %>
16 |
17 | <%= downnest_object_name.pluralize.humanize %>
18 |
19 | <% end %>
20 | <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
21 | <%= @singular %>: <%= @singular %>,
22 | <%= downnest_object_name %>: <%= @singular %>.<%= downnest %>
23 | }
24 | .merge({nested_for: "<% if @nested_set.any? %>#{nested_for + "__" if defined?(nested_for)}<% end %><%= @singular %>-#{<%= @singular %>.id}"})
25 | <%= @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {} )"}.join("\n") %>
26 | \%>
27 | <% if !@stacked_downnesting %><% end %>
28 | <% end %>
29 | <% if @stacked_downnesting %>
<% end %>
30 | <% end %>
31 |
32 |
33 | <% if @list_after_each_row_partial %><\%= render partial: "<%= namespace_with_trailing_dash %><%= @controller_build_folder %>/list_after_each_row", locals: {<%= @singular %>: <%= @singular %><% if @nested_set.any? %>, <%= @nested_set.collect{|x| x[:singular] + ": " + x[:singular] }.join(", ") %><% end %>} %>
34 | <% end %>
35 |
36 | <%= @layout_strategy.button_style %>
37 | >
38 | <%= magic_button_output %>
39 |
40 | <% if destroy_action %>
41 | <\%= form_with url: <%= delete_path_helper %>, html: {data: {'<%= @ujs_syntax ? 'confirm' : 'turbo-confirm' %>': "Are you sure you want to delete #{ <%= @singular + "." + display_class %> }?" }, style: "display: inline-block;"}, method: :delete do |f| %>
42 | <\%= f.submit "Delete".html_safe, class: "delete-<%= singular %>-button btn btn-primary btn-sm" %>
43 | <\% end %>
44 | <% end %>
45 |
46 | <% unless @no_edit %>
47 | <\%= link_to "Edit <% if @button_icons == 'font-awesome' %> <% end %>".html_safe, <%= edit_path_helper %>, <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary btn-sm" %>
48 | <% end %>
49 |
50 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/create.turbo_stream.erb:
--------------------------------------------------------------------------------
1 | <\% if @<%= singular %>.errors.none? %>
2 | <\%= turbo_stream.replace "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
3 | <\%= render partial: "list", locals: {<%= plural %>: @<%= plural %><% if @nested_set.any? %>, <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>, nested_for: '<%= @nested_set.collect{|arg| "\"#{arg[:singular]}-\#{@#{arg[:singular]}.id}\""}.join("__") %>' <% end %> } %>
4 |
5 | <\% end %>
6 | <\% end %>
7 |
8 | <%= turbo_parental_updates %>
9 |
10 | <\%= turbo_stream.replace "<%= @namespace %>__<%= singular %>-new" do %>
11 | <\% if @<%= singular %>.errors.none? %>
12 | <\%= render partial: "new_button", locals: {}<%= @nested_set.collect{|arg| ".merge(@" + arg[:singular] + " ? {" + arg[:singular] + ": @" + arg[:singular] + "} : {})"}.join() %> %>
13 | <\% else %>
14 | <\%= render partial: "new_form", locals: {<%= singular %>: @<%= singular %>}<%= @nested_set.collect{|arg| ".merge(@" + arg[:singular] + " ? {" + arg[:singular] + ": @" + arg[:singular] + "} : {})"}.join() %> %>
15 | <\% end %>
16 | <\% end %>
17 | <\%= turbo_stream.replace "flash_notices" do %>
18 | <\%= render partial: "layouts/flash_notices", locals: {resource: @<%= singular %>} %>
19 | <\% end %>
20 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/destroy.turbo_stream.erb:
--------------------------------------------------------------------------------
1 | <%= turbo_parental_updates %>
2 |
3 | <\%= turbo_stream.update "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
4 | <\%= render partial: "list", locals: {<%=plural%>: @<%=plural%> }<%= @nested_set.collect{|arg| ".merge(@" + arg[:singular] + " ? {nested_for: \"" + arg[:singular] + "-\#{@" + arg[:singular] + ".id}\"" + ", " + arg[:singular] + ": @" + arg[:singular] + "} : {})"}.join() %> \%>
5 | <\% end %>
6 |
7 | <\%= turbo_stream.update "flash_notices" do %>
8 | <\%= render partial: "layouts/flash_notices", locals: {resource: @<%= singular %>} %>
9 | <\% end %>
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/edit.erb:
--------------------------------------------------------------------------------
1 | <% if @big_edit %>
2 |
3 |
4 |
5 | <\%= link_to "<% if @button_icons == 'font-awesome' %> <% end %> Back to list".html_safe, <%= path_helper_plural(true) %> %>
6 | <% end %>
7 | <\%= render partial: "edit", locals: {<%= singular %>: @<%= singular %><%= @nested_set.any? ? ", " + (@nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") ) : "" %>} %>
8 | <% if @big_edit %>
9 |
10 |
11 |
12 |
13 |
14 |
15 | <% if @downnest_children.any? && @big_edit %>
16 |
17 |
" role="tablist">
18 | <% @downnest_object.each_with_index do |data,index| %>
19 | <% downnest = data[0] %>
20 |
21 | " id="<%= downnest %>-tab" data-bs-toggle="tab" data-bs-target="#<%= downnest %>-portal" type="button" role="tab" aria-controls="home" aria-selected="true">
22 | <%= downnest.titlecase.pluralize %>
23 |
24 |
25 | <% end %>
26 |
27 |
28 |
29 | <% @downnest_object.each_with_index do |data, index| %>
30 | <% downnest = data[0] %>
31 |
" id="<%= downnest %>-portal" role="tabpanel" aria-labelledby="<%= downnest %>-tab">
32 | <% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
33 | <% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest}` found on `#{singular_class}`; please check relationship for has_many :#{downnest}"; end; %>
34 | <% downnest_class = downnest_object.class_name %>
35 | <% downnest_object_name = eval("#{downnest_class}.table_name") %>
36 | <% downnest_style = @layout_strategy.downnest_style %>
37 |
38 | <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {<%= @singular %>: @<%= @singular %>, <%= downnest_object_name %>: @<%= @singular %>.<%= downnest %><% if @nested_set.any? %>, <%= @nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|x| "#{x[:singular]}-" + "\#{" + "@#{x[:singular]}.id}"}.join("__") %>__<%= singular %>-#{@<%= @singular %>.id}" <% end %> } \%>
39 |
40 | <% end %>
41 |
42 |
43 |
44 | <% end %>
45 |
46 |
47 | <% end %>
48 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/edit.turbo_stream.erb:
--------------------------------------------------------------------------------
1 | <\%= turbo_stream.replace "<%= @namespace %>__#{dom_id(@<%= singular %>)}" do %>
2 | <\%= render 'edit', locals: { <%= singular %>: @<%= singular %><%= @nested_set.collect{|arg| ", #{arg[:singular]}: @#{arg[:singular]} " }.join("") %> } %>
3 | <\% end %>
4 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/index.erb:
--------------------------------------------------------------------------------
1 | <% if @menu_file_exists %><\%= render partial: "<%= namespace_with_trailing_dash %>menu", locals: {active: '<%= plural %>'} %><% end %>
2 |
3 |
4 | <% if include_nav_template %><%= @layout_strategy.page_begin %><\%= render partial: "<%= nav_template %>", locals: {nav: "<%= @plural %>"} %><%= @layout_strategy.page_end %><% end %>
5 | <% if @index_before_list_partial %><\%= render partial: "index_before_list" %><% end %>
6 |
7 | <%= @layout_strategy.page_begin %>
8 | <\%= render partial: '<%= list_path_partial %>',
9 | locals: {<%= plural %>: @<%= plural %>}<%= @nested_set.collect{|arg| ".merge(@" + arg[:singular] + " ? {nested_for: \"" + arg[:singular] + "-\#{@" + arg[:singular] + ".id}\"" + ", " + arg[:singular] + ": @" + arg[:singular] + "} : {})"}.join() %> \%>
10 | <%= @layout_strategy.page_end %>
11 |
12 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/new.erb:
--------------------------------------------------------------------------------
1 | <\%= render partial: "new_form", locals: {<%= singular %>: @<%=singular%>}<%= @nested_set.collect{|arg| ".merge(@#{arg[:singular]} ? {#{arg[:singular]}: @#{arg[:singular]}} : {})" }.join %> %>
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/erb/update.turbo_stream.erb:
--------------------------------------------------------------------------------
1 | <% if !@display_list_after_update %><\%= turbo_stream.replace "<%= @namespace %>__#{dom_id(@<%= singular %>)}" do %>
2 | <\%= render partial: 'line', locals: {<%= singular %>: @<%= singular %>, <%= @nested_set.collect{|arg| " #{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %> } \%>
3 | <\% end %><% else %><\%= turbo_stream.replace "<%= plural %>-list" do %>
4 | <\%= render partial: '<%= list_path_partial %>', locals: {<%= plural %>: @<%= plural %><%= @nested_set.collect{|arg| " #{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>
5 | \%>
6 | <\% end %>
7 | <% end %>
8 |
9 | <%= turbo_parental_updates %>
10 |
11 | <\%= turbo_stream.update "flash_notices" do %>
12 | <\%= render partial: "layouts/flash_notices", locals: {resource: @<%= singular %>} %>
13 | <\% end %>
14 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/javascript/date_range_picker_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | // Connects to data-controller="date-range-picker"
4 | export default class extends Controller {
5 |
6 | static targets = [ "matchSelector", "start", "end" ];
7 | connect() {
8 |
9 | console.log("date_range_picker_controller.js connect.....")
10 | }
11 |
12 | matchSelection(event) {
13 |
14 | console.log("date_range_picker_controller.js matchSelection.....")
15 | console.log(event.target.value)
16 | // this.matchSelectorTarget.value = event.target.value
17 |
18 | switch(event.target.value) {
19 | case "is_on":
20 | this.startTarget.disabled = false
21 | this.endTarget.disabled = true
22 | this.endTarget.value = ""
23 | break;
24 | case "is_between":
25 | this.startTarget.disabled = false
26 | this.endTarget.disabled = false
27 | break;
28 | case "is_on_or_after":
29 | this.startTarget.disabled = false
30 | this.endTarget.disabled = true
31 | this.endTarget.value = ""
32 | break;
33 | case "is_before_or_on":
34 | this.startTarget.disabled = true
35 | this.startTarget.value = ""
36 | this.endTarget.disabled = false
37 | break;
38 | case "not_on":
39 | this.startTarget.disabled = false
40 | this.endTarget.disabled = true
41 | this.endTarget.value = ""
42 | break;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/javascript/search_form_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | // Connects to data-controller="search_form"
4 | export default class extends Controller {
5 | static targets = ["clearButton"];
6 |
7 | connect() {
8 |
9 | if (this.hasClearButtonTarget) {
10 | this.clearButtonTarget.addEventListener("click", (event) => {
11 | event.preventDefault()
12 | this.element.reset()
13 | })
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/javascript/time_range_picker_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | // Connects to data-controller="time-range-picker"
4 | export default class extends Controller {
5 | static targets = [ "matchSelector", "start", "end" ];
6 | connect() {
7 | console.log("time_range_picker_controller.js connect.....")
8 | }
9 |
10 | matchSelection(event) {
11 |
12 | console.log("time_range_picker_controller.js matchSelection.....")
13 | console.log(event.target.value)
14 | // this.matchSelectorTarget.value = event.target.value
15 |
16 | switch(event.target.value) {
17 | case "is_at":
18 | this.startTarget.disabled = false
19 | this.endTarget.disabled = true
20 | this.endTarget.value = ""
21 | break;
22 | case "is_between":
23 | this.startTarget.disabled = false
24 | this.endTarget.disabled = false
25 | break;
26 | case "is_at_or_after":
27 | this.startTarget.disabled = false
28 | this.endTarget.disabled = true
29 | this.endTarget.value = ""
30 | break;
31 | case "is_before_or_at":
32 | this.startTarget.disabled = true
33 | this.startTarget.value = ""
34 | this.endTarget.disabled = false
35 | break;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/system_spec.rb.erb:
--------------------------------------------------------------------------------
1 | <% item1_addOns = ""
2 | if (eval(@singular_class).instance_methods.include?(display_class.to_s))
3 | item1_addOns << "#{display_class}: FFaker::Name.name"
4 | end
5 | item1_addOns << ", \n " + @columns_map.collect{|col, col_object|
6 | col_object.spec_setup_let_arg
7 | }.compact.join(", \n ")
8 | %>require 'rails_helper'
9 |
10 | describe 'interaction for <%= controller_class_name %>' do
11 | include HotGlue::ControllerHelper
12 | include ActionView::RecordIdentifier
13 |
14 | <%= @existing_content %>
15 | <% unless @god %>let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<% end %>
16 | <%= spec_related_column_lets %>
17 | <% unless @self_auth %> let!(:<%= singular %>1) {
18 | <%= singular %> = create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> <%= item1_addOns %> )
19 | <%= @attachments.collect{ |attachment|
20 | " #{singular}.#{ attachment[0].to_s }.attach(
21 | io: File.open('spec/fixtures/glass_button.png'),
22 | filename: 'glass_button.png',
23 | content_type: 'image/png')"
24 | }.join("\n")
25 | %>
26 | <%=singular%>.save!
27 | <%=singular%>
28 | }<% end %>
29 | <%= objest_nest_factory_setup %> <% unless @god || (@existing_content && @existing_content.include?("login_as")) %>
30 | before do
31 | login_as(<%= @auth %>)
32 | end <% end %> <% if any_datetime_fields? %>
33 | let(:testing_timezone) {
34 | Rails.application.config.time_zone
35 | }<% end %>
36 | describe "index" do
37 | it "should show me the list" do
38 | visit <%= path_helper_plural %>
39 | <%= @columns_map.collect{|col, col_object| col_object.spec_list_view_assertion }.join("\n ") %>
40 | end
41 | end
42 |
43 | <% unless @no_create %> describe "new & create" do
44 | it "should create a new <%= singular.titlecase %>" do
45 | visit <%= path_helper_plural %>
46 | click_link "<%= @new_button_label %>"
47 | expect(page).to have_selector(:xpath, './/h3[contains(., "<%= @new_button_label %>")]')
48 | <%= capybara_make_updates(:create) %>
49 | click_button "Save"
50 | expect(page).to have_content("Successfully created")
51 |
52 | <%=" " + @columns_map.map{ |col, col_object|
53 | if @attachments.keys.collect(&:to_sym).include?(col)
54 | elsif @show_only.include?(col)
55 | else
56 | col_object.spec_make_assertion
57 | end
58 | }.compact.join("\n ")
59 | %>
60 | end
61 | end<% end %>
62 |
63 | <% unless @no_edit %>
64 | describe "edit & update" do
65 | it "should return an editable form" do
66 | visit <%= path_helper_plural %>
67 | find("a.edit-<%= singular %>-button[href='/<%= namespace_with_slash %><%= plural %>/#{<%= factory_testing_name %>.id}/edit']").click
68 |
69 | expect(page).to have_content("Editing #{<%= factory_testing_name %>.<%= @display_class %>.squish || "(no name)"}")
70 | <%= capybara_make_updates(:update) %>
71 | click_button "Save"
72 | within("turbo-frame#<%= @namespace %>__#{dom_id(<%= factory_testing_name %>)} ") do
73 | <%= " " + @columns_map.map{ |col, col_object|
74 | if @attachments.keys.collect(&:to_sym).include?(col)
75 | elsif @show_only.include?(col)
76 | else
77 | col_object.spec_make_assertion
78 | end
79 | }.compact.join("\n ")
80 | %>
81 | end
82 | end
83 | end <% end %><% if destroy_action %>
84 |
85 | describe "destroy" do
86 | it "should destroy" do
87 | visit <%= path_helper_plural %>
88 | accept_alert do
89 | find("form[action='<%= namespace_with_dash %>/<%= nested_path %><%= plural %>/#{<%= singular %>1.id}'] > input.delete-<%= singular %>-button").click
90 | end
91 | expect(page).to_not have_content(<%= singular %>1.<%= @display_class %>)
92 | expect(<%= singular_class %>.where(id: <%= singular %>1.id).count).to eq(0)
93 | end
94 | end<% end %>
95 | end
96 |
97 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/themes/hotglue_scaffold_dark_knight.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
3 | background-color: black;
4 | color: white;
5 |
6 | .alert.alert-danger {
7 | padding: 1em;
8 | border: solid 1px crimson;
9 | background-color: #ffd9d9;
10 | color: black;
11 | font-weight: bold;
12 | }
13 | }
14 |
15 | .scaffold-container {
16 |
17 |
18 |
19 |
20 | .cell input {
21 | -webkit-writing-mode: horizontal-tb !important;
22 | text-rendering: auto;
23 | letter-spacing: normal;
24 | word-spacing: normal;
25 | line-height: normal;
26 | text-transform: none;
27 | text-indent: 0px;
28 | text-shadow: none;
29 | display: inline-block;
30 | text-align: start;
31 | appearance: auto;
32 | -webkit-rtl-ordering: logical;
33 | margin: 0em;
34 | border-image: initial;
35 |
36 | display: block;
37 | padding: 0.375rem 0.75rem;
38 | font-size: 1rem;
39 | font-weight: 400;
40 | line-height: 1.5;
41 |
42 | background-clip: padding-box;
43 | border: 1px solid #ced4da;
44 | -webkit-appearance: none;
45 | -moz-appearance: none;
46 | appearance: none;
47 | border-radius: 0.25rem;
48 | transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
49 | color: #212529;
50 | background-clip: padding-box;
51 | border: 1px solid #ced4da;
52 | }
53 |
54 | .scaffold-row {
55 | .scaffold-col-heading {
56 | }
57 | .scaffold-col, .scaffold-col-heading {
58 |
59 | }
60 |
61 | .scaffold-cell {
62 | }
63 |
64 | .scaffold-list {
65 | flex: 0 0 auto;
66 | width: 100%;
67 | }
68 | }
69 |
70 | .container-fluid, .scaffold-container {
71 | width: 100%;
72 |
73 | margin-right: auto;
74 | margin-left: auto;
75 | }
76 |
77 | .row {
78 | display: flex;
79 | --bs-gutter-x: 1.5rem;
80 | --bs-gutter-y: 0;
81 | display: flex;
82 | flex-wrap: wrap;
83 |
84 | margin-top: calc(-1 * var(--bs-gutter-y));
85 | }
86 |
87 | .btn-primary {
88 | color: #212529;
89 |
90 | background-color: #4D889E;
91 | &:hover {
92 | color: #fff;
93 | border-color: #4D889E;
94 | }
95 | }
96 |
97 | .btn-secondary {
98 | color: white;
99 |
100 | background-color: darkgrey;
101 | &:hover {
102 | color: lightgrey;
103 | border-color: black;
104 | }
105 | }
106 |
107 | .scaffold-list {
108 | input, .btn {
109 | font-size: 0.8rem;
110 | font-weight: 400;
111 | line-height: 1.4;
112 | }
113 |
114 |
115 | .scaffold-list {
116 | input, .btn {
117 | font-size: 0.8rem;
118 | line-height: 1.2;
119 | }
120 |
121 |
122 |
123 | .scaffold-list {
124 | input, .btn {
125 | font-size: 0.55rem;
126 | line-height: 1.0;
127 | }
128 | }
129 | }
130 | }
131 |
132 |
133 | .btn {
134 | display: inline-block;
135 | font-weight: 400;
136 | line-height: 1.5;
137 | color: #212529;
138 | text-align: center;
139 | text-decoration: none;
140 | vertical-align: middle;
141 | cursor: pointer;
142 | -webkit-user-select: none;
143 | -moz-user-select: none;
144 | -ms-user-select: none;
145 | user-select: none;
146 | border: 1px solid transparent;
147 | padding: 0.375rem 0.75rem;
148 | font-size: 1rem;
149 | border-radius: 6px;
150 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
151 |
152 | box-shadow: 0px 0px 12px 2px whitesmoke;
153 | margin-right: 0.6em;
154 | }
155 |
156 |
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/themes/hotglue_scaffold_like_bootstrap.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
3 | background-color: white;
4 | color: darkslategrey;
5 |
6 | .alert.alert-danger {
7 | padding: 1em;
8 | border: 1px solid transparent;
9 | color: #721c24;
10 | background-color: #f8d7da;
11 | border-color: #f5c6cb;
12 | }
13 | }
14 |
15 |
16 | .scaffold-container {
17 | .cell input {
18 | -webkit-writing-mode: horizontal-tb !important;
19 | text-rendering: auto;
20 | letter-spacing: normal;
21 | word-spacing: normal;
22 | line-height: normal;
23 | text-transform: none;
24 | text-indent: 0px;
25 | text-shadow: none;
26 | display: inline-block;
27 | text-align: start;
28 | appearance: auto;
29 | -webkit-rtl-ordering: logical;
30 | margin: 0em;
31 | border-image: initial;
32 |
33 | display: block;
34 | padding: 0.375rem 0.75rem;
35 | font-size: 1rem;
36 | font-weight: 400;
37 | line-height: 1.5;
38 |
39 | background-color: #fff;
40 | background-clip: padding-box;
41 | border: 1px solid #ced4da;
42 | -webkit-appearance: none;
43 | -moz-appearance: none;
44 | appearance: none;
45 | border-radius: 0.25rem;
46 | transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
47 | color: #212529;
48 | background-color: #fff;
49 | background-clip: padding-box;
50 | border: 1px solid #ced4da;
51 | }
52 |
53 | .scaffold-row {
54 | .scaffold-col-heading {
55 | }
56 | .scaffold-col, .scaffold-col-heading {
57 |
58 | }
59 |
60 | .scaffold-cell {
61 | }
62 |
63 | .scaffold-list {
64 | flex: 0 0 auto;
65 | width: 100%;
66 | }
67 | }
68 |
69 | .container-fluid, .scaffold-container {
70 | width: 100%;
71 |
72 | margin-right: auto;
73 | margin-left: auto;
74 | }
75 |
76 | .row {
77 | display: flex;
78 | --bs-gutter-x: 1.5rem;
79 | --bs-gutter-y: 0;
80 | display: flex;
81 | flex-wrap: wrap;
82 |
83 | margin-top: calc(-1 * var(--bs-gutter-y));
84 | }
85 |
86 | .btn-primary {
87 | color: #212529;
88 |
89 | background-color: #0d6efd;
90 | &:hover {
91 | color: #fff;
92 | border-color: #0a58ca;
93 | }
94 | }
95 |
96 | .btn-secondary {
97 | color: white;
98 |
99 | background-color: darkgrey;
100 | &:hover {
101 | color: lightgrey;
102 | border-color: black;
103 | }
104 | }
105 |
106 | .scaffold-list {
107 | input, .btn {
108 | font-size: 0.8rem;
109 | font-weight: 400;
110 | line-height: 1.4;
111 | }
112 |
113 |
114 | .scaffold-list {
115 | input, .btn {
116 | font-size: 0.8rem;
117 | line-height: 1.2;
118 | }
119 |
120 |
121 |
122 | .scaffold-list {
123 | input, .btn {
124 | font-size: 0.55rem;
125 | line-height: 1.0;
126 | }
127 | }
128 | }
129 | }
130 |
131 |
132 | .btn {
133 | display: inline-block;
134 | font-weight: 400;
135 | line-height: 1.5;
136 | color: #212529;
137 | text-align: center;
138 | text-decoration: none;
139 | vertical-align: middle;
140 | cursor: pointer;
141 | -webkit-user-select: none;
142 | -moz-user-select: none;
143 | -ms-user-select: none;
144 | user-select: none;
145 | border: 1px solid transparent;
146 | padding: 0.375rem 0.75rem;
147 | font-size: 1rem;
148 | border-radius: 0.25rem;
149 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
150 | }
151 |
152 |
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/themes/hotglue_scaffold_like_los_gatos.scss:
--------------------------------------------------------------------------------
1 | .scaffold-container {
2 | -webkit-font-smoothing: antialiased;
3 | font-family: 'Netflix Sans','Helvetica Neue',Helvetica,Arial,sans-serif;
4 | color: #737373;
5 |
6 | font-size: .875rem;
7 | letter-spacing: .2px;
8 | input[type='submit'] {
9 | background-color: rgba(255,255,255,0);
10 | border: none;
11 | }
12 |
13 |
14 |
15 |
16 | .scaffold-cell {
17 | textarea {
18 |
19 | -webkit-box-sizing: border-box;
20 | box-sizing: border-box;
21 | margin: 1px!important;
22 | padding: 3px 1px 3px 3px;
23 | -webkit-transition: none;
24 | transition: none;
25 | }
26 |
27 | input {
28 | -webkit-writing-mode: horizontal-tb !important;
29 | text-rendering: auto;
30 | letter-spacing: normal;
31 | word-spacing: normal;
32 | line-height: normal;
33 | text-transform: none;
34 | text-indent: 0px;
35 | text-shadow: none;
36 | display: inline-block;
37 | text-align: start;
38 | appearance: auto;
39 | -webkit-rtl-ordering: logical;
40 | margin: 0em;
41 | border-image: initial;
42 |
43 | display: block;
44 | padding: 0.375rem 0.75rem;
45 | font-size: 1rem;
46 | font-weight: 400;
47 | line-height: 1.5;
48 |
49 | background-color: #fff;
50 | background-clip: padding-box;
51 | -webkit-appearance: none;
52 | -moz-appearance: none;
53 | appearance: none;
54 | border: 1px solid #ced4da;
55 | border-radius: 1px;
56 |
57 | transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
58 | color: #212529;
59 | background-color: #fff;
60 | background-clip: padding-box;
61 |
62 | &[type=submit] {
63 | border: none;
64 | border-radius: 0;
65 | }
66 | }
67 |
68 | input, textarea, select {
69 | &:hover {
70 | cursor: pointer;
71 | }
72 | background-color: #fff;
73 | color: #222;
74 |
75 | border: solid 1px #828282;
76 | border-radius: 2px;
77 |
78 |
79 | outline: none !important;
80 |
81 | box-shadow: none;
82 |
83 | &:focus, &:focus-visible {
84 |
85 | outline: none !important;
86 | }
87 | }
88 | }
89 |
90 |
91 | .scaffold-row {
92 | .scaffold-col-heading {
93 | }
94 | .scaffold-col, .scaffold-col-heading {
95 |
96 | }
97 |
98 | .scaffold-cell {
99 | }
100 |
101 | .scaffold-list {
102 | flex: 0 0 auto;
103 | width: 100%;
104 | }
105 | }
106 |
107 | .container-fluid, .scaffold-container {
108 | width: 100%;
109 |
110 | margin-right: auto;
111 | margin-left: auto;
112 | }
113 |
114 | .row {
115 | display: flex;
116 | --bs-gutter-x: 1.5rem;
117 | --bs-gutter-y: 0;
118 | flex-wrap: wrap;
119 | margin-top: calc(-1 * var(--bs-gutter-y));
120 | }
121 |
122 | .btn-primary {
123 | color: white;
124 | background-color: #e50914;
125 | border-radius: 2px;
126 | &:hover {
127 | color: darkslategrey;
128 | }
129 | }
130 |
131 | .btn-secondary {
132 | color: darkslategrey;
133 |
134 | background-color: white;
135 | &:hover {
136 | color: lightgrey;
137 | }
138 | }
139 |
140 | .scaffold-list {
141 | input, .btn {
142 | font-size: 0.8rem;
143 | font-weight: 400;
144 | line-height: 1.4;
145 | }
146 |
147 |
148 | .scaffold-list {
149 | input, .btn {
150 | font-size: 0.8rem;
151 | line-height: 1.2;
152 | }
153 |
154 |
155 |
156 | .scaffold-list {
157 | input, .btn {
158 | font-size: 0.55rem;
159 | line-height: 1.0;
160 | }
161 | }
162 | }
163 | }
164 |
165 | .btn {
166 | display: inline-block;
167 | font-weight: 400;
168 | line-height: 1.5;
169 | color: #212529;
170 | text-align: center;
171 | text-decoration: none;
172 | vertical-align: middle;
173 | cursor: pointer;
174 | -webkit-user-select: none;
175 | -moz-user-select: none;
176 | -ms-user-select: none;
177 | user-select: none;
178 | padding: 0.375rem 0.75rem;
179 | font-size: 1rem;
180 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_controller.rb.erb:
--------------------------------------------------------------------------------
1 | class <%= ((@namespace.titleize.gsub(" ", "") + "::" if @namespace) || "") + @plural.titleize.gsub(" ", "") + "TypeaheadController" %> < <%= controller_descends_from %>
2 | # regenerate this controller with
3 | <% if defined?(RuboCop) %># rubocop:disable Layout/LineLength
4 | <% end %># <%= regenerate_me_code %><% if defined?(RuboCop) %>
5 | # rubocop:enable Layout/LineLength <% end %>
6 |
7 |
8 | <% @nested_set.each do |nest| %>before_action :<%= nest[:singular] %>
9 | def <%= nest[:singular] %>
10 | @<%= nest[:singular] %> ||= current_user.accounts.find(params[:account_id])
11 | end
12 | <% end %>
13 |
14 | <% nest_chain = [] %>
15 | <% @nested_set.each { |arg|
16 | if @auth_identifier == arg[:singular]
17 | this_scope = auth_object
18 | elsif nest_chain.empty?
19 | this_scope = "#{@auth ? @auth : class_name}.#{arg[:plural]}"
20 | else
21 | this_scope = "#{nest_chain.last}.#{arg[:plural]}"
22 | end
23 | nest_chain << arg
24 | }%>
25 |
26 | def index
27 | <% if @pundit %>authorize <%= @class_name %>, :typeahead? <% end %>
28 | query = params[:query]
29 | @typeahead_identifier = params[:typeahead_identifier]
30 |
31 |
32 | <% if @nested_set.none? %>
33 | @<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
34 | <% else %>
35 | <% @nested_set.each do |arg| %>
36 | @<%= @plural %> = <%= @nested_set.last[:singular] %>.<%= @plural %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
37 | <% end %>
38 | <% end %>
39 | render layout: false
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_views/_thing.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <\%= <%= @singular %>.name %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_views/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | <\% if @<%= @plural %>.any? %>
8 | <\%= render partial: "<%= @singular %>", collection: @<%= @plural %> %>
9 | <\% else %>
10 | No results
11 | <\% end %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_views/typeahead.scss:
--------------------------------------------------------------------------------
1 | .typeahead {
2 |
3 | }
4 |
5 | .search__input {
6 | border: 1px solid gray;
7 | border-radius: 2px;
8 | padding: 10px;
9 | font-size: 16px;
10 | box-sizing: border-box;
11 | }
12 |
13 | [data-typeahead-target="results"] {
14 | position: absolute;
15 | }
16 |
17 | .search__results {
18 | border: 1px solid gray;
19 | border-radius: 2px;
20 | border-top: none;
21 | margin: 0;
22 | padding: 0;
23 | list-style-type: none;
24 | top: -1px;
25 | }
26 |
27 | .search__result {
28 | span.search-result-item {
29 | text-decoration: none;
30 | color: black;
31 | padding: 10px;
32 | display: block;
33 | cursor: pointer;
34 | &:hover {
35 | background: #86b7fe;
36 | }
37 | }
38 | }
39 |
40 | .search__result--current, .search__result:hover {
41 | background: #e0e0e0;
42 | }
43 |
44 | .search__result--empty {
45 | padding: 10px;
46 | }
47 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_views/typeahead_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | export default class extends Controller {
4 | static targets = [ "query", "results", "hiddenFormValue",
5 | "classIdentifier"]
6 | static values = { url: String }
7 | static outlets = [ "typeahead-results" ]
8 |
9 | disconnect() {
10 | this.reset()
11 | }
12 |
13 | fetchResults() {
14 |
15 |
16 | var typeaheadIdentifier = this.classIdentifierTarget.dataset.id
17 |
18 | if(this.query == "") {
19 | this.reset()
20 | return
21 | }
22 |
23 | if(this.query == this.previousQuery) {
24 | return
25 | }
26 | this.previousQuery = this.query
27 | const url = new URL(this.urlValue)
28 | url.searchParams.append("query", this.query)
29 | url.searchParams.append("typeahead_identifier", typeaheadIdentifier)
30 |
31 | this.abortPreviousFetchRequest()
32 |
33 | this.abortController = new AbortController()
34 |
35 | fetch(url, { signal: this.abortController.signal })
36 | .then(response => response.text())
37 | .then(html => {
38 | this.resultsTarget.innerHTML = html
39 | })
40 | .catch(() => {})
41 | }
42 |
43 | navigateResults(event) {
44 | if(this.hasSearchResultsOutlet) {
45 | this.searchResultsOutlet.navigateResults(event)
46 | }
47 | }
48 |
49 | // private
50 |
51 | reset() {
52 | this.resultsTarget.innerHTML = ""
53 | this.queryTarget.value = ""
54 | this.previousQuery = null
55 | }
56 |
57 | abortPreviousFetchRequest() {
58 | if(this.abortController) {
59 | this.abortController.abort()
60 | }
61 | }
62 |
63 | get query() {
64 | return this.queryTarget.value
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/templates/typeahead_views/typeahead_results_controller.js:
--------------------------------------------------------------------------------
1 | import { Controller } from "@hotwired/stimulus"
2 |
3 | const upKey = 38
4 | const downKey = 40
5 | const enterKey = 13
6 | const navigationKeys = [upKey, downKey, enterKey]
7 |
8 | export default class extends Controller {
9 | static classes = [ "current" ]
10 | static targets = [ "result" ]
11 | static outlets = [ "typeahead" ]
12 |
13 | connect() {
14 | this.currentResultIndex = 0
15 | const allElements = this.resultTarget.querySelectorAll(".search-result-item");
16 |
17 | allElements.forEach((element, index) => {
18 | element.addEventListener("click", () => {
19 | // Call the searchItemClicked member function when the element is clicked
20 | this.searchItemClicked(element, index);
21 | });
22 | })
23 | this.selectCurrentResult()
24 | }
25 |
26 | searchItemClicked(element, index) {
27 | const result_value = element.dataset.value;
28 | const result_id = element.dataset.id;
29 |
30 | // how to pass this to the search controller, set the field value and clear out the search
31 |
32 | this.typeaheadOutlets.forEach(outlet => {
33 | outlet.hiddenFormValueTarget.value = result_id;
34 | outlet.queryTarget.value = result_value;
35 | })
36 |
37 | this.resultTarget.innerHTML = "";
38 | }
39 |
40 | navigateResults(event) {
41 | if(!navigationKeys.includes(event.keyCode)) {
42 | return
43 | }
44 |
45 | event.preventDefault()
46 |
47 | switch(event.keyCode) {
48 | case downKey:
49 | this.selectNextResult()
50 | break;
51 | case upKey:
52 | this.selectPreviousResult()
53 | break;
54 | case enterKey:
55 | this.goToSelectedResult()
56 | break;
57 | }
58 | }
59 |
60 | // private
61 |
62 | selectCurrentResult() {
63 | this.resultTargets.forEach((element, index) => {
64 | element.classList.toggle(this.currentClass, index == this.currentResultIndex)
65 | })
66 | }
67 |
68 | selectNextResult() {
69 | if(this.currentResultIndex < this.resultTargets.length - 1) {
70 | this.currentResultIndex++
71 | this.selectCurrentResult()
72 | }
73 | }
74 |
75 | selectPreviousResult() {
76 | if(this.currentResultIndex > 0) {
77 | this.currentResultIndex--
78 | this.selectCurrentResult()
79 | }
80 | }
81 |
82 | goToSelectedResult() {
83 | this.resultTargets[this.currentResultIndex].firstElementChild.click()
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/lib/generators/hot_glue/typeahead_install_generator.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class TypeaheadInstallGenerator < Rails::Generators::Base
3 | source_root File.expand_path('templates', __dir__)
4 | class_option :namespace, type: :string, default: nil
5 |
6 | def filepath_prefix
7 | # todo: inject the context
8 | 'spec/dummy/' if $INTERNAL_SPECS
9 | end
10 |
11 |
12 | def initialize(*args) #:nodoc:
13 | super
14 |
15 | copy_file "typeahead_views/typeahead.scss", "#{'spec/dummy/' if $INTERNAL_SPECS}app/assets/stylesheets/typeahead.scss"
16 |
17 |
18 | try = ["application.scss", "application.bootstrap.scss"]
19 | try.each do |filename|
20 | main_scss_file = "#{'spec/dummy/' if $INTERNAL_SPECS}app/assets/stylesheets/#{filename}"
21 | if File.exist?(main_scss_file)
22 | insert_into_file main_scss_file do
23 | "@import 'typeahead';\n"
24 | end
25 | puts "Inserted @import 'typeahead'; into #{main_scss_file}"
26 | break
27 | else
28 | # puts "Could not find #{main_scss_file}. Please add the following line to your main scss file: @import 'typeahead';"
29 | end
30 | end
31 | copy_file "typeahead_views/typeahead_controller.js", "#{'spec/dummy/' if $INTERNAL_SPECS}app/javascript/controllers/typeahead_controller.js"
32 | copy_file "typeahead_views/typeahead_results_controller.js", "#{'spec/dummy/' if $INTERNAL_SPECS}app/javascript/controllers/typeahead_results_controller.js"
33 |
34 | system("bin/rails stimulus:manifest:update")
35 | end
36 | end
37 | end
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/hot-glue.rb:
--------------------------------------------------------------------------------
1 | require "hotglue/engine"
2 | require 'kaminari'
3 |
4 | module HotGlue
5 | module TemplateBuilders
6 |
7 | end
8 |
9 |
10 | class Error < StandardError
11 | end
12 |
13 |
14 | def self.to_camel_case(str)
15 | words = str.split(/[^a-zA-Z0-9]/) # split by non-alphanumeric characters
16 | return '' if words.empty?
17 |
18 | first_word = words.first.downcase
19 | rest_words = words[1..-1].map { |w| w.capitalize }
20 |
21 | first_word + rest_words.join
22 | end
23 |
24 |
25 | def self.construct_downnest_object(input)
26 | res = input.split(",").map { |child|
27 | child_name = child.gsub("+","")
28 | extra_size = child.count("+")
29 | {child_name => 4+extra_size}
30 | }
31 | Hash[*res.collect{|hash| hash.collect{|key,value| [key,value].flatten}.flatten}.flatten]
32 | end
33 |
34 | def self.optionalized_ternary(namespace: nil,
35 | target:,
36 | nested_set:,
37 | modifier: "",
38 | with_params: false,
39 | top_level: false,
40 | put_form: false,
41 | instance_last_item: false )
42 | instance_sym = top_level ? "@" : ""
43 |
44 |
45 | if nested_set.nil? || nested_set.empty?
46 | return modifier + "#{(namespace + '_') if namespace}#{target}_path" + (("(#{instance_sym}#{target})" if put_form) || "")
47 | elsif nested_set[0][:optional] == false
48 |
49 | res = modifier + ((namespace + "_" if namespace) || "") + nested_set.collect{|x|
50 | x[:singular] + "_"
51 | }.join() + target + "_path" + (("(#{nested_set.collect{
52 | |x| instance_sym + x[:singular] }.join(",")
53 | }#{ put_form ? ',' + (instance_last_item ? "@" : instance_sym) + target : '' })") || "")
54 |
55 | res
56 |
57 | else
58 | # copy the first item, make a ternery in this cycle, and recursively move to both the
59 | # is present path and the is optional path
60 |
61 | nonoptional = nested_set[0].dup
62 | nonoptional[:optional] = false
63 | rest_of_nest = nested_set[1..-1]
64 |
65 | is_present_path = HotGlue.optionalized_ternary(
66 | namespace: namespace,
67 | target: target,
68 | modifier: modifier,
69 | top_level: top_level,
70 | with_params: with_params,
71 | put_form: put_form,
72 | nested_set: [nonoptional, *rest_of_nest])
73 |
74 | is_missing_path = HotGlue.optionalized_ternary(
75 | namespace: namespace,
76 | target: target,
77 | modifier: modifier,
78 | top_level: top_level,
79 | with_params: with_params,
80 | put_form: put_form,
81 | nested_set: rest_of_nest )
82 | return "defined?(#{instance_sym + nested_set[0][:singular]}2) ? #{is_present_path} : #{is_missing_path}"
83 | end
84 | end
85 |
86 | def self.derrive_reference_name(thing_as_string)
87 | assoc_class = eval(thing_as_string)
88 |
89 | if assoc_class.new.respond_to?("name")
90 | display_column = "name"
91 | elsif assoc_class.new.respond_to?("to_label")
92 | display_column = "to_label"
93 | elsif assoc_class.new.respond_to?("full_name")
94 | display_column = "full_name"
95 | elsif assoc_class.new.respond_to?("display_name")
96 | display_column = "display_name"
97 | elsif assoc_class.new.respond_to?("email")
98 | display_column = "email"
99 | end
100 | display_column
101 | end
102 |
103 |
104 | end
105 |
106 |
--------------------------------------------------------------------------------
/lib/hotglue/engine.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class Engine < ::Rails::Engine
3 |
4 |
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/lib/hotglue/version.rb:
--------------------------------------------------------------------------------
1 | module HotGlue
2 | class Version
3 | CURRENT = '0.6.18'
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/script/clean_generated_code:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | rm dummy/app/controllers/ghis_controller.rb
3 | rm dummy/app/controllers/abcs_controller.rb
4 | rm dummy/app/controllers/dfgs_controller.rb
5 | rm dummy/app/controllers/cantelopes_controller.rb
6 | rm dummy/app/controllers/jkls_controller.rb
7 | rm dummy/app/controllers/users_controller.rb
8 | rm dummy/app/controllers/humans_controller.rb
9 | rm dummy/app/controllers/pets_controller.rb
10 |
11 |
12 | rm -rf dummy/app/views/cantelopes/*
13 | rm -rf dummy/app/views/jkls/*
14 | rm -rf dummy/app/views/ghis/*
15 | rm -rf dummy/app/views/abcs/*
16 | rm -rf dummy/app/views/dfgs/*
17 | rm -rf dummy/app/views/users/*
18 | rm -rf dummy/app/views/humans/*
19 | rm -rf dummy/app/views/pets/*
20 |
21 | /bin/rm -rf dummy/spec/features/
22 |
23 |
24 | # !("application_controller.rb"|"welcome_controller.rb")
25 | #find dummy/app/views/ -type f ! -name "application.html.erb" ! -name "welcome/index.erb" -delete
26 |
--------------------------------------------------------------------------------
/script/test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | clean_generated_code() {
4 | ./clean_generated_code
5 | }
6 |
7 | script/clean_generated_code
8 |
9 | echo "Integration test suite for Hot Glue..."
10 | echo "these specs generate several controllers & specs in the dummy app"
11 | echo "and then run the generated specs to test the generated code"
12 |
13 | cd dummy
14 |
15 | echo "Setting up database..."
16 |
17 | bundle install
18 | rake db:drop db:create db:migrate db:test:prepare
19 |
20 | echo "Generating all code for testing..."
21 | bin/rails generate hot_glue:scaffold Abc --gd
22 |
23 | bin/rails generate hot_glue:scaffold Ghi --gd
24 |
25 | bin/rails generate hot_glue:scaffold Dfg --auth=current_user
26 |
27 | bin/rails generate hot_glue:scaffold Fruits::Cantelope --gd
28 |
29 | bin/rails generate hot_glue:scaffold Pet --gd
30 |
31 | bin/rails generate hot_glue:scaffold Human --gd
32 |
33 |
34 | # why is only this one failing on CI
35 |
36 |
37 | #
38 | # 1) interaction for UsersController edit & update should return an editable form
39 | # Failure/Error: find("a.edit-user-button[href='/users/#{current_user.id}/edit']").click
40 | #
41 | # Capybara::ElementNotFound:
42 | # Unable to find css "a.edit-user-button[href='/users/14/edit']"
43 | # # ./spec/features/users_behavior_spec.rb:31:in `block (3 levels) in '
44 | #
45 | #Finished in 10.76 seconds (files took 2.69 seconds to load)
46 | #26 examples, 1 failure
47 |
48 | #bin/rails generate hot_glue:scaffold User --no-create --self-auth
49 |
50 |
51 | #rails generate hot_glue:scaffold Jkl --gd
52 | #rails generate hot_glue:scaffold Appointment --hawk=pets --gd
53 | #rails generate hot_glue:scaffold Family --gd
54 |
55 | # TODO: test these
56 | # --update-show-only
57 | # --alt-lookup-foreign-keys
58 | # --factory-creation
59 |
60 | rspec || exit
61 |
62 | cd ../
63 |
64 | script/clean_generated_code
65 |
66 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/abc.rb:
--------------------------------------------------------------------------------
1 | class Abc < ApplicationRecord
2 |
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/dfg.rb:
--------------------------------------------------------------------------------
1 | class Dfg < ApplicationRecord
2 | # can't use DEF as it is a Ruby Keyword
3 |
4 | belongs_to :user
5 | belongs_to :cantelope, class_name: "Fruits::Cantelope"
6 |
7 | has_many :ghis
8 |
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/spec/dummy/app/policies/dfg_policy.rb:
--------------------------------------------------------------------------------
1 | class DfgPolicy < ApplicationPolicy
2 | def initialize(user, record)
3 | @user = user
4 | @record = record
5 | end
6 |
7 | def name_able?
8 | @record.sent_at.nil?
9 | end
10 |
11 | def update?
12 | if !@user.is_admin?
13 | return false
14 | elsif record.name_changed? && !name_able?
15 | record.errors.add(:name, "cannot be changed.")
16 | return false
17 | else
18 | return true
19 | end
20 | end
21 |
22 | class Scope < Scope
23 | attr_reader :user, :scope
24 | def initialize(user, scope)
25 | @user = user
26 | @scope = scope
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/spec/dummy/config/hot_glue.yml:
--------------------------------------------------------------------------------
1 | ---
2 | :layout: hotglue
3 | :markup: erb
4 | :default_boolean_display: radio
5 |
--------------------------------------------------------------------------------
/spec/dummy/spec/files/computer_code.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hot-glue-for-rails/hot-glue/caf4d1ebfb456fdccfcfc5f1213aef2e0062cd52/spec/dummy/spec/files/computer_code.jpg
--------------------------------------------------------------------------------
/spec/dummy/spec/support/capybara_login.rb:
--------------------------------------------------------------------------------
1 | def login_as(user)
2 | visit '/users/sign_in'
3 | within("#new_user") do
4 | fill_in 'Email', with: user.email
5 | fill_in 'Password', with: 'password'
6 | end
7 | click_button 'Log in'
8 | end
9 |
--------------------------------------------------------------------------------
/spec/lib/generators/hot_glue/direct_upload_install_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 |
4 | describe HotGlue::DirectUploadInstallGenerator do
5 | # include GeneratorsTestHelper
6 |
7 | def setup
8 |
9 | end
10 |
11 | def teardown
12 |
13 | end
14 |
15 |
16 | describe "importmap" do
17 |
18 | describe "when app/javascript/application.js is empty" do
19 | before(:each) do
20 | File.write("spec/dummy/app/javascript/application.js", "")
21 | end
22 | # PASSES LOCALLY FAILS ON GITHUB ACTIONS
23 | # it "installs adds active storage to application.js " do
24 | # Rails::Generators.invoke("hot_glue:direct_upload_install")
25 | # res = File.read("spec/dummy/app/javascript/application.js")
26 | # expect(res).to include("//= require activestorage")
27 | # end
28 | end
29 |
30 |
31 | describe "when app/javascript/application.js already contains //= require activestorage" do
32 | before(:each) do
33 | File.write("spec/dummy/app/javascript/application.js", "//= require activestorage")
34 | end
35 | # PASSES LOCALLY, FAILS ON GITHUB ACTION
36 | # it "installs adds active storage to application.js " do
37 | # Rails::Generators.invoke("hot_glue:direct_upload_install")
38 | # res = File.read("spec/dummy/app/javascript/application.js")
39 | # expect(res.scan(/(?=#{"//= require activestorage"})/).count).to be(1)
40 | # end
41 | end
42 | end
43 |
44 | describe "jsbundling" do
45 |
46 | end
47 | end
48 |
49 |
50 |
--------------------------------------------------------------------------------
/spec/lib/generators/hot_glue/dropzone_install_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 |
4 | describe HotGlue::DropzoneInstallGenerator do
5 | after(:each) do
6 | File.delete("spec/dummy/app/assets/stylesheets/application.scss") if File.exists?("spec/dummy/app/assets/stylesheets/application.scss")
7 | File.delete("spec/dummy/app/assets/stylesheets/application.bootstrap.scss") if File.exists?("spec/dummy/app/assets/stylesheets/application.bootstrap.scss")
8 | end
9 |
10 | describe "bootstrap" do
11 | before(:each) do
12 | File.write("spec/dummy/app/assets/stylesheets/application.bootstrap.scss", "")
13 | end
14 | # PASSES LOCALLY, FAILS ON GITHUB ACTIONS
15 | # it "installs adds active storage to application.js " do
16 | # Rails::Generators.invoke("hot_glue:dropzone_install")
17 | # res = File.read("spec/dummy/app/javascript/controllers/dropzone_controller.js")
18 | # expect(res).to include("Dropzone")
19 | #
20 | # css = File.read("spec/dummy/app/assets/stylesheets/application.bootstrap.scss")
21 | # expect(css).to include("@import \"dropzone/dist/dropzone\"")
22 | # expect(css).to include("@import \"dropzone/dist/basic\"")
23 | # end
24 | end
25 |
26 | describe "no bootstrap" do
27 | before(:each) do
28 | File.write("spec/dummy/app/assets/stylesheets/application.scss", "")
29 | end
30 | # PASSES LOCALLY, FAILS ON GITHUB ACTIONS
31 | # it "installs adds active storage to application.js " do
32 | # Rails::Generators.invoke("hot_glue:dropzone_install")
33 | # res = File.read("spec/dummy/app/javascript/controllers/dropzone_controller.js")
34 | # expect(res).to include("Dropzone")
35 | #
36 | # css = File.read("spec/dummy/app/assets/stylesheets/application.scss")
37 | # expect(res).to include("import Dropzone from \"dropzone\";")
38 | # end
39 | end
40 |
41 |
42 | # PASSES LOCALLY, FAILS ON GITHUB ACTIONS
43 | # describe "can't detect stylesheet" do
44 | # before(:each) do
45 | #
46 | # end
47 | # it "installs adds active storage to application.js " do
48 | # expect{
49 | # Rails::Generators.invoke("hot_glue:dropzone_install")
50 | # }.to raise_exception(HotGlue::Error)
51 | # end
52 | # end
53 |
54 | describe "stylesheet already contains dropzone" do
55 | before(:each) do
56 | File.write("spec/dummy/app/assets/stylesheets/application.scss", "@import \"dropzone/dist/dropzone\"")
57 | end
58 | # PASSES LOCALLY, FAILS ON GITHUB ACTIONS
59 | # it "installs adds active storage to application.js " do
60 | # Rails::Generators.invoke("hot_glue:dropzone_install")
61 | # res = File.read("spec/dummy/app/javascript/controllers/dropzone_controller.js")
62 | # expect(res).to include("Dropzone")
63 | #
64 | # css = File.read("spec/dummy/app/assets/stylesheets/application.scss")
65 | #
66 | # expect(res.scan(/(?=#{"import Dropzone from \"dropzone\";"})/).count).to be(1)
67 | # end
68 | end
69 | end
70 |
71 |
72 |
--------------------------------------------------------------------------------
/spec/lib/generators/hot_glue/install_generator_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 |
4 | describe HotGlue::InstallGenerator do
5 | # include GeneratorsTestHelper
6 |
7 | def setup
8 |
9 | end
10 |
11 | def teardown
12 | end
13 |
14 |
15 | describe "css strategies" do
16 | it "should install correctly with bootstrap " do
17 | Rails::Generators.invoke("hot_glue:install", ["Ghi", "--layout=bootstrap"])
18 | res = File.read("spec/dummy/config/hot_glue.yml")
19 | end
20 |
21 | it "should install correctly with tailwind " do
22 | Rails::Generators.invoke("hot_glue:install", ["Ghi", "--layout=tailwind"])
23 | end
24 | end
25 |
26 | describe "with a theme " do
27 | it "should install correctly with hotglue layout syntax" do
28 | response = Rails::Generators.invoke("hot_glue:install --theme=dark_knight")
29 |
30 | end
31 | end
32 | end
33 |
34 |
35 |
--------------------------------------------------------------------------------
/spec/lib/helpers/hot_glue_helper_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper.rb'
2 |
3 | describe "HotGlueHelper" do
4 |
5 | class FakeController
6 | include HotGlueHelper
7 | end
8 | it "#enum_to_collection_select should take a hash" do
9 | controller = FakeController.new
10 |
11 | controller.enum_to_collection_select({4 => "a"})
12 |
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/lib/hot_glue/field_factory_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe FieldFactory do
4 | it "should make a new filed " do
5 | ff = FieldFactory.new(type: :integer,
6 | name: "how_many",
7 | generator: OpenStruct.new({
8 | modify_as: {},
9 | display_as: {},
10 | default_boolean_display: 'radio',
11 | form_labels_position: nil,
12 | singular_class: "Hgi",
13 | layout_strategy: nil,
14 | form_placeholder_labels: false,
15 | ownership_field: nil,
16 | hawk_keys: nil,
17 | auth: nil,
18 | attachment_data: nil,
19 | sample_file_path: nil,
20 | class_name: "Abc",
21 | alt_lookups: {},
22 | singular: "abc",
23 | update_show_only: [],
24 | attachments: {}
25 | }))
26 |
27 | expect(ff.field).to be_a(IntegerField)
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/spec/lib/hot_glue/hot_glue_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | describe HotGlue do
4 |
5 | describe "#construct_downnest_object" do
6 |
7 | it "should work when passed nothing" do
8 | res = HotGlue.construct_downnest_object("")
9 | expect(res).to eq({})
10 | end
11 |
12 | it "should work when passed one downnested" do
13 | res = HotGlue.construct_downnest_object("abc")
14 | expect(res).to eq({"abc"=>4})
15 | end
16 |
17 | it "should work when passed two downnested" do
18 | res = HotGlue.construct_downnest_object("abc,def")
19 | expect(res).to eq({"abc"=>4,"def"=>4})
20 | end
21 |
22 | it "should work when passed two downnested" do
23 | res = HotGlue.construct_downnest_object("abc+,def")
24 | expect(res).to eq({"abc"=>5,"def"=>4})
25 | end
26 |
27 | it "should work when passed two downnested" do
28 | res = HotGlue.construct_downnest_object("abc,def+")
29 | expect(res).to eq({"abc"=>4,"def"=>5})
30 | end
31 | end
32 |
33 |
34 |
35 | describe "#optionalized_ternary" do
36 |
37 | describe "when the first parent is optional" do
38 | it "should work for a one-level nest" do
39 | target = 'invoices'
40 | nested_set = [
41 | {singular: 'account', optional: true, plural: 'accounts'}
42 | ]
43 |
44 | result = HotGlue.optionalized_ternary(target: 'invoices',
45 | nested_set: nested_set,
46 | namespace: "admin")
47 | # expect(result).to eq("defined?(account) ? admin_account_invoices_path : admin_invoices_path")
48 | end
49 | end
50 |
51 | describe "for non-optional" do
52 | it "should work for a one-level nest" do
53 | target = 'invoices'
54 | nested_set = [
55 | {singular: 'account', optional: false, plural: 'accounts'}
56 | ]
57 |
58 | result = HotGlue.optionalized_ternary(target: 'invoices',
59 | nested_set: nested_set,
60 | namespace: "admin")
61 | expect(result).to eq("admin_account_invoices_path(account)")
62 | end
63 |
64 |
65 | it "should work for a two-level nest" do
66 |
67 | end
68 |
69 | it "should work for a three-level nest" do
70 |
71 | end
72 | end
73 | end
74 |
75 |
76 | describe "for two level optional" do
77 |
78 | end
79 |
80 | describe "with top level" do
81 |
82 | end
83 |
84 | describe "namespace" do
85 |
86 | end
87 |
88 | describe "modifier" do
89 |
90 | end
91 |
92 | describe "with_params" do
93 |
94 | end
95 |
96 | describe "top_level" do
97 |
98 | end
99 | end
100 |
--------------------------------------------------------------------------------
/spec/lib/hot_glue/version_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper.rb"
2 |
3 |
4 | describe HotGlue::Version do
5 | before(:each) do
6 | @version = HotGlue::Version::CURRENT
7 | end
8 |
9 | it "should be a major- syntax" do
10 | @version = HotGlue::Version::CURRENT
11 | split = @version.split(".").collect(&:to_i)
12 | expect(split[0]).to be_kind_of(Numeric)
13 | end
14 | it "should be a point- syntax" do
15 | split = @version.split(".").collect(&:to_i)
16 | expect(split[1]).to be_kind_of(Numeric)
17 | end
18 |
19 | it "should be a minor- syntax" do
20 | split = @version.split(".").collect(&:to_i)
21 | expect(split[2]).to be_kind_of(Numeric)
22 | end
23 |
24 | it "should be before version 1 " do
25 | split = @version.split(".").collect(&:to_i)
26 | expect(split[0]).to be(0)
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/lib/hot_glue_spec.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'spec_helper.rb'
3 |
4 |
5 |
6 | describe HotGlue do
7 | context("#configure") do
8 | it "should assert true" do
9 | expect(true).to be(true)
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | ENV['RAILS_ENV'] ||= 'test'
2 | require 'spec_helper'
3 | require 'byebug'
4 |
5 |
6 | # require File.expand_path('../../config/environment', __FILE__)
7 | require 'rspec/rails'
8 | # require 'database_cleaner'
9 | require 'factory_bot'
10 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
11 |
12 | ActiveRecord::Migration.maintain_test_schema!
13 |
14 | RSpec.configure do |config|
15 |
16 | config.include FactoryBot::Syntax::Methods
17 |
18 | # config.use_transactional_fixtures = false
19 |
20 | # config.before(:suite) do
21 | # DatabaseCleaner.clean_with(:truncation)
22 | # end
23 | #
24 | config.before(:each) do
25 | $INTERNAL_SPECS = true
26 | end
27 |
28 | # config.before(:each, js: true) do
29 | # DatabaseCleaner.strategy = :truncation
30 | # end
31 | # config.before(:each) do
32 | # DatabaseCleaner.start
33 | # end
34 |
35 | config.after(:each) do
36 | $INTERNAL_SPECS = false
37 | end
38 |
39 | # config.before(:all) do
40 | # DatabaseCleaner.start
41 | # end
42 | # config.after(:all) do
43 | # DatabaseCleaner.clean
44 | # end
45 | config.infer_spec_type_from_file_location!
46 | end
47 |
48 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] ||= "test"
2 | # require 'byebug'
3 |
4 | require 'simplecov'
5 | require 'simplecov-rcov'
6 | class SimpleCov::Formatter::MergedFormatter
7 | def format(result)
8 | SimpleCov::Formatter::HTMLFormatter.new.format(result)
9 | SimpleCov::Formatter::RcovFormatter.new.format(result)
10 | end
11 | end
12 | SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
13 | SimpleCov.start 'rails' do
14 | add_filter "/vendor/"
15 | add_filter "/test/"
16 | add_filter "/dummy/"
17 | add_filter "lib/hotglue/version.rb"
18 | add_filter "lib/generators/hot_glue/templates/capybara_login.rb"
19 | end
20 |
21 | require "rails/all"
22 | require 'rails/generators'
23 | require './lib/hot-glue.rb'
24 |
25 | # require the gem's core code
26 | Dir["./lib/**/*.rb"].each do |x|
27 | require(x)
28 | end
29 |
30 | require_relative "../dummy/config/application.rb"
31 | require "rspec/rails"
32 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
33 |
34 | # https://stackoverflow.com/questions/76319469/when-i-switch-my-rails-open-source-engine-to-postgres-for-testing-i-get-cant
35 | #
36 | # begin
37 | Dummy::Application.initialize!
38 | # rescue
39 | # end
40 |
41 |
42 | RSpec.configure do |config|
43 | config.infer_spec_type_from_file_location!
44 | config.order = :random
45 | config.use_transactional_fixtures = true
46 |
47 | config.expect_with :rspec do |expectations|
48 | expectations.syntax = :expect
49 | end
50 |
51 | config.mock_with :rspec do |mocks|
52 | mocks.syntax = :expect
53 | end
54 |
55 | config.before {
56 | restore_default_warning_free_config
57 | }
58 | end
59 |
60 | def restore_default_warning_free_config
61 |
62 | end
63 |
--------------------------------------------------------------------------------