light_switch 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +209 -0
  4. data/Rakefile +7 -0
  5. data/app/assets/config/light_switch_manifest.js +2 -0
  6. data/app/assets/images/light_switch/light-switch.svg +1 -0
  7. data/app/assets/javascripts/light_switch/application.js +1 -0
  8. data/app/assets/stylesheets/light_switch/application.css +97 -0
  9. data/app/assets/stylesheets/light_switch/normalize.css +427 -0
  10. data/app/assets/stylesheets/light_switch/skeleton.css +418 -0
  11. data/app/controllers/light_switch/application_controller.rb +4 -0
  12. data/app/controllers/light_switch/switches_controller.rb +52 -0
  13. data/app/models/concerns/light_switch/switch/notifications_concern.rb +23 -0
  14. data/app/models/light_switch/application_record.rb +5 -0
  15. data/app/models/light_switch/switch.rb +29 -0
  16. data/app/views/layouts/light_switch/application.html.erb +30 -0
  17. data/app/views/light_switch/switches/_form.html.erb +6 -0
  18. data/app/views/light_switch/switches/_form_errors.html.erb +5 -0
  19. data/app/views/light_switch/switches/_switch.html.erb +23 -0
  20. data/app/views/light_switch/switches/index.html.erb +22 -0
  21. data/config/locales/light_switch.en.yml +13 -0
  22. data/config/routes.rb +5 -0
  23. data/db/migrate/20231116015256_create_light_switch_switches.rb +11 -0
  24. data/lib/light_switch/configuration.rb +5 -0
  25. data/lib/light_switch/engine.rb +27 -0
  26. data/lib/light_switch/null_cache.rb +10 -0
  27. data/lib/light_switch/version.rb +3 -0
  28. data/lib/light_switch.rb +41 -0
  29. data/lib/tasks/light_switch_tasks.rake +4 -0
  30. metadata +223 -0
@@ -0,0 +1,418 @@
1
+ /*
2
+ * Skeleton V2.0.4
3
+ * Copyright 2014, Dave Gamache
4
+ * www.getskeleton.com
5
+ * Free to use under the MIT license.
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ * 12/29/2014
8
+ */
9
+
10
+
11
+ /* Table of contents
12
+ ––––––––––––––––––––––––––––––––––––––––––––––––––
13
+ - Grid
14
+ - Base Styles
15
+ - Typography
16
+ - Links
17
+ - Buttons
18
+ - Forms
19
+ - Lists
20
+ - Code
21
+ - Tables
22
+ - Spacing
23
+ - Utilities
24
+ - Clearing
25
+ - Media Queries
26
+ */
27
+
28
+
29
+ /* Grid
30
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
31
+ .container {
32
+ position: relative;
33
+ width: 100%;
34
+ max-width: 960px;
35
+ margin: 0 auto;
36
+ padding: 0 20px;
37
+ box-sizing: border-box; }
38
+ .column,
39
+ .columns {
40
+ width: 100%;
41
+ float: left;
42
+ box-sizing: border-box; }
43
+
44
+ /* For devices larger than 400px */
45
+ @media (min-width: 400px) {
46
+ .container {
47
+ width: 85%;
48
+ padding: 0; }
49
+ }
50
+
51
+ /* For devices larger than 550px */
52
+ @media (min-width: 550px) {
53
+ .container {
54
+ width: 80%; }
55
+ .column,
56
+ .columns {
57
+ margin-left: 4%; }
58
+ .column:first-child,
59
+ .columns:first-child {
60
+ margin-left: 0; }
61
+
62
+ .one.column,
63
+ .one.columns { width: 4.66666666667%; }
64
+ .two.columns { width: 13.3333333333%; }
65
+ .three.columns { width: 22%; }
66
+ .four.columns { width: 30.6666666667%; }
67
+ .five.columns { width: 39.3333333333%; }
68
+ .six.columns { width: 48%; }
69
+ .seven.columns { width: 56.6666666667%; }
70
+ .eight.columns { width: 65.3333333333%; }
71
+ .nine.columns { width: 74.0%; }
72
+ .ten.columns { width: 82.6666666667%; }
73
+ .eleven.columns { width: 91.3333333333%; }
74
+ .twelve.columns { width: 100%; margin-left: 0; }
75
+
76
+ .one-third.column { width: 30.6666666667%; }
77
+ .two-thirds.column { width: 65.3333333333%; }
78
+
79
+ .one-half.column { width: 48%; }
80
+
81
+ /* Offsets */
82
+ .offset-by-one.column,
83
+ .offset-by-one.columns { margin-left: 8.66666666667%; }
84
+ .offset-by-two.column,
85
+ .offset-by-two.columns { margin-left: 17.3333333333%; }
86
+ .offset-by-three.column,
87
+ .offset-by-three.columns { margin-left: 26%; }
88
+ .offset-by-four.column,
89
+ .offset-by-four.columns { margin-left: 34.6666666667%; }
90
+ .offset-by-five.column,
91
+ .offset-by-five.columns { margin-left: 43.3333333333%; }
92
+ .offset-by-six.column,
93
+ .offset-by-six.columns { margin-left: 52%; }
94
+ .offset-by-seven.column,
95
+ .offset-by-seven.columns { margin-left: 60.6666666667%; }
96
+ .offset-by-eight.column,
97
+ .offset-by-eight.columns { margin-left: 69.3333333333%; }
98
+ .offset-by-nine.column,
99
+ .offset-by-nine.columns { margin-left: 78.0%; }
100
+ .offset-by-ten.column,
101
+ .offset-by-ten.columns { margin-left: 86.6666666667%; }
102
+ .offset-by-eleven.column,
103
+ .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104
+
105
+ .offset-by-one-third.column,
106
+ .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107
+ .offset-by-two-thirds.column,
108
+ .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109
+
110
+ .offset-by-one-half.column,
111
+ .offset-by-one-half.columns { margin-left: 52%; }
112
+
113
+ }
114
+
115
+
116
+ /* Base Styles
117
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
118
+ /* NOTE
119
+ html is set to 62.5% so that all the REM measurements throughout Skeleton
120
+ are based on 10px sizing. So basically 1.5rem = 15px :) */
121
+ html {
122
+ font-size: 62.5%; }
123
+ body {
124
+ font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125
+ line-height: 1.6;
126
+ font-weight: 400;
127
+ font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128
+ color: #222; }
129
+
130
+
131
+ /* Typography
132
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
133
+ h1, h2, h3, h4, h5, h6 {
134
+ margin-top: 0;
135
+ margin-bottom: 2rem;
136
+ font-weight: 300; }
137
+ h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138
+ h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139
+ h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140
+ h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141
+ h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142
+ h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143
+
144
+ /* Larger than phablet */
145
+ @media (min-width: 550px) {
146
+ h1 { font-size: 5.0rem; }
147
+ h2 { font-size: 4.2rem; }
148
+ h3 { font-size: 3.6rem; }
149
+ h4 { font-size: 3.0rem; }
150
+ h5 { font-size: 2.4rem; }
151
+ h6 { font-size: 1.5rem; }
152
+ }
153
+
154
+ p {
155
+ margin-top: 0; }
156
+
157
+
158
+ /* Links
159
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
160
+ a {
161
+ color: #1EAEDB; }
162
+ a:hover {
163
+ color: #0FA0CE; }
164
+
165
+
166
+ /* Buttons
167
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
168
+ .button,
169
+ button,
170
+ input[type="submit"],
171
+ input[type="reset"],
172
+ input[type="button"] {
173
+ display: inline-block;
174
+ height: 38px;
175
+ padding: 0 30px;
176
+ color: #555;
177
+ text-align: center;
178
+ font-size: 11px;
179
+ font-weight: 600;
180
+ line-height: 38px;
181
+ letter-spacing: .1rem;
182
+ text-transform: uppercase;
183
+ text-decoration: none;
184
+ white-space: nowrap;
185
+ background-color: transparent;
186
+ border-radius: 4px;
187
+ border: 1px solid #bbb;
188
+ cursor: pointer;
189
+ box-sizing: border-box; }
190
+ .button:hover,
191
+ button:hover,
192
+ input[type="submit"]:hover,
193
+ input[type="reset"]:hover,
194
+ input[type="button"]:hover,
195
+ .button:focus,
196
+ button:focus,
197
+ input[type="submit"]:focus,
198
+ input[type="reset"]:focus,
199
+ input[type="button"]:focus {
200
+ color: #333;
201
+ border-color: #888;
202
+ outline: 0; }
203
+ .button.button-primary,
204
+ button.button-primary,
205
+ input[type="submit"].button-primary,
206
+ input[type="reset"].button-primary,
207
+ input[type="button"].button-primary {
208
+ color: #FFF;
209
+ background-color: #33C3F0;
210
+ border-color: #33C3F0; }
211
+ .button.button-primary:hover,
212
+ button.button-primary:hover,
213
+ input[type="submit"].button-primary:hover,
214
+ input[type="reset"].button-primary:hover,
215
+ input[type="button"].button-primary:hover,
216
+ .button.button-primary:focus,
217
+ button.button-primary:focus,
218
+ input[type="submit"].button-primary:focus,
219
+ input[type="reset"].button-primary:focus,
220
+ input[type="button"].button-primary:focus {
221
+ color: #FFF;
222
+ background-color: #1EAEDB;
223
+ border-color: #1EAEDB; }
224
+
225
+
226
+ /* Forms
227
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
228
+ input[type="email"],
229
+ input[type="number"],
230
+ input[type="search"],
231
+ input[type="text"],
232
+ input[type="tel"],
233
+ input[type="url"],
234
+ input[type="password"],
235
+ textarea,
236
+ select {
237
+ height: 38px;
238
+ padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239
+ background-color: #fff;
240
+ border: 1px solid #D1D1D1;
241
+ border-radius: 4px;
242
+ box-shadow: none;
243
+ box-sizing: border-box; }
244
+ /* Removes awkward default styles on some inputs for iOS */
245
+ input[type="email"],
246
+ input[type="number"],
247
+ input[type="search"],
248
+ input[type="text"],
249
+ input[type="tel"],
250
+ input[type="url"],
251
+ input[type="password"],
252
+ textarea {
253
+ -webkit-appearance: none;
254
+ -moz-appearance: none;
255
+ appearance: none; }
256
+ textarea {
257
+ min-height: 65px;
258
+ padding-top: 6px;
259
+ padding-bottom: 6px; }
260
+ input[type="email"]:focus,
261
+ input[type="number"]:focus,
262
+ input[type="search"]:focus,
263
+ input[type="text"]:focus,
264
+ input[type="tel"]:focus,
265
+ input[type="url"]:focus,
266
+ input[type="password"]:focus,
267
+ textarea:focus,
268
+ select:focus {
269
+ border: 1px solid #33C3F0;
270
+ outline: 0; }
271
+ label,
272
+ legend {
273
+ display: block;
274
+ margin-bottom: .5rem;
275
+ font-weight: 600; }
276
+ fieldset {
277
+ padding: 0;
278
+ border-width: 0; }
279
+ input[type="checkbox"],
280
+ input[type="radio"] {
281
+ display: inline; }
282
+ label > .label-body {
283
+ display: inline-block;
284
+ margin-left: .5rem;
285
+ font-weight: normal; }
286
+
287
+
288
+ /* Lists
289
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
290
+ ul {
291
+ list-style: circle inside; }
292
+ ol {
293
+ list-style: decimal inside; }
294
+ ol, ul {
295
+ padding-left: 0;
296
+ margin-top: 0; }
297
+ ul ul,
298
+ ul ol,
299
+ ol ol,
300
+ ol ul {
301
+ margin: 1.5rem 0 1.5rem 3rem;
302
+ font-size: 90%; }
303
+ li {
304
+ margin-bottom: 1rem; }
305
+
306
+
307
+ /* Code
308
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
309
+ code {
310
+ padding: .2rem .5rem;
311
+ margin: 0 .2rem;
312
+ font-size: 90%;
313
+ white-space: nowrap;
314
+ background: #F1F1F1;
315
+ border: 1px solid #E1E1E1;
316
+ border-radius: 4px; }
317
+ pre > code {
318
+ display: block;
319
+ padding: 1rem 1.5rem;
320
+ white-space: pre; }
321
+
322
+
323
+ /* Tables
324
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
325
+ th,
326
+ td {
327
+ padding: 12px 15px;
328
+ text-align: left;
329
+ border-bottom: 1px solid #E1E1E1; }
330
+ th:first-child,
331
+ td:first-child {
332
+ padding-left: 0; }
333
+ th:last-child,
334
+ td:last-child {
335
+ padding-right: 0; }
336
+
337
+
338
+ /* Spacing
339
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
340
+ button,
341
+ .button {
342
+ margin-bottom: 1rem; }
343
+ input,
344
+ textarea,
345
+ select,
346
+ fieldset {
347
+ margin-bottom: 1.5rem; }
348
+ pre,
349
+ blockquote,
350
+ dl,
351
+ figure,
352
+ table,
353
+ p,
354
+ ul,
355
+ ol,
356
+ form {
357
+ margin-bottom: 2.5rem; }
358
+
359
+
360
+ /* Utilities
361
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
362
+ .u-full-width {
363
+ width: 100%;
364
+ box-sizing: border-box; }
365
+ .u-max-full-width {
366
+ max-width: 100%;
367
+ box-sizing: border-box; }
368
+ .u-pull-right {
369
+ float: right; }
370
+ .u-pull-left {
371
+ float: left; }
372
+
373
+
374
+ /* Misc
375
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
376
+ hr {
377
+ margin-top: 3rem;
378
+ margin-bottom: 3.5rem;
379
+ border-width: 0;
380
+ border-top: 1px solid #E1E1E1; }
381
+
382
+
383
+ /* Clearing
384
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
385
+
386
+ /* Self Clearing Goodness */
387
+ .container:after,
388
+ .row:after,
389
+ .u-cf {
390
+ content: "";
391
+ display: table;
392
+ clear: both; }
393
+
394
+
395
+ /* Media Queries
396
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
397
+ /*
398
+ Note: The best way to structure the use of media queries is to create the queries
399
+ near the relevant code. For example, if you wanted to change the styles for buttons
400
+ on small devices, paste the mobile query code up in the buttons section and style it
401
+ there.
402
+ */
403
+
404
+
405
+ /* Larger than mobile */
406
+ @media (min-width: 400px) {}
407
+
408
+ /* Larger than phablet (also point when grid becomes active) */
409
+ @media (min-width: 550px) {}
410
+
411
+ /* Larger than tablet */
412
+ @media (min-width: 750px) {}
413
+
414
+ /* Larger than desktop */
415
+ @media (min-width: 1000px) {}
416
+
417
+ /* Larger than Desktop HD */
418
+ @media (min-width: 1200px) {}
@@ -0,0 +1,4 @@
1
+ module LightSwitch
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,52 @@
1
+ module LightSwitch
2
+ class SwitchesController < ApplicationController
3
+ before_action :load_switches, on: %i[index create]
4
+
5
+ def index
6
+ @switch = Switch.new
7
+ end
8
+
9
+ def create
10
+ @switch = Switch.new(switch_params.slice(:name))
11
+
12
+ if @switch.save
13
+ redirect_to [:switches], notice: "Switch #{@switch.name} was successfully created.", status: :see_other
14
+ else
15
+ render :index, status: :unprocessable_entity
16
+ end
17
+ rescue ActiveRecord::RecordNotUnique
18
+ @switch.errors.add(:name, "already taken")
19
+ render :index, status: :unprocessable_entity
20
+ end
21
+
22
+ def update
23
+ @switch = Switch.find(params[:id])
24
+
25
+ if @switch.update(switch_params.slice(:state))
26
+ redirect_to [:switches], notice: "Switch #{@switch.name} was successfully updated.", status: :see_other
27
+ else
28
+ errors = @switch.errors.full_messages.to_sentence
29
+ @switch.restore_attributes
30
+ redirect_to [:switches], alert: "Failed to update Switch #{@switch.name}: #{errors}", status: :see_other
31
+ end
32
+ rescue ActiveRecord::RecordNotFound
33
+ redirect_to [:switches], alert: "Failed to update Switch because it has been deleted.", status: :see_other
34
+ end
35
+
36
+ def destroy
37
+ switch = Switch.find_by(id: params[:id])
38
+ switch&.destroy!
39
+ redirect_to [:switches], notice: "Switch #{switch.name} was successfully deleted.", status: :see_other
40
+ end
41
+
42
+ private
43
+
44
+ def load_switches
45
+ @switches = Switch.ordered
46
+ end
47
+
48
+ def switch_params
49
+ params.require(:switch).permit(:name, :state)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ module LightSwitch::Switch::NotificationsConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ after_commit :publish_committed, if: :saved_changes?
6
+ end
7
+
8
+ private
9
+
10
+ def publish_committed
11
+ event = if previously_new_record?
12
+ :create
13
+ elsif destroyed?
14
+ :destroy
15
+ else
16
+ :update
17
+ end
18
+
19
+ ActiveSupport::Notifications.instrument("#{event}_committed.switch.light_switch", switch: self) do
20
+ # Do nothing; just publishing the event for subscribers
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module LightSwitch
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ module LightSwitch
2
+ class Switch < ApplicationRecord
3
+ include NotificationsConcern
4
+
5
+ if Gem::Version.new(Rails.version) >= Gem::Version.new("7.2")
6
+ enum :state, {on: "on", off: "off"}
7
+ else
8
+ enum state: {on: "on", off: "off"}
9
+ end
10
+
11
+ scope :ordered, -> { order(:name) }
12
+
13
+ validates :name, :state, presence: true
14
+
15
+ before_validation :normalize_name
16
+
17
+ after_save :delete_from_cache
18
+
19
+ private
20
+
21
+ def delete_from_cache
22
+ LightSwitch.config.cache.delete("#{self.class.name.underscore}/#{name}")
23
+ end
24
+
25
+ def normalize_name
26
+ name.tap(&:strip!).downcase! if name.present?
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Light Switch</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+
9
+ <link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
10
+
11
+ <%= stylesheet_link_tag "light_switch/application", media: "all", data: { turbolinks_track: :reload } %>
12
+ <%= javascript_include_tag "light_switch/application", type: :module, defer: true, data: { turbolinks_track: :reload } %>
13
+ </head>
14
+ <body>
15
+ <div class="container">
16
+ <div class="site-header">
17
+ <%= inline_svg_tag("light_switch/light-switch.svg", class: "site-logo") %>
18
+ <h2>Light Switch</h2>
19
+ </div>
20
+
21
+ <%= yield %>
22
+
23
+ <div class="site-footer u-full-width">
24
+ Light Switch logo was created by
25
+ <a href="https://thenounproject.com/snjeffries1106">Sara Jeffries</a>
26
+ from the Noun Project.
27
+ </div>
28
+ </div>
29
+ </body>
30
+ </html>
@@ -0,0 +1,6 @@
1
+ <%= render "form_errors", switch: switch %>
2
+
3
+ <%= form_with(model: switch, class: "form-inline") do |form| %>
4
+ <%= form.text_field :name, placeholder: "Name" %>
5
+ <%= form.submit %>
6
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if switch.present? && switch.errors.any? %>
2
+ <p class="form-errors alert">
3
+ Failed to save: <%= switch.errors.full_messages.to_sentence %>.
4
+ </p>
5
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <tr id="<%= dom_id(switch)%>">
2
+ <td><%= switch.name %></td>
3
+ <td>
4
+ <%= form_with(model: switch, class: "form-inline") do |form| %>
5
+ <span class="mr-1 switch-state <%= switch.on? ? "switch-state-on" : "switch-state-off" %>">
6
+ <%= switch.state.upcase %>
7
+ </span>
8
+ <%= form.hidden_field :state, value: switch.on? ? "off" : "on" %>
9
+ <%=
10
+ form.submit(
11
+ switch.on? ? "Turn off" : "Turn on",
12
+ class: "turn-#{switch.on? ? 'off' : 'on'}",
13
+ data: { turbo_confirm: t(".confirm.turn_#{switch.on? ? "off" : "on"}") }
14
+ )
15
+ %>
16
+ <% end %>
17
+ </td>
18
+ <td><%= l(switch.created_at, format: :long) %></td>
19
+ <td><%= l(switch.updated_at, format: :long) %></td>
20
+ <td>
21
+ <%= button_to "Delete", switch, method: :delete, data: { turbo_confirm: t(".confirm.delete", name: switch.name) }, form_class: "form-inline" %>
22
+ </td>
23
+ </tr>
@@ -0,0 +1,22 @@
1
+ <h4>Switches</h4>
2
+
3
+ <% flash.each do |key, msg| %>
4
+ <p class="<%= key %>"><%= msg %></p>
5
+ <% end %>
6
+
7
+ <table id="switches" class="u-full-width">
8
+ <thead>
9
+ <th>Name</th>
10
+ <th>State</th>
11
+ <th>Created At</th>
12
+ <th>Updated At</th>
13
+ <th><!-- Actions --></th>
14
+ </thead>
15
+ <tbody>
16
+ <%= render @switches %>
17
+ </tbody>
18
+ </table>
19
+
20
+ <div id="new-switch">
21
+ <%= render "form", switch: @switch %>
22
+ </div>
@@ -0,0 +1,13 @@
1
+ en:
2
+ light_switch:
3
+ switches:
4
+ switch:
5
+ confirm:
6
+ delete: >
7
+ Are you sure that you want to delete %{name}?
8
+
9
+
10
+ If your code still references this switch, it will behave as if it is turned on.
11
+
12
+ turn_off: Are you sure that you want to turn off this switch?
13
+ turn_on: Are you sure that you want to turn on this switch?
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ LightSwitch::Engine.routes.draw do
2
+ resources :switches, except: %i[edit show]
3
+
4
+ root "switches#index"
5
+ end
@@ -0,0 +1,11 @@
1
+ class CreateLightSwitchSwitches < ActiveRecord::Migration["#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"]
2
+ def change
3
+ create_table :light_switch_switches do |t|
4
+ t.string :name, null: false
5
+ t.string :state, null: false, default: "on"
6
+
7
+ t.timestamps
8
+ end
9
+ add_index :light_switch_switches, :name, unique: true
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module LightSwitch
2
+ class Configuration
3
+ attr_accessor :cache, :cache_fetch_options, :switches
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ require "inline_svg"
2
+ require "turbo-rails"
3
+
4
+ module LightSwitch
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace LightSwitch
7
+
8
+ config.before_configuration { LightSwitch.configure_defaults }
9
+
10
+ initializer "light_switch.assets.precompile" do |app|
11
+ app.config.assets.precompile += [
12
+ "light_switch/application.css",
13
+ "light_switch/application.js",
14
+ "light_switch/light-switch.svg"
15
+ ]
16
+ end
17
+
18
+ initializer "light_switch.create_switches", after: :load_config_initializers do
19
+ ActiveSupport.on_load(:active_record) do
20
+ LightSwitch.config.switches.each do |name|
21
+ Switch.find_or_create_by!(name: name.to_s) if Switch.table_exists?
22
+ rescue ActiveRecord::RecordNotUnique
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end