shoelace-rails 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +11 -61
  3. data/.gitignore +1 -6
  4. data/Appraisals +6 -0
  5. data/CHANGELOG.md +16 -5
  6. data/Gemfile +0 -3
  7. data/Rakefile +2 -17
  8. data/app/helpers/shoelace/form_helper.rb +38 -2
  9. data/gemfiles/rails_60.gemfile +0 -1
  10. data/gemfiles/rails_61.gemfile +0 -1
  11. data/gemfiles/rails_70.gemfile +0 -1
  12. data/gemfiles/rails_71.gemfile +10 -0
  13. data/gemfiles/rails_edge.gemfile +0 -1
  14. data/lib/shoelace/rails/version.rb +1 -1
  15. data/shoelace-rails.gemspec +1 -1
  16. data/test/helpers/form_helper_test.rb +39 -10
  17. metadata +6 -58
  18. data/dist/.keep +0 -0
  19. data/dist/types/.keep +0 -0
  20. data/package.json +0 -50
  21. data/rollup.config.js +0 -49
  22. data/src/index.ts +0 -2
  23. data/src/turbo/index.ts +0 -6
  24. data/src/turbo/polyfills/formdata-event.js +0 -27
  25. data/src/turbo/sl-turbo-form.ts +0 -110
  26. data/src/turbolinks/features/confirm.ts +0 -42
  27. data/src/turbolinks/features/disable.ts +0 -94
  28. data/src/turbolinks/features/remote.ts +0 -107
  29. data/src/turbolinks/index.ts +0 -6
  30. data/src/turbolinks/selectors.ts +0 -38
  31. data/src/turbolinks/start.ts +0 -38
  32. data/src/turbolinks/turbolinks.ts +0 -78
  33. data/src/turbolinks/utils/ajax.ts +0 -146
  34. data/src/turbolinks/utils/csp.ts +0 -20
  35. data/src/turbolinks/utils/csrf.ts +0 -33
  36. data/src/turbolinks/utils/dom.ts +0 -40
  37. data/src/turbolinks/utils/event.ts +0 -57
  38. data/src/turbolinks/utils/form.ts +0 -58
  39. data/test/dummy_app/Gemfile +0 -19
  40. data/test/dummy_app/Rakefile +0 -6
  41. data/test/dummy_app/app/controllers/hotwire_forms_controller.rb +0 -46
  42. data/test/dummy_app/app/controllers/turbolinks_forms_controller.rb +0 -37
  43. data/test/dummy_app/app/models/user.rb +0 -16
  44. data/test/dummy_app/app/packs/entrypoints/hotwire.js +0 -1
  45. data/test/dummy_app/app/packs/entrypoints/turbolinks.js +0 -5
  46. data/test/dummy_app/app/views/hotwire_forms/form.html.erb +0 -45
  47. data/test/dummy_app/app/views/hotwire_forms/show.html.erb +0 -5
  48. data/test/dummy_app/app/views/layouts/application.html.erb +0 -39
  49. data/test/dummy_app/app/views/turbolinks_forms/form.html.erb +0 -44
  50. data/test/dummy_app/app/views/turbolinks_forms/show.html.erb +0 -5
  51. data/test/dummy_app/bin/rails +0 -5
  52. data/test/dummy_app/bin/webpack +0 -18
  53. data/test/dummy_app/bin/yarn +0 -18
  54. data/test/dummy_app/config/application.rb +0 -16
  55. data/test/dummy_app/config/boot.rb +0 -4
  56. data/test/dummy_app/config/environment.rb +0 -2
  57. data/test/dummy_app/config/environments/development.rb +0 -10
  58. data/test/dummy_app/config/environments/test.rb +0 -18
  59. data/test/dummy_app/config/routes.rb +0 -4
  60. data/test/dummy_app/config/webpack/development.js +0 -5
  61. data/test/dummy_app/config/webpack/production.js +0 -1
  62. data/test/dummy_app/config/webpack/test.js +0 -5
  63. data/test/dummy_app/config/webpacker.yml +0 -33
  64. data/test/dummy_app/config.ru +0 -6
  65. data/test/dummy_app/package.json +0 -24
  66. data/test/dummy_app/test/system/hotwire_form_test.rb +0 -63
  67. data/test/dummy_app/test/system/turbolinks_form_test.rb +0 -38
  68. data/test/dummy_app/test/test_helper.rb +0 -68
  69. data/tsconfig.json +0 -19
  70. data/yarn.lock +0 -249
@@ -1,146 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { cspNonce } from "./csp"
4
- import { CSRFProtection } from "./csrf"
5
-
6
- const AcceptHeaders = {
7
- "*": "*/*",
8
- text: "text/plain",
9
- html: "text/html",
10
- xml: "application/xml, text/xml",
11
- json: "application/json, text/javascript",
12
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript",
13
- }
14
-
15
- export const ajax = (options) => {
16
- options = prepareOptions(options)
17
- var xhr = createXHR(options, function () {
18
- const response = processResponse(
19
- xhr.response != null ? xhr.response : xhr.responseText,
20
- xhr.getResponseHeader("Content-Type")
21
- )
22
-
23
- if (Math.floor(xhr.status / 100) === 2) {
24
- if (typeof options.success === "function") {
25
- options.success(response, xhr.statusText, xhr)
26
- }
27
- } else {
28
- if (typeof options.error === "function") {
29
- options.error(response, xhr.statusText, xhr)
30
- }
31
- }
32
- return typeof options.complete === "function" ? options.complete(xhr, xhr.statusText) : undefined
33
- })
34
-
35
- if (options.beforeSend != null && !options.beforeSend(xhr, options)) {
36
- return false
37
- }
38
-
39
- if (xhr.readyState === XMLHttpRequest.OPENED) {
40
- return xhr.send(options.data)
41
- }
42
- }
43
-
44
- const prepareOptions = (options) => {
45
- options.url = options.url || location.href
46
- options.type = options.type.toUpperCase()
47
- // append data to url if it's a GET request
48
- if (options.type === "GET" && options.data) {
49
- if (options.url.indexOf("?") < 0) {
50
- options.url += "?" + options.data
51
- } else {
52
- options.url += "&" + options.data
53
- }
54
- }
55
-
56
- // Use "*" as default dataType
57
- if (AcceptHeaders[options.dataType] == null) {
58
- options.dataType = "*"
59
- }
60
-
61
- options.accept = AcceptHeaders[options.dataType]
62
- if (options.dataType !== "*") {
63
- options.accept += ", */*; q=0.01"
64
- }
65
-
66
- return options
67
- }
68
-
69
- const createXHR = (options, done) => {
70
- const xhr = new XMLHttpRequest()
71
-
72
- // Open and set up xhr
73
- xhr.open(options.type, options.url, true)
74
- xhr.setRequestHeader("Accept", options.accept)
75
-
76
- // Set Content-Type only when sending a string
77
- // Sending FormData will automatically set Content-Type to multipart/form-data
78
- if (typeof options.data === "string") {
79
- xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
80
- }
81
-
82
- if (!options.crossDomain) {
83
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
84
- CSRFProtection(xhr)
85
- }
86
-
87
- xhr.withCredentials = !!options.withCredentials
88
- xhr.onreadystatechange = function () {
89
- if (xhr.readyState === XMLHttpRequest.DONE) {
90
- return done(xhr)
91
- }
92
- }
93
- return xhr
94
- }
95
-
96
- const processResponse = (response, type) => {
97
- if (typeof response === "string" && typeof type === "string") {
98
- if (type.match(/\bjson\b/)) {
99
- try {
100
- response = JSON.parse(response)
101
- } catch (error) {
102
- // no-op...
103
- }
104
- } else if (type.match(/\b(?:java|ecma)script\b/)) {
105
- const script = document.createElement("script")
106
- script.setAttribute("nonce", cspNonce())
107
- script.text = response
108
- document.head.appendChild(script).parentNode.removeChild(script)
109
- } else if (type.match(/\b(xml|html|svg)\b/)) {
110
- const parser = new DOMParser()
111
- type = type.replace(/;.+/, "") // remove something like ';charset=utf-8'
112
-
113
- try {
114
- response = parser.parseFromString(response, type)
115
- } catch (error1) {}
116
- }
117
- }
118
-
119
- return response
120
- }
121
-
122
- // Default way to get an element's href. May be overridden at Rails.href.
123
- export const href = (element) => element.href
124
-
125
- // Determines if the request is a cross domain request.
126
- export const isCrossDomain = (url) => {
127
- const originAnchor = document.createElement("a")
128
- originAnchor.href = location.href
129
- const urlAnchor = document.createElement("a")
130
-
131
- try {
132
- urlAnchor.href = url
133
- // If URL protocol is false or is a string containing a single colon
134
- // *and* host are false, assume it is not a cross-domain request
135
- // (should only be the case for IE7 and IE compatibility mode).
136
- // Otherwise, evaluate protocol and host of the URL against the origin
137
- // protocol and host.
138
- return !(
139
- ((!urlAnchor.protocol || urlAnchor.protocol === ":") && !urlAnchor.host) ||
140
- originAnchor.protocol + "//" + originAnchor.host === urlAnchor.protocol + "//" + urlAnchor.host
141
- )
142
- } catch (e) {
143
- // If there is an error parsing the URL, assume it is crossDomain.
144
- return true
145
- }
146
- }
@@ -1,20 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- let nonce = null
4
-
5
- const loadCSPNonce = () => {
6
- if (nonce) {
7
- return nonce
8
- }
9
-
10
- const cspMetaTag: HTMLMetaElement = document.querySelector("meta[name=csp-nonce]")
11
-
12
- if (cspMetaTag) {
13
- nonce = cspMetaTag.content
14
- }
15
-
16
- return nonce
17
- }
18
-
19
- // Returns the Content-Security-Policy nonce for inline scripts.
20
- export const cspNonce = () => (nonce != null ? nonce : loadCSPNonce())
@@ -1,33 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- const $ = (selector) => Array.prototype.slice.call(document.querySelectorAll(selector))
4
-
5
- // Up-to-date Cross-Site Request Forgery token
6
- export const csrfToken = () => {
7
- const meta: HTMLMetaElement = document.querySelector("meta[name=csrf-token]")
8
- return meta && meta.content
9
- }
10
-
11
- // URL param that must contain the CSRF token
12
- export const csrfParam = () => {
13
- const meta: HTMLMetaElement = document.querySelector("meta[name=csrf-param]")
14
- return meta && meta.content
15
- }
16
-
17
- // Make sure that every Ajax request sends the CSRF token
18
- export const CSRFProtection = (xhr) => {
19
- const token = csrfToken()
20
- if (token != null) {
21
- return xhr.setRequestHeader("X-CSRF-Token", token)
22
- }
23
- }
24
-
25
- // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
26
- export const refreshCSRFTokens = () => {
27
- const token = csrfToken()
28
- const param = csrfParam()
29
-
30
- if (token != null && param != null) {
31
- return $('sl-form input[name="' + param + '"]').forEach((input) => (input.value = token))
32
- }
33
- }
@@ -1,40 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- const elementPrototype = Element.prototype as any
4
-
5
- const m: (this: Element, selector: string) => boolean =
6
- elementPrototype.matches ||
7
- elementPrototype.matchesSelector ||
8
- elementPrototype.mozMatchesSelector ||
9
- elementPrototype.msMatchesSelector ||
10
- elementPrototype.oMatchesSelector ||
11
- elementPrototype.webkitMatchesSelector
12
-
13
- // Checks if the given native dom element matches the selector
14
- // element::
15
- // native DOM element
16
- // selector::
17
- // CSS selector string or
18
- // a JavaScript object with `selector` and `exclude` properties
19
- // Examples: "form", { selector: "form", exclude: "form[data-remote='true']"}
20
- export const matches = (element, selector) => {
21
- if (selector.exclude != null) {
22
- return m.call(element, selector.selector) && !m.call(element, selector.exclude)
23
- } else {
24
- return m.call(element, selector)
25
- }
26
- }
27
-
28
- // get and set data on a given element using "expando properties"
29
- // See: https://developer.mozilla.org/en-US/docs/Glossary/Expando
30
- const expando = "_ujsData"
31
-
32
- export const getData = (element, key) => (element[expando] != null ? element[expando][key] : undefined)
33
-
34
- export const setData = (element, key, value) => {
35
- if (element[expando] == null) {
36
- element[expando] = {}
37
- }
38
-
39
- return (element[expando][key] = value)
40
- }
@@ -1,57 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { matches } from "./dom"
4
-
5
- // Triggers a custom event on an element and returns false if the event result is false
6
- // obj::
7
- // a native DOM element
8
- // name::
9
- // string that corresponds to the event you want to trigger
10
- // e.g. 'click', 'submit'
11
- // data::
12
- // data you want to pass when you dispatch an event
13
- export const fire = (obj, name, data = {}) => {
14
- const event = new CustomEvent(name, {
15
- bubbles: true,
16
- cancelable: true,
17
- detail: data,
18
- })
19
-
20
- obj.dispatchEvent(event)
21
- return !event.defaultPrevented
22
- }
23
-
24
- // Helper function, needed to provide consistent behavior in IE
25
- export const stopEverything = (event) => {
26
- fire(event.target, "ujs:everythingStopped")
27
-
28
- event.preventDefault()
29
- event.stopPropagation()
30
-
31
- return event.stopImmediatePropagation()
32
- }
33
-
34
- // Delegates events
35
- // to a specified parent `element`, which fires event `handler`
36
- // for the specified `selector` when an event of `eventType` is triggered
37
- // element::
38
- // parent element that will listen for events e.g. document
39
- // selector::
40
- // CSS selector; or an object that has `selector` and `exclude` properties (see: Rails.matches)
41
- // eventType::
42
- // string representing the event e.g. 'submit', 'click'
43
- // handler::
44
- // the event handler to be called
45
- export const delegate = (element, selector, eventType, handler) =>
46
- element.addEventListener(eventType, function (event) {
47
- let { target } = event
48
-
49
- while (!!(target instanceof Element) && !matches(target, selector)) {
50
- target = target.parentNode
51
- }
52
-
53
- if (target instanceof Element && handler.call(target, event) === false) {
54
- event.preventDefault()
55
- return event.stopPropagation()
56
- }
57
- })
@@ -1,58 +0,0 @@
1
- // This code was heavily inspired by the rails-ujs project.
2
- // Copyright (c) 2007-2021 Rails Core team.
3
- import { matches } from "./dom"
4
-
5
- const toArray = (e) => Array.prototype.slice.call(e)
6
-
7
- export const serializeElement = (element, additionalParam) => {
8
- let inputs = [element]
9
- if (matches(element, "form")) {
10
- inputs = toArray(element.elements)
11
- }
12
- const params = []
13
-
14
- inputs.forEach(function (input) {
15
- if (!input.name || input.disabled) {
16
- return
17
- }
18
-
19
- if (matches(input, "fieldset[disabled] *")) {
20
- return
21
- }
22
-
23
- if (matches(input, "select")) {
24
- return toArray(input.options).forEach(function (option) {
25
- if (option.selected) {
26
- return params.push({ name: input.name, value: option.value })
27
- }
28
- })
29
- } else if (input.checked || ["radio", "checkbox", "submit"].indexOf(input.type) === -1) {
30
- return params.push({ name: input.name, value: input.value })
31
- }
32
- })
33
-
34
- if (additionalParam) {
35
- params.push(additionalParam)
36
- }
37
-
38
- return params
39
- .map(function (param) {
40
- if (param.name != null) {
41
- return `${encodeURIComponent(param.name)}=${encodeURIComponent(param.value)}`
42
- } else {
43
- return param
44
- }
45
- })
46
- .join("&")
47
- }
48
-
49
- // Helper function that returns form elements that match the specified CSS selector
50
- // If form is actually a "form" element this will return associated elements outside the from that have
51
- // the html form attribute set
52
- export const formElements = (form, selector) => {
53
- if (matches(form, "form")) {
54
- return toArray(form.elements).filter((el) => matches(el, selector))
55
- } else {
56
- return toArray(form.querySelectorAll(selector))
57
- }
58
- }
@@ -1,19 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rails', '~> 7.0.0'
4
- gem 'webrick'
5
- gem 'bootsnap', '>= 1.4.4', require: false
6
- gem 'rexml'
7
- gem 'shoelace-rails', path: '../../../shoelace-rails'
8
- gem 'webpacker', '6.0.0.rc.5'
9
-
10
- group :development, :test do
11
- gem 'pry-byebug'
12
- end
13
-
14
- group :test do
15
- gem 'capybara', '>= 3.26'
16
- gem 'capybara-shadowdom'
17
- gem 'selenium-webdriver', '>= 4.0.0.rc3'
18
- gem 'webdrivers'
19
- end
@@ -1,6 +0,0 @@
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
@@ -1,46 +0,0 @@
1
- class HotwireFormsController < ActionController::Base
2
- layout "application"
3
-
4
- def show
5
- @user = User.new(session[:user])
6
- end
7
-
8
- # GET /users/new
9
- def new
10
- @user = User.new(params[:user]&.permit!)
11
-
12
- render 'form'
13
- end
14
-
15
- # GET /users/1/edit
16
- def edit
17
- @user = User.new(name: "Yuki Nishijima")
18
-
19
- render 'form'
20
- end
21
-
22
- # POST /users
23
- def create
24
- @user = User.new(user_params)
25
-
26
- if @user.valid?
27
- session[:user] = user_params.to_h
28
- redirect_to hotwire_form_path(1)
29
- else
30
- render 'form', status: 422
31
- end
32
- end
33
-
34
- # PATCH/PUT /users/1
35
- def update
36
- @user = User.new(user_params)
37
-
38
- render(@user.valid? ? 'show' : 'form')
39
- end
40
-
41
- private
42
-
43
- def user_params
44
- params.require(:user).permit!
45
- end
46
- end
@@ -1,37 +0,0 @@
1
- class TurbolinksFormsController < ActionController::Base
2
- layout "application"
3
-
4
- # GET /users/new
5
- def new
6
- @user = User.new
7
-
8
- render 'form'
9
- end
10
-
11
- # GET /users/1/edit
12
- def edit
13
- @user = User.new(name: "Yuki Nishijima")
14
-
15
- render 'form'
16
- end
17
-
18
- # POST /users
19
- def create
20
- @user = User.new(user_params)
21
-
22
- render(@user.valid? ? 'show' : 'form')
23
- end
24
-
25
- # PATCH/PUT /users/1
26
- def update
27
- @user = User.new(user_params)
28
-
29
- render(@user.valid? ? 'show' : 'form')
30
- end
31
-
32
- private
33
-
34
- def user_params
35
- params.require(:user).permit!
36
- end
37
- end
@@ -1,16 +0,0 @@
1
- class User
2
- include ActiveModel::Model
3
- include ActiveModel::Attributes
4
-
5
- attribute :name
6
- attribute :description
7
- attribute :color
8
- attribute :score
9
- attribute :current_city
10
- attribute :previous_city
11
- attribute :past_cities
12
- attribute :remember_me
13
- attribute :subscribe_to_emails
14
-
15
- validates :name, presence: true
16
- end
@@ -1 +0,0 @@
1
- import "@hotwired/turbo-rails"
@@ -1,5 +0,0 @@
1
- import Turbolinks from "turbolinks"
2
- import Rails from '@rails/ujs'
3
-
4
- Turbolinks.start()
5
- Rails.start()
@@ -1,45 +0,0 @@
1
- <% locations = { tokyo: "Tokyo", new_york: "New York", london: "London" } %>
2
- <%= sl_form_for(@user, url: hotwire_forms_path) do |form| %>
3
- <div>
4
- <%= form.text_field :name do %>
5
- <span slot="help-text" style="color: rgb(var(--sl-color-danger-600));">
6
- <%= @user.errors.full_messages_for(:name).first %>
7
- </span>
8
- <% end %>
9
- </div>
10
-
11
- <div>
12
- <%= form.color_field :color %>
13
- </div>
14
-
15
- <div>
16
- <%= form.range_field :score, min: 0, max: 100, step: 1 %>
17
- </div>
18
-
19
- <div>
20
- <%= form.collection_radio_buttons :current_city, locations, :first, :last %>
21
- </div>
22
-
23
- <div>
24
- <%= form.collection_select :previous_city, locations, :first, :last, {}, { placeholder: "Select one" } %>
25
- </div>
26
-
27
- <div>
28
- <%= form.collection_select :past_cities, locations, :first, :last, {}, { placeholder: "Select two or more", multiple: true, clearable: true } %>
29
- </div>
30
-
31
- <div>
32
- <%= form.check_box :remember_me %>
33
- </div>
34
-
35
- <div>
36
- <%= form.switch_field :subscribe_to_emails, value: "1" %>
37
- </div>
38
-
39
- <div>
40
- <%= form.text_area :description %>
41
- </div>
42
-
43
- <%= form.submit %>
44
- <%= form.submit "Submit without Turbo", data: { turbo: false } %>
45
- <% end %>
@@ -1,5 +0,0 @@
1
- <% @user.attributes.each do |attribute_name, value| %>
2
- <div>
3
- <%= attribute_name.titleize %>: <%= value %>
4
- </div>
5
- <% end %>
@@ -1,39 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Shoelace Test</title>
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <%= csrf_meta_tags %>
7
- <%= csp_meta_tag %>
8
-
9
- <style>
10
- body {
11
- font-family: var(--sl-font-sans);
12
- font-size: var(--sl-font-size-medium);
13
- font-weight: var(--sl-font-weight-normal);
14
- letter-spacing: var(--sl-letter-spacing-normal);
15
- color: var(--sl-color-gray-800);
16
- line-height: var(--sl-line-height-normal);
17
- }
18
-
19
- sl-form div, sl-turbo-form div {
20
- margin-bottom: 2em;
21
- }
22
- </style>
23
-
24
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.88/dist/themes/light.css">
25
- <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.88/dist/shoelace.js"></script>
26
-
27
- <% if request.path.include?("hotwire") %>
28
- <%= javascript_pack_tag 'hotwire' %>
29
- <% else %>
30
- <%= javascript_pack_tag 'turbolinks' %>
31
- <% end %>
32
- </head>
33
-
34
- <body>
35
- <div style="width: 950px; margin: auto">
36
- <%= yield %>
37
- </div>
38
- </body>
39
- </html>
@@ -1,44 +0,0 @@
1
- <% locations = { tokyo: "Tokyo", new_york: "New York", london: "London" } %>
2
- <%= sl_form_for(@user, url: turbolinks_forms_path) do |form| %>
3
- <div>
4
- <%= form.text_field :name do %>
5
- <span slot="help-text" style="color: rgb(var(--sl-color-danger-600));">
6
- <%= @user.errors.full_messages_for(:name).first %>
7
- </span>
8
- <% end %>
9
- </div>
10
-
11
- <div>
12
- <%= form.color_field :color %>
13
- </div>
14
-
15
- <div>
16
- <%= form.range_field :score, min: 0, max: 100, step: 1 %>
17
- </div>
18
-
19
- <div>
20
- <%= form.collection_radio_buttons :current_city, locations, :first, :last %>
21
- </div>
22
-
23
- <div>
24
- <%= form.collection_select :previous_city, locations, :first, :last, {}, { placeholder: "Select one" } %>
25
- </div>
26
-
27
- <div>
28
- <%= form.collection_select :past_cities, locations, :first, :last, {}, { placeholder: "Select two or more", multiple: true, clearable: true } %>
29
- </div>
30
-
31
- <div>
32
- <%= form.check_box :remember_me %>
33
- </div>
34
-
35
- <div>
36
- <%= form.switch_field :subscribe_to_emails, value: "1" %>
37
- </div>
38
-
39
- <div>
40
- <%= form.text_area :description %>
41
- </div>
42
-
43
- <%= form.submit %>
44
- <% end %>
@@ -1,5 +0,0 @@
1
- <% @user.attributes.each do |attribute_name, value| %>
2
- <div>
3
- <%= attribute_name.titleize %>: <%= value %>
4
- </div>
5
- <% end %>
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- APP_PATH = File.expand_path('../config/application', __dir__)
4
- require_relative "../config/boot"
5
- require "rails/commands"
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4
- ENV["NODE_ENV"] ||= "development"
5
-
6
- require "pathname"
7
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8
- Pathname.new(__FILE__).realpath)
9
-
10
- require "bundler/setup"
11
-
12
- require "webpacker"
13
- require "webpacker/webpack_runner"
14
-
15
- APP_ROOT = File.expand_path("..", __dir__)
16
- Dir.chdir(APP_ROOT) do
17
- Webpacker::WebpackRunner.run(ARGV)
18
- end