loco_motion-rails 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +880 -0
- data/app/components/daisy/actions/button_component.html.haml +7 -0
- data/app/components/daisy/actions/button_component.rb +52 -0
- data/app/components/daisy/actions/dropdown_component.html.haml +13 -0
- data/app/components/daisy/actions/dropdown_component.rb +48 -0
- data/app/components/daisy/actions/modal_component.html.haml +31 -0
- data/app/components/daisy/actions/modal_component.rb +92 -0
- data/app/components/daisy/actions/swap_component.html.haml +17 -0
- data/app/components/daisy/actions/swap_component.rb +56 -0
- data/app/components/daisy/actions/theme_controller_component.html.haml +5 -0
- data/app/components/daisy/actions/theme_controller_component.rb +8 -0
- data/app/components/daisy/data_display/accordion_component.html.haml +4 -0
- data/app/components/daisy/data_display/accordion_component.rb +82 -0
- data/app/components/daisy/data_display/avatar_component.html.haml +9 -0
- data/app/components/daisy/data_display/avatar_component.rb +60 -0
- data/app/components/daisy/data_display/badge_component.html.haml +2 -0
- data/app/components/daisy/data_display/badge_component.rb +27 -0
- data/app/components/daisy/data_display/card_component.html.haml +17 -0
- data/app/components/daisy/data_display/card_component.rb +53 -0
- data/app/components/daisy/data_display/carousel_component.html.haml +3 -0
- data/app/components/daisy/data_display/carousel_component.rb +17 -0
- data/app/components/daisy/data_display/chat_component.html.haml +14 -0
- data/app/components/daisy/data_display/chat_component.rb +38 -0
- data/app/components/daisy/data_display/collapse_component.html.haml +13 -0
- data/app/components/daisy/data_display/collapse_component.rb +37 -0
- data/app/components/daisy/data_display/countdown_component.html.haml +24 -0
- data/app/components/daisy/data_display/countdown_component.rb +70 -0
- data/app/components/daisy/data_display/countdown_controller.js +78 -0
- data/app/components/daisy/data_display/diff_component.html.haml +6 -0
- data/app/components/daisy/data_display/diff_component.rb +25 -0
- data/app/components/daisy/data_display/kbd_component.html.haml +2 -0
- data/app/components/daisy/data_display/kbd_component.rb +21 -0
- data/app/components/daisy/data_display/stat_component.html.haml +27 -0
- data/app/components/daisy/data_display/stat_component.rb +41 -0
- data/app/components/daisy/data_display/table_component.html.haml +14 -0
- data/app/components/daisy/data_display/table_component.rb +148 -0
- data/app/components/daisy/data_display/timeline_component.html.haml +7 -0
- data/app/components/daisy/data_display/timeline_component.rb +8 -0
- data/app/components/daisy/data_display/timeline_event_component.html.haml +28 -0
- data/app/components/daisy/data_display/timeline_event_component.rb +47 -0
- data/app/components/daisy/feedback/alert_component.html.haml +8 -0
- data/app/components/daisy/feedback/alert_component.rb +19 -0
- data/app/components/daisy/layout/join_component.rb +15 -0
- data/app/components/daisy/navigation/bottom_nav_component.rb +59 -0
- data/app/components/daisy/navigation/breadcrumbs_component.html.haml +7 -0
- data/app/components/daisy/navigation/breadcrumbs_component.rb +15 -0
- data/app/components/daisy/navigation/link_component.html.haml +4 -0
- data/app/components/daisy/navigation/link_component.rb +34 -0
- data/app/components/daisy/navigation/menu_component.html.haml +3 -0
- data/app/components/daisy/navigation/menu_component.rb +49 -0
- data/app/components/daisy/navigation/navbar_component.html.haml +4 -0
- data/app/components/daisy/navigation/navbar_component.rb +12 -0
- data/app/components/daisy/navigation/steps_component.rb +40 -0
- data/app/components/daisy/navigation/tabs_component.html.haml +4 -0
- data/app/components/daisy/navigation/tabs_component.rb +107 -0
- data/app/components/hero/icon_component.rb +18 -0
- data/lib/daisy/helpers.rb +61 -0
- data/lib/daisy.rb +19 -0
- data/lib/loco_motion/base_component.rb +371 -0
- data/lib/loco_motion/basic_component.rb +18 -0
- data/lib/loco_motion/component_config.rb +165 -0
- data/lib/loco_motion/engine.rb +8 -0
- data/lib/loco_motion/errors.rb +33 -0
- data/lib/loco_motion.rb +48 -0
- metadata +408 -0
data/README.md
ADDED
@@ -0,0 +1,880 @@
|
|
1
|
+
<!-- omit from toc -->
|
2
|
+
# loco_motion
|
3
|
+
|
4
|
+
Crazy fast Rails development with modern tools and components leveraging
|
5
|
+
ViewComponent, TailwindCSS, DaisyUI and more!
|
6
|
+
|
7
|
+
![image](./docs/assets/images/loco-chats.png)
|
8
|
+
|
9
|
+
_**DISCLAIMER**_
|
10
|
+
|
11
|
+
This project is in active development and many changes occur with every release!
|
12
|
+
In particular, new Daisy components are being added frequently and older
|
13
|
+
components are being updated with new features meaning the APIs are very likely
|
14
|
+
to change!
|
15
|
+
|
16
|
+
We plan to publish the docs site to a publicly available URL soon, but until
|
17
|
+
then, you can run the docs by cloning the repository and running `make all` (or
|
18
|
+
`make all-quick` if you've already run `make all` or `make rebuild` previously)
|
19
|
+
and visiting http://localhost:3000/ in your browser.
|
20
|
+
|
21
|
+
Please reach out by opening an
|
22
|
+
[Issue](https://github.com/profoundry-us/loco_motion/issues) if you've found a
|
23
|
+
bug or starting a
|
24
|
+
[Discussion](https://github.com/profoundry-us/loco_motion/discussions) if you
|
25
|
+
have a question!
|
26
|
+
|
27
|
+
Please open a Discussion / Issue **before** starting a Pull Request to make sure
|
28
|
+
we aren't already working on the suggested feature / bug, and to ensure that
|
29
|
+
your solution is aligned with our goals.
|
30
|
+
|
31
|
+
- [About](#about)
|
32
|
+
- [Getting Started](#getting-started)
|
33
|
+
- [Installing / Setting up Rails](#installing--setting-up-rails)
|
34
|
+
- [Install HAML (Optional)](#install-haml-optional)
|
35
|
+
- [Install DaisyUI (Optional)](#install-daisyui-optional)
|
36
|
+
- [Try Out Your Application](#try-out-your-application)
|
37
|
+
- [Debugging](#debugging)
|
38
|
+
- [Testing](#testing)
|
39
|
+
- [Authentication](#authentication)
|
40
|
+
- [Web Console](#web-console)
|
41
|
+
- [BetterErrors (Optional)](#bettererrors-optional)
|
42
|
+
- [LocoMotion Components](#locomotion-components)
|
43
|
+
- [Install](#install)
|
44
|
+
- [Using Components](#using-components)
|
45
|
+
- [Setting a Base Component Class](#setting-a-base-component-class)
|
46
|
+
- [Developing](#developing)
|
47
|
+
- [Tooling](#tooling)
|
48
|
+
- [TODO / Next Steps](#todo--next-steps)
|
49
|
+
|
50
|
+
|
51
|
+
## About
|
52
|
+
|
53
|
+
loco_motion is both a set of philosophies and paradigms for developing robust
|
54
|
+
web applications in Ruby on Rails, as well gems and tools to help you execute
|
55
|
+
on your vision quickly and reliably.
|
56
|
+
|
57
|
+
It includes standards for your
|
58
|
+
|
59
|
+
* Development Environment
|
60
|
+
* Testing / Debugging
|
61
|
+
* CSS / Page Markup
|
62
|
+
* Components / Libraries
|
63
|
+
* Releasing / Hosting
|
64
|
+
* and much more!
|
65
|
+
|
66
|
+
You can use as much or as little of the frameworks and philosophies provided,
|
67
|
+
and you can customize it all to your heart's content.
|
68
|
+
|
69
|
+
## Getting Started
|
70
|
+
|
71
|
+
We recommend using Docker to get your project setup from the beginning. Even
|
72
|
+
before you run the `rails new` command. This ensures that you have a stable
|
73
|
+
development environment, no matter what OS or system you're using to develop.
|
74
|
+
|
75
|
+
It also allows you to troubleshoot and debug the application since the
|
76
|
+
development container is so small and simple with very few dependencies.
|
77
|
+
|
78
|
+
You can download it from https://www.docker.com/.
|
79
|
+
|
80
|
+
Once you have that downloaded, open a terminal, and create a new directory for
|
81
|
+
your project. You can put it anywhere, but we recommend a directory structure
|
82
|
+
similar to the following:
|
83
|
+
|
84
|
+
```shell
|
85
|
+
mkdir -p ~/Development/mycompany/myproject
|
86
|
+
```
|
87
|
+
|
88
|
+
Now, change into that directory:
|
89
|
+
|
90
|
+
```shell
|
91
|
+
cd ~/Development/mycompany/myproject
|
92
|
+
```
|
93
|
+
|
94
|
+
Look in the `examples` directory for basic `docker-compose.yml`, `Dockerfile`,
|
95
|
+
`dev/Dockerfile`, and `entrypoint.sh` files to get you started and give you a
|
96
|
+
place to run commands. Copy these into your project directory.
|
97
|
+
|
98
|
+
Next, we recommend using a [Makefile](/examples/Makefile) (also in
|
99
|
+
`examples`) to create shortcuts for running your various commands. `make` will
|
100
|
+
run on just about any operating system, and provides a self-documenting list of
|
101
|
+
all of the ways that you typically interact with your application. This means
|
102
|
+
that other developers can quickly see the common use-cases, but will also have a
|
103
|
+
starting point if they need to customize any of the commands for their
|
104
|
+
particular setup.
|
105
|
+
|
106
|
+
Copy this `Makefile` into your top-level project directory as well.
|
107
|
+
|
108
|
+
Your directory structure should look like this:
|
109
|
+
|
110
|
+
```txt
|
111
|
+
- ~/Development
|
112
|
+
- mycompany
|
113
|
+
- myproject
|
114
|
+
- Dockerfile
|
115
|
+
- Makefile
|
116
|
+
- dev
|
117
|
+
- Dockerfile
|
118
|
+
- docker-compose.yml
|
119
|
+
- entrypoint.sh
|
120
|
+
```
|
121
|
+
|
122
|
+
Finally, we recommend [VSCode](https://code.visualstudio.com/) as your code
|
123
|
+
editor, but this is purely preference. It has a lot of plugins that make it
|
124
|
+
really customizable, but utlimately, you should use whatever editor makes you
|
125
|
+
most comfortable during development.
|
126
|
+
|
127
|
+
You should now be able to run `make dev` in a terminal inside your project
|
128
|
+
directory to build and run all of the containers.
|
129
|
+
|
130
|
+
Once they have all built and started, in a separate terminal, you can run
|
131
|
+
`make dev-shell` to open a Bash shell into your development container.
|
132
|
+
|
133
|
+
Congratulations! You're ready to create your Rails app!
|
134
|
+
|
135
|
+
## Installing / Setting up Rails
|
136
|
+
|
137
|
+
Once you're inside of the development container, everything should be setup and
|
138
|
+
ready for you to install Ruby on Rails.
|
139
|
+
|
140
|
+
Change into the app directory which is mapped to your local machine and run the
|
141
|
+
`rails new` command:
|
142
|
+
|
143
|
+
> [!NOTE]
|
144
|
+
> If you want to use something other than PostgreSQL or TailwindCSS, you can
|
145
|
+
> change that here. These are just our recommendations.
|
146
|
+
|
147
|
+
> [!TIP]
|
148
|
+
> We tend to recommend that you lag behind on the latest version of Ruby as
|
149
|
+
> it can occassionally have issues building the Rails project. But you can
|
150
|
+
> swap it to the latest inside of the `dev/Dockerfile` by changing the `FROM`
|
151
|
+
> line at the top.
|
152
|
+
|
153
|
+
```shell
|
154
|
+
cd /home/app && rails new . --skip --database=postgresql --javascript=esbuild --css=tailwind
|
155
|
+
```
|
156
|
+
|
157
|
+
If you run into trouble with the above Rails command, this should get you back
|
158
|
+
to a good starting point without having to blow away any changes you might have
|
159
|
+
made to the dev files.
|
160
|
+
|
161
|
+
```shell
|
162
|
+
rm -rf .dockerignore .git .gitattributes .gitignore .node-version .ruby-version\
|
163
|
+
Gemfile README.md Rakefile app bin config config.ru
|
164
|
+
```
|
165
|
+
|
166
|
+
Once complete, you should now be able to exit out of the dev container and kill
|
167
|
+
the running docker containers with <kbd>Ctrl-C</kbd> in the running terminal, or
|
168
|
+
you can open a new terminal and run `make down`.
|
169
|
+
|
170
|
+
Open the newly created `config/database.yml` file and add the following three
|
171
|
+
lines under the `default` key:
|
172
|
+
|
173
|
+
```yaml
|
174
|
+
host: db
|
175
|
+
username: postgres
|
176
|
+
password: password
|
177
|
+
```
|
178
|
+
|
179
|
+
Now, uncomment the `app` section in your `docker-compose.yml` file and run
|
180
|
+
`make app` to build the application.
|
181
|
+
|
182
|
+
After a minute or two, everything should be booted up and you should see output
|
183
|
+
similar to the following:
|
184
|
+
|
185
|
+
```txt
|
186
|
+
myproject-app-1 | == Restarting application server ==
|
187
|
+
myproject-app-1 | => Booting Puma
|
188
|
+
myproject-app-1 | => Rails 7.1.2 application starting in development
|
189
|
+
myproject-app-1 | => Run `bin/rails server --help` for more startup options
|
190
|
+
myproject-app-1 | Puma starting in single mode...
|
191
|
+
myproject-app-1 | * Puma version: 6.4.0 (ruby 3.3.0-p-1) ("The Eagle of Durango")
|
192
|
+
myproject-app-1 | * Min threads: 5
|
193
|
+
myproject-app-1 | * Max threads: 5
|
194
|
+
myproject-app-1 | * Environment: development
|
195
|
+
myproject-app-1 | * PID: 1
|
196
|
+
myproject-app-1 | * Listening on http://0.0.0.0:3000
|
197
|
+
myproject-app-1 | Use Ctrl-C to stop
|
198
|
+
```
|
199
|
+
|
200
|
+
Congratulations!
|
201
|
+
|
202
|
+
You can now visit [http://localhost:3000](http://localhost:3000) in your web
|
203
|
+
browser and see your running Rails application!
|
204
|
+
|
205
|
+
### Install HAML (Optional)
|
206
|
+
|
207
|
+
While you can use the default ERB templating system that comes with Rails, we
|
208
|
+
highly recommend using [HAML](https://haml.info/) instead as it provides a much
|
209
|
+
cleaner language for your template files.
|
210
|
+
|
211
|
+
Drop this at the bottom of your `Gemfile`:
|
212
|
+
|
213
|
+
> [!NOTE]
|
214
|
+
> We suggest keeping your custom gems alphabetized at the bottom.
|
215
|
+
|
216
|
+
```yaml
|
217
|
+
# App-Specific Gems
|
218
|
+
gem "haml-rails", "~> 2.0"
|
219
|
+
```
|
220
|
+
|
221
|
+
And add the following to your `Gemfile` in the `group :development` section:
|
222
|
+
|
223
|
+
```yaml
|
224
|
+
gem 'html2haml'
|
225
|
+
```
|
226
|
+
|
227
|
+
Next, open up a Docker shell in the app container using `make app-shell` and
|
228
|
+
run `bundle` to install the HAML gem.
|
229
|
+
|
230
|
+
Next, open up your `tailwind.config.js` file and replace the line for `erb`
|
231
|
+
views with `haml` views:
|
232
|
+
|
233
|
+
```js
|
234
|
+
module.exports = {
|
235
|
+
content: [
|
236
|
+
'./app/views/**/*.html.haml',
|
237
|
+
// ...
|
238
|
+
]
|
239
|
+
```
|
240
|
+
|
241
|
+
Finally, you can run the following command to replace all of your `.erb`
|
242
|
+
files with `.haml` versions:
|
243
|
+
|
244
|
+
```bash
|
245
|
+
HAML_RAILS_DELETE_ERB=true rails haml:erb2haml
|
246
|
+
```
|
247
|
+
|
248
|
+
You should see output similar to the following:
|
249
|
+
|
250
|
+
```text
|
251
|
+
--------------------------------------------------------------------------------
|
252
|
+
Generating HAML for app/views/layouts/application.html.erb...
|
253
|
+
Generating HAML for app/views/layouts/mailer.html.erb...
|
254
|
+
Generating HAML for app/views/layouts/mailer.text.erb...
|
255
|
+
--------------------------------------------------------------------------------
|
256
|
+
HAML generated for the following files:
|
257
|
+
app/views/layouts/application.html.erb
|
258
|
+
app/views/layouts/mailer.html.erb
|
259
|
+
app/views/layouts/mailer.text.erb
|
260
|
+
--------------------------------------------------------------------------------
|
261
|
+
Deleting original .erb files.
|
262
|
+
--------------------------------------------------------------------------------
|
263
|
+
Task complete!
|
264
|
+
```
|
265
|
+
|
266
|
+
### Install DaisyUI (Optional)
|
267
|
+
|
268
|
+
Next up, let's utilize a mighty combo for our CSS layer!
|
269
|
+
|
270
|
+
[TailwindCSS](https://tailwindcss.com/) is a utility-based CSS framework which
|
271
|
+
allows you to easily build your own components by piecing together the utility
|
272
|
+
classes that you need.
|
273
|
+
|
274
|
+
For example, to make a rounded button, you might do something like this:
|
275
|
+
|
276
|
+
```haml
|
277
|
+
%button.px-4.py-2.border.rounded-lg
|
278
|
+
My Button
|
279
|
+
```
|
280
|
+
|
281
|
+
> [!IMPORTANT]
|
282
|
+
> We _highly_ recommend using Tailwind for every project and have already
|
283
|
+
> installed it as part of the `rails new` command above.
|
284
|
+
|
285
|
+
[DaisyUI](https://daisyui.com/) takes a more traditional route and provides a
|
286
|
+
set of classes that utilize Tailwind to create the components for you. This
|
287
|
+
means your button above would look more like this:
|
288
|
+
|
289
|
+
```haml
|
290
|
+
%button.btn
|
291
|
+
My Button
|
292
|
+
```
|
293
|
+
|
294
|
+
If you want pure customization or are building your own UI components from
|
295
|
+
scratch, we recommend that you stick with Tailwind by itself.
|
296
|
+
|
297
|
+
However, if you're working on a project and want a good starting point for UI
|
298
|
+
components, you might checkout DaisyUI or a simliar Tailwind-based UI library.
|
299
|
+
|
300
|
+
DaisyUI is a plugin for Tailwind, so installing it is dead simple. Just open up
|
301
|
+
an app shell by running `make app-shell` in the terminal and run the following
|
302
|
+
command:
|
303
|
+
|
304
|
+
```shell
|
305
|
+
yarn add daisyui@latest --dev
|
306
|
+
```
|
307
|
+
|
308
|
+
Next, edit your `tailwind.config.js` file to add it as a plugin:
|
309
|
+
|
310
|
+
> [!IMPORTANT]
|
311
|
+
> Make sure to add a `,` to the previous line if you put it at the bottom.
|
312
|
+
|
313
|
+
```js
|
314
|
+
module.exports = {
|
315
|
+
//...
|
316
|
+
plugins: [require("daisyui")],
|
317
|
+
}
|
318
|
+
```
|
319
|
+
|
320
|
+
> [!IMPORTANT]
|
321
|
+
> Moving forward, this guide will assume you have installed DaisyUI, so some of
|
322
|
+
> the example view files will utilize these CSS classes.
|
323
|
+
|
324
|
+
### Try Out Your Application
|
325
|
+
|
326
|
+
Now that we have everything installed and running, let's build a few simple
|
327
|
+
parts of a Rails application to test that everything is working properly!
|
328
|
+
|
329
|
+
By default, only the Rails application is running, but we now need to build
|
330
|
+
and bundle our Javascript and CSS.
|
331
|
+
|
332
|
+
Open up your `Procfile.dev` and tell the Rails server to bind to `0.0.0.0`:
|
333
|
+
|
334
|
+
```
|
335
|
+
web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0
|
336
|
+
```
|
337
|
+
|
338
|
+
Next, you'll need to update the `Dockerfile` to tell Docker how to start
|
339
|
+
your app using Foreman.
|
340
|
+
|
341
|
+
Change the following line:
|
342
|
+
|
343
|
+
```Dockerfile
|
344
|
+
CMD ["rails", "server", "-b", "0.0.0.0"]
|
345
|
+
```
|
346
|
+
|
347
|
+
to
|
348
|
+
|
349
|
+
```Dockerfile
|
350
|
+
CMD ["./bin/dev"]
|
351
|
+
```
|
352
|
+
|
353
|
+
Since we're using Docker, you might also want to edit your `bin/setup` file
|
354
|
+
to automatically remove any old PID files that might be lying around from a bad
|
355
|
+
container shutdown.
|
356
|
+
|
357
|
+
Add the following lines right above the last few lines that restart the
|
358
|
+
application server:
|
359
|
+
|
360
|
+
```sh
|
361
|
+
puts "\n== Removing old PID files =="
|
362
|
+
system! "rm -rf /home/app/tmp/pids/server.pid"
|
363
|
+
```
|
364
|
+
|
365
|
+
Finally, you can kill your running docker containers (either using
|
366
|
+
<kbd>Ctrl-C</kbd>, opening a new terminal in your project folder and running
|
367
|
+
`make down`, or using the Docker UI to stop all of the containers).
|
368
|
+
|
369
|
+
Now restart using `make app`.
|
370
|
+
|
371
|
+
> [!TIP]
|
372
|
+
> Once you have stabalized your Dockerfile and any dependencies, you can run
|
373
|
+
> `make app-quick` to launch the containers without rebuilding.
|
374
|
+
>
|
375
|
+
> In this case, since we changed our `Dockerfile`, we still need to use the
|
376
|
+
> regular `make app` command.
|
377
|
+
|
378
|
+
You should be able to test that everything is working by altering a few files so
|
379
|
+
you can see some custom output:
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
# config/routes.rb
|
383
|
+
|
384
|
+
root "application#test"
|
385
|
+
```
|
386
|
+
|
387
|
+
```ruby
|
388
|
+
# app/controllers/application_controller.rb
|
389
|
+
|
390
|
+
class ApplicationController < ActionController::Base
|
391
|
+
def test
|
392
|
+
render html: 'Test', layout: true
|
393
|
+
end
|
394
|
+
end
|
395
|
+
```
|
396
|
+
|
397
|
+
```haml
|
398
|
+
# app/views/layouts/application.html.haml
|
399
|
+
|
400
|
+
# Just modify the body & yield lines to look like this
|
401
|
+
|
402
|
+
%body
|
403
|
+
.m-2.p-2.rounded.bg-red-400
|
404
|
+
= yield
|
405
|
+
```
|
406
|
+
|
407
|
+
Now visit [http://localhost:3000](http://localhost:3000) and you should
|
408
|
+
see a red, rounded box with the word "Test"!
|
409
|
+
|
410
|
+
If you also installed, DaisyUI, we can test that as well. Add some additional
|
411
|
+
code to the bottom of the `application.html.haml` file:
|
412
|
+
|
413
|
+
```haml
|
414
|
+
# app/views/layouts/application.html.haml
|
415
|
+
|
416
|
+
# Leave the html / head code above
|
417
|
+
|
418
|
+
%body
|
419
|
+
.m-2.p-2.rounded.bg-red-400
|
420
|
+
= yield
|
421
|
+
|
422
|
+
# Add this
|
423
|
+
.btn
|
424
|
+
Test Button
|
425
|
+
```
|
426
|
+
|
427
|
+
If everything worked, you should see a gray button that changes when
|
428
|
+
you hover and click on it!
|
429
|
+
|
430
|
+
> [!CAUTION]
|
431
|
+
> Once you're done playing around with this, you should undo your changes to the
|
432
|
+
> layout so that it doesn't cause confusion in later parts of this guide.
|
433
|
+
|
434
|
+
## Debugging
|
435
|
+
|
436
|
+
The latest version of Rails makes it much easier to debug within a Docker
|
437
|
+
container as it automatically starts a remote debugger for you.
|
438
|
+
|
439
|
+
Add the word `debugger` anywhere in your code (perhaps the `test` method of your
|
440
|
+
`ApplicationController`), reload the page (it will look like it's hanging), and
|
441
|
+
then run `make app-debug` in a separate terminal.
|
442
|
+
|
443
|
+
This will connect to the remote debugger instance which will be stopped at your
|
444
|
+
`debugger` line.
|
445
|
+
|
446
|
+
## Testing
|
447
|
+
|
448
|
+
Before we start creating a bunch of models, controllers, and other pieces of
|
449
|
+
code, it's good to get a solid testing foundation in place. Rails ships with
|
450
|
+
[MiniTest](https://guides.rubyonrails.org/testing.html) out of the box and many
|
451
|
+
people prefer this as it's built-in and is essentially just Ruby code.
|
452
|
+
|
453
|
+
However, many larger teams opt to utilize [RSpec](https://rspec.info/) which is
|
454
|
+
a Behavior Driven Development (BDD) framework whose tests utilize the english
|
455
|
+
language to help you build relevant test cases. It also has a large ecosystem of
|
456
|
+
plugins which can accelerate your development.
|
457
|
+
|
458
|
+
Which one you choose is up to you, but after developing many applications, we
|
459
|
+
recommned Rspec with [factory_bot](https://github.com/thoughtbot/factory_bot)
|
460
|
+
and [Shoulda Matchers](https://github.com/thoughtbot/shoulda-matchers).
|
461
|
+
|
462
|
+
Finally, although both libraries offer some functionality for testing your user
|
463
|
+
interface, we recommend utilizing [Cypress](https://www.cypress.io/) instead as
|
464
|
+
it more closely mimics the real user experience in a browser and it allows you
|
465
|
+
to see in real-time what is happening, including in-browser debugging!
|
466
|
+
|
467
|
+
> [!NOTE]
|
468
|
+
> One thing to note about Cypress, however, is that it is Javascript-based and
|
469
|
+
> thus requires you to write tests in Javascript. If you are only famililar with
|
470
|
+
> Ruby, you might want to stick with Rspec or Minitest when you first start your
|
471
|
+
> project, and expand into using Cypress once you are comfortable learning a new
|
472
|
+
> lanugage / framework.
|
473
|
+
|
474
|
+
## Authentication
|
475
|
+
|
476
|
+
There are a **lot** of different ways to handle user authentication in Ruby on
|
477
|
+
Rails. Because of this, many gems have popped up to help you handle this. The
|
478
|
+
two most popular ones are [OmniAuth](https://github.com/omniauth/omniauth) and
|
479
|
+
[Devise](https://github.com/heartcombo/devise).
|
480
|
+
|
481
|
+
We recommend starting with OmniAuth because it has a very simple `:developer`
|
482
|
+
authentication strategy which will allow you to get started very quickly, and
|
483
|
+
it allows you to
|
484
|
+
[integrate with devise](https://github.com/heartcombo/devise#omniauth) or a
|
485
|
+
service like [Auth0](https://auth0.com/) later if you choose.
|
486
|
+
|
487
|
+
> [!TIP]
|
488
|
+
> You can always find the latest setup documentation on OmniAuth's README.
|
489
|
+
|
490
|
+
Add the relevant gems to your application's `Gemfile` and re-run
|
491
|
+
`bundle install`:
|
492
|
+
|
493
|
+
```Gemfile
|
494
|
+
gem 'omniauth'
|
495
|
+
gem "omniauth-rails_csrf_protection"
|
496
|
+
```
|
497
|
+
|
498
|
+
After that has finished, you'll need to restart your Rails server.
|
499
|
+
|
500
|
+
> [!TIP]
|
501
|
+
> Although you can do this by using <kbd>Ctrl-C</kbd> and re-running `make
|
502
|
+
> app-quick`, a faster way to restart only the web server is to create a
|
503
|
+
> temporary file named `restart.txt`.
|
504
|
+
>
|
505
|
+
> You can easily do this by running `touch tmp/restart.txt` in a terminal!
|
506
|
+
|
507
|
+
Next, create an OmniAuth initializer:
|
508
|
+
|
509
|
+
```ruby
|
510
|
+
# config/initializers/omniauth.rb
|
511
|
+
|
512
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
513
|
+
provider :developer if Rails.env.development?
|
514
|
+
end
|
515
|
+
```
|
516
|
+
|
517
|
+
We'll need to setup a few routes:
|
518
|
+
|
519
|
+
```ruby
|
520
|
+
# config/routes.rb
|
521
|
+
|
522
|
+
get '/auth/:provider/callback', to: 'sessions#create'
|
523
|
+
get '/login', to: 'sessions#new'
|
524
|
+
```
|
525
|
+
|
526
|
+
Finally, we'll need to add the relevant sessions controller and view:
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
# app/controllers/sessions_controller.rb
|
530
|
+
|
531
|
+
class SessionsController < ApplicationController
|
532
|
+
def new
|
533
|
+
render :new
|
534
|
+
end
|
535
|
+
|
536
|
+
def create
|
537
|
+
user_info = request.env['omniauth.auth']
|
538
|
+
raise user_info # Your own session management should be placed here.
|
539
|
+
|
540
|
+
session[:user_info] = user_info.to_hash
|
541
|
+
|
542
|
+
redirect_to root_path
|
543
|
+
end
|
544
|
+
end
|
545
|
+
```
|
546
|
+
|
547
|
+
```haml
|
548
|
+
=# app/views/sessions/new.html.haml
|
549
|
+
|
550
|
+
- if Rails.env.development?
|
551
|
+
= form_tag('/auth/developer', method: 'post', data: {turbo: false}) do
|
552
|
+
%button.btn{ type: 'submit' }
|
553
|
+
Login with Developer
|
554
|
+
```
|
555
|
+
|
556
|
+
From here, you can login by visiting http://localhost:3000/login, clicking the
|
557
|
+
button, and entering a random name and email address.
|
558
|
+
|
559
|
+
It should throw an error and show you the line that it failed on
|
560
|
+
(`raise user_info`).
|
561
|
+
|
562
|
+
This is not terribly helpful as you can't easily inspect the variable and see
|
563
|
+
it's value.
|
564
|
+
|
565
|
+
In general, you'd want to set this to something like `session[:user_info]` and
|
566
|
+
integrate it into your application flow.
|
567
|
+
|
568
|
+
When you're ready for it to work, just delete or comment out the
|
569
|
+
`raise user_info` line.
|
570
|
+
|
571
|
+
However, this gives us an opportune time to get some better error management.
|
572
|
+
So let's do that first!
|
573
|
+
|
574
|
+
## Web Console
|
575
|
+
|
576
|
+
At this point, if you look in your Docker logs, you'll probably see a line like
|
577
|
+
the following:
|
578
|
+
|
579
|
+
```text
|
580
|
+
Cannot render console from 172.23.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1
|
581
|
+
```
|
582
|
+
|
583
|
+
> [!NOTE]
|
584
|
+
> Your IP address may be different! Take note of what IP the error says.
|
585
|
+
|
586
|
+
Because we're running inside Docker, we have a different network than what Rails
|
587
|
+
typically expects (127.0.0.1) and it blocks the default web console that loads
|
588
|
+
when an error happens.
|
589
|
+
|
590
|
+
This is easy to fix, we just need to take the IP address in the error message
|
591
|
+
above and add the following line to our `config/environments/development.rb`
|
592
|
+
file:
|
593
|
+
|
594
|
+
```ruby
|
595
|
+
# Fix console permissions for Docker
|
596
|
+
config.web_console.permissions = '172.23.0.1'
|
597
|
+
```
|
598
|
+
|
599
|
+
Restart the application and refresh the page. You should see the same error
|
600
|
+
appear, but now, you should see a black console at the bottom of the screen that
|
601
|
+
allows you to interact with the application.
|
602
|
+
|
603
|
+
Type the following in the console and hit enter:
|
604
|
+
|
605
|
+
```ruby
|
606
|
+
user_info.to_hash
|
607
|
+
```
|
608
|
+
|
609
|
+
You should see some information about the user you just logged in with.
|
610
|
+
|
611
|
+
You can run pretty much any code in this console that you would run inside your
|
612
|
+
controllers, views, models, etc.
|
613
|
+
|
614
|
+
In fact, when I'm debugging an issue, I often find a point just above where I'm
|
615
|
+
wanting to look, type something non-existant like `asdf` in my Rails code, and
|
616
|
+
then refresh the page.
|
617
|
+
|
618
|
+
This will stop the application where the `asdf` was found and allows you to
|
619
|
+
interact with your application and see exactly what's going on.
|
620
|
+
|
621
|
+
## BetterErrors (Optional)
|
622
|
+
|
623
|
+
[BetterErrors](https://github.com/BetterErrors/better_errors) provides (in our
|
624
|
+
humble opinion) a slightly better interface for the errors that sometimes happen
|
625
|
+
in a Rails application.
|
626
|
+
|
627
|
+
In particular, we like how it lays out the stack trace to the left of the code
|
628
|
+
and console and adds a bit more styling to the page to make it easier to read.
|
629
|
+
|
630
|
+
It's also very easy to install!
|
631
|
+
|
632
|
+
Add the following to your `Gemfile` and re-run `bundle install` inside of the
|
633
|
+
Docker app container (`make app-shell`).
|
634
|
+
|
635
|
+
> [!TIP]
|
636
|
+
> You can also just kill (using <kbd>Ctrl-C</kbd>) and restart the container
|
637
|
+
> using `make app-quick` as this process attempts to install any gems for you.
|
638
|
+
|
639
|
+
|
640
|
+
```Gemfile
|
641
|
+
# Gemfile
|
642
|
+
|
643
|
+
group :development do
|
644
|
+
gem "better_errors"
|
645
|
+
gem "binding_of_caller"
|
646
|
+
end
|
647
|
+
```
|
648
|
+
|
649
|
+
> [!IMPORTANT]
|
650
|
+
> It is imperitive that you put these in the `:development` tag so that they
|
651
|
+
> cannot load in production.
|
652
|
+
>
|
653
|
+
> This would lead to a **massive** security risk!
|
654
|
+
|
655
|
+
Again, because we're running inside of Docker, we'll need to tell BetterErrors
|
656
|
+
that it's allowed to render for our IP address.
|
657
|
+
|
658
|
+
Add the following to the `config/environments/development.rb` file (make sure
|
659
|
+
the IP address matches the one you used for the Web Console above):
|
660
|
+
|
661
|
+
```ruby
|
662
|
+
# Allow BetterErrors to render
|
663
|
+
BetterErrors::Middleware.allow_ip! '172.23.0.1'
|
664
|
+
```
|
665
|
+
|
666
|
+
## LocoMotion Components
|
667
|
+
|
668
|
+
In addition to the recommendations / suggestions above, LocoMotion also provides
|
669
|
+
a full set of UI components to help you build robust and full-featured apps.
|
670
|
+
|
671
|
+
> [!CAUTION]
|
672
|
+
> The LocoMotion components are being actively developed and are NOT ready for
|
673
|
+
> production / public use (currently they are just some example components while
|
674
|
+
> I get everything setup). I'm mainly adding the docs here so that I remember
|
675
|
+
> how to set them up properly when they are ready for release.
|
676
|
+
|
677
|
+
### Install
|
678
|
+
|
679
|
+
Add the following to your `Gemfile` and re-run `bundle`:
|
680
|
+
|
681
|
+
```Gemfile
|
682
|
+
# Gemfile
|
683
|
+
|
684
|
+
gem "loco_motion", github: "profoundry-us/loco_motion", branch: "main", require: "loco_motion"
|
685
|
+
|
686
|
+
# or
|
687
|
+
|
688
|
+
gem "loco_motion-rails", "0.0.6", require: "loco_motion"
|
689
|
+
```
|
690
|
+
|
691
|
+
Next add the following lines to the `contents` section of your
|
692
|
+
`tailwind.config.js` to import / build the proper files:
|
693
|
+
|
694
|
+
```js
|
695
|
+
const { execSync } = require('child_process');
|
696
|
+
|
697
|
+
let locoBundlePath = execSync('bundle show loco_motion').toString().trim();
|
698
|
+
|
699
|
+
module.exports = {
|
700
|
+
content:[
|
701
|
+
`${locoBundlePath}/app/components/**/*.{rb,js,html.haml}`,
|
702
|
+
|
703
|
+
// ...
|
704
|
+
]
|
705
|
+
}
|
706
|
+
```
|
707
|
+
|
708
|
+
> [!WARNING]
|
709
|
+
> Note that this will not output anything if it fails to find the right
|
710
|
+
> directory, so your CSS may stop working if you update the gem and forget to
|
711
|
+
> update this setting.
|
712
|
+
|
713
|
+
Next, if you're using any of the components that require JavaScript (like the
|
714
|
+
Countdown component), you'll need to add the library as a dependency and include
|
715
|
+
those controllers in your `application.js` file.
|
716
|
+
|
717
|
+
```sh
|
718
|
+
npm add @profoundry-us/loco_motion
|
719
|
+
```
|
720
|
+
|
721
|
+
or
|
722
|
+
|
723
|
+
```sh
|
724
|
+
yarn add @profoundry-us/loco_motion
|
725
|
+
```
|
726
|
+
|
727
|
+
Then inside your `application.js` file, make sure to import and register the
|
728
|
+
relevant controllers.
|
729
|
+
|
730
|
+
```js
|
731
|
+
import { Application } from "@hotwired/stimulus"
|
732
|
+
|
733
|
+
import { CountdownController } from "@profoundry-us/loco_motion"
|
734
|
+
|
735
|
+
const application = Application.start()
|
736
|
+
|
737
|
+
application.register("countdown", CountdownController)
|
738
|
+
|
739
|
+
export { application }
|
740
|
+
```
|
741
|
+
|
742
|
+
### Using Components
|
743
|
+
|
744
|
+
Back in the `app/layouts/application.html.haml` file, replace the `body` with
|
745
|
+
the following code and refresh your page.
|
746
|
+
|
747
|
+
```haml
|
748
|
+
%body
|
749
|
+
.m-2.p-2.rounded.bg-red-400
|
750
|
+
= session[:user_info].inspect
|
751
|
+
|
752
|
+
%div
|
753
|
+
= render(Daisy::Actions::ButtonComponent.new(title: "Click Me"))
|
754
|
+
|
755
|
+
%div
|
756
|
+
= daisy_button(css: "btn-primary") do
|
757
|
+
Click Me Too
|
758
|
+
|
759
|
+
= yield
|
760
|
+
```
|
761
|
+
|
762
|
+
You should see a few buttons and the user info that we saved from OmniAuth
|
763
|
+
represented as a Ruby hash! Any other content you have will be rendered below.
|
764
|
+
|
765
|
+
### Setting a Base Component Class
|
766
|
+
|
767
|
+
Sometimes, you may want to override the way that LocoMotion handles things, or
|
768
|
+
provide some functionality yourself in a sub-class of our components. Since you
|
769
|
+
can't have a class inherit from two classes, we give you a way to override the
|
770
|
+
base class that all of our components inherit from.
|
771
|
+
|
772
|
+
This allows you to define a class that inherits from `LocoMotion::BaseComponent`
|
773
|
+
and then adds any special methods or overrides to our default components.
|
774
|
+
|
775
|
+
Create a file called `app/components/application_component.rb` with the following
|
776
|
+
contents:
|
777
|
+
|
778
|
+
```ruby
|
779
|
+
class ApplicationComponent < LocoMotion::BaseComponent
|
780
|
+
end
|
781
|
+
```
|
782
|
+
|
783
|
+
Then add the following to `config/initializers/loco_motion.rb`.
|
784
|
+
|
785
|
+
|
786
|
+
```ruby
|
787
|
+
LocoMotion.configure do |config|
|
788
|
+
|
789
|
+
# Override the base component class to inherit from our ApplicationComponent
|
790
|
+
# so that we can add our own overrides / methods.
|
791
|
+
Rails.application.config.after_initialize do
|
792
|
+
config.base_component_class = ApplicationComponent
|
793
|
+
end
|
794
|
+
|
795
|
+
end
|
796
|
+
```
|
797
|
+
|
798
|
+
> [!NOTE]
|
799
|
+
> It doesn't have to inherit from `ApplicationComponent`, you can use any class
|
800
|
+
> you want, so you could create a separate `CustomizedLocoMotionComponent` class
|
801
|
+
> so that you don't have any conflicts with your `ApplicationComponent`.
|
802
|
+
|
803
|
+
## Developing
|
804
|
+
|
805
|
+
To work on LocoMotion, first clone the repository and make sure you have Docker
|
806
|
+
installed and running on your machine.
|
807
|
+
|
808
|
+
You should then be able to run `make rebuild` in the project directory and then
|
809
|
+
`make all-quick` to start the services.
|
810
|
+
|
811
|
+
> [!NOTE]
|
812
|
+
>
|
813
|
+
> We use `npm link` within the `docs/demo/bin/dev` script to enable quick
|
814
|
+
> editing of the JavaScript library files so you don't have to publish a new
|
815
|
+
> package during testing.
|
816
|
+
|
817
|
+
From here, you can access the demo site at http://localhost:3000 and the YARD
|
818
|
+
docs at http://localhost:8808/docs/yard
|
819
|
+
|
820
|
+
You can type `make demo-shell` to open a shell inside the demo Docker container,
|
821
|
+
or `make loco-shell` to get a shell inside the gem's Docker container.
|
822
|
+
|
823
|
+
See the `Makefile` for all available commands.
|
824
|
+
|
825
|
+
> [!WARNING]
|
826
|
+
>
|
827
|
+
> Right now, Rails doesn't auto-reload the LocoMotion library files when they
|
828
|
+
> change, so you might have to restart your server to get it to pickup the
|
829
|
+
> changes.
|
830
|
+
>
|
831
|
+
> ```sh
|
832
|
+
> make demo-restart
|
833
|
+
> ```
|
834
|
+
|
835
|
+
### Tooling
|
836
|
+
|
837
|
+
For VSCode, you may want to add the following to your settings to get
|
838
|
+
TailwindCSS Intellisense working properly.
|
839
|
+
|
840
|
+
```json
|
841
|
+
"tailwindCSS.emmetCompletions": true,
|
842
|
+
"tailwindCSS.includeLanguages": {
|
843
|
+
"haml": "html",
|
844
|
+
"ruby": "html",
|
845
|
+
},
|
846
|
+
"files.associations": {
|
847
|
+
"*.html.haml": "haml"
|
848
|
+
},
|
849
|
+
"tailwindCSS.experimental.classRegex": [
|
850
|
+
[ "add_css\\(:[a-z]+, ?\"([^\"]*)\"", "([a-zA-Z0-9\\-:]+)" ],
|
851
|
+
[ "css: ?\"([^\"]*)\"", "([a-zA-Z0-9\\-:]+)" ],
|
852
|
+
[ "class: ?\"([^\"]*)\"", "([a-zA-Z0-9\\-:]+)" ],
|
853
|
+
[ "(\\.[\\w\\-.]+)[\\n\\=\\{\\s]", "([\\w\\-]+)" ],
|
854
|
+
],
|
855
|
+
```
|
856
|
+
|
857
|
+
## TODO / Next Steps
|
858
|
+
|
859
|
+
There is a LOT left to be done. We're not currently seeking assistance, but if
|
860
|
+
you feel very strongly that you'd like to contribute, please reach out through
|
861
|
+
the GitHub Discussions feature and let us know!
|
862
|
+
|
863
|
+
- [x] Basic versions of DaisyUI Actions
|
864
|
+
- [x] Basic versions of DaisyUI Data Display
|
865
|
+
- [x] Basic versions of DaisyUI Navigation
|
866
|
+
- [ ] Basic versions of DaisyUI Feedback
|
867
|
+
- [ ] Basic versions of DaisyUI Data Input
|
868
|
+
- [ ] Basic versions of DaisyUI Layout
|
869
|
+
- [ ] Basic versions of DaisyUI Mockup
|
870
|
+
- [ ] Get YARD docs rendering with (better) Markdown
|
871
|
+
- [x] Extract relevant pieces into a yard-loco_motion plugin
|
872
|
+
- [ ] Publish Gem
|
873
|
+
- [x] Publish NPM package
|
874
|
+
- [ ] Update YARD plugin to add `@part`s
|
875
|
+
- [x] Extract doc callouts into a doc component (and / or the Daisy component)
|
876
|
+
- [ ] Choose and recommend / document a pagination gem
|
877
|
+
- [ ] Discuss caching techniques / setup
|
878
|
+
- [ ] Create / publish a production version of the demo site
|
879
|
+
- [ ] Create / publish a production version of the docs site
|
880
|
+
- [ ] Update demo site to allow for a different docs site using ENV var
|