Skip to content

Commit 0e9088d

Browse files
committed
Merge branch '2.0.0' of github.com:matestack/matestack-ui-core into 2.0.0
2 parents 65a9165 + 336b23f commit 0e9088d

File tree

5 files changed

+61
-40
lines changed

5 files changed

+61
-40
lines changed
File renamed without changes.
File renamed without changes.

docs/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
* [Installation & Update](getting-started/installation-update.md)
99
* [Concepts & Rails Integration](getting-started/concepts-rails-integration.md)
10-
* [Quick Start \[WIP\]](getting-started/quick-start.md)
10+
* [Tutorial](getting-started/quick-start.md)
1111
* [Support & Feedback \[WIP\]](getting-started/support-and-feedback.md)
1212
* [Common Issues \[WIP\]](getting-started/common-issues.md)
1313

docs/getting-started/concepts-rails-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Based on a strong foundation - Rails with all the sugar you love - Matestack ena
1212

1313
**which leads to beautiful reactive web UI implemented in pure Ruby:**
1414

15-
![](../.gitbook/assets/image%20%289%29%20%281%29.png)
15+
![](../.gitbook/assets/image%20%289%29%20%281%29%20%281%29.png)
1616

1717
yielding following advantages:
1818

docs/getting-started/quick-start.md

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
# Quick Start \[WIP\]
1+
# Tutorial
22

3-
{% hint style="danger" %}
4-
Migration to 2.0.0 in progress
5-
{% endhint %}
3+
## Create a reactive Twitter clone in pure Ruby
64

75
In this step-by-step guide, I will show you how to create a Twitter clone in pure Ruby with Matestack, following the great screencasts from Chris McCord [Phoenix LiveView Twitter Clone](https://youtu.be/MZvmYaFkNJI) and Nate Hopkins [Stimulus Reflex Twitter Clone](https://youtu.be/F5hA79vKE_E). We will use the Gem `matestack-ui-core`, which enables us to implement our UI in some Ruby classes rather than writing ERB, HAML or Slim views. Furthermore we don't need to touch JavaScript in order to create reactive UI features, such as updating the DOM without a full browser page reload or syncing multiple web clients through Action Cable!
86

9-
I've added a screencast \(two parts\) showing you what you will be doing in this tutorial:
7+
I've added a small demo showing you what you will be creating in this tutorial:
108

119
[![](https://img.youtube.com/vi/Mue5gs6Wtq4/0.jpg)](https://www.youtube.com/watch?v=Mue5gs6Wtq4)
1210

1311
_This guide utilizes the full power of Matestack and uses `matestack-ui-core` as a complete substitute for Rails views. If you only want to create UI components in pure Ruby on existing Rails views, please check out_ [_this guide_](https://docs.matestack.io/docs/ui_components/100-rails_integration)
1412

15-
## Setup
13+
### Setup
1614

1715
* [x] Create a new Rails app and install some dependencies:
1816

@@ -29,7 +27,7 @@ yarn add matestack-ui-core
2927
rails g scaffold Post body:text likes_count:integer username:string
3028
```
3129

32-
## Model & Database
30+
### Model & Database
3331

3432
* [x] Modify generated migration in order to add defaults:
3533

@@ -70,7 +68,7 @@ class Post < ApplicationRecord
7068
end
7169
```
7270

73-
## Import Matestack's JavaScript
71+
### Import Matestack's JavaScript
7472

7573
Previously, in version 1.5, Vue and Vuex were imported automatically. Now this must be done manually which is the webpacker way. You can import it in `app/javascript/packs/application.js` or in another pack if you need.
7674

@@ -104,7 +102,7 @@ document.addEventListener('DOMContentLoaded', () => {
104102
})
105103
```
106104

107-
## Application Layout and Views
105+
### Application Layout and Views
108106

109107
On `app/views/layouts/application.html.erb` do:
110108

@@ -141,7 +139,7 @@ On `app/views/layouts/application.html.erb` do:
141139

142140
* [x] Delete all generated `app/views/posts` views - we don't need them!
143141

144-
## Controller
142+
### Controller
145143

146144
* [x] Add Matestack's helper to your application controller:
147145

@@ -194,7 +192,7 @@ class PostsController < ApplicationController
194192
end
195193
```
196194

197-
## Matestack App and Pages
195+
### Matestack App and Pages
198196

199197
* [x] Add a `matestack` folder and create a Matestack app and a Matestack `Post` index page file:
200198

@@ -246,7 +244,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page
246244
end
247245
```
248246

249-
## Add Matestack to the Controller
247+
### Add Matestack to the Controller
250248

251249
* [x] Reference Matestack's app and page on the controller and `index` action:
252250

@@ -280,7 +278,7 @@ rails s
280278

281279
You should see the heading "Twitte Clone" and that's it. We don't have any posts in our database, so we need a `form` to create one!
282280

283-
## Add a Reactive Form
281+
### Add a Reactive Form
284282

285283
* [x] Add a reactive `form` to the index page
286284
* [x] Use the `form_config_helper` method returning a config hash in order to inject a hash into the form without polluting the code
@@ -387,11 +385,11 @@ end
387385

388386
* [x] Navigate to `localhost:3000/posts`
389387

390-
You should see a basic index page with a form at the top. When submitting the form without any values, ActiveRecord errors should appear below the input fields without a browser page reload. When submitting valid data, the form should reset automatically without a browser page reload, but you will still have to reload the browser in order to see the new post!
388+
You should see a basic index page with a form at the top. When submitting the form without any values, ActiveRecord errors should appear below the input fields without a browser page reload. When submitting valid data, the form should reset automatically without a browser page reload, but you will still have to reload the browser in order to see the new post!
391389

392390
To get that reactivity to work, we need make use of the `async` component.
393391

394-
## Add Matestack's Async Component
392+
### Add Matestack's Async Component
395393

396394
* [x] Add `success: {emit: "submitted"}` to the form config
397395
* [x] Wrap the `post_list_partial` with an `async`, configured to rerender when the event `submitted` is received
@@ -437,7 +435,7 @@ Cool! Now you should see the list automatically updating itself after form submi
437435

438436
Now we need to add some `action` components in order to "like" the posts.
439437

440-
## Enable "likes"
438+
### Enable "likes"
441439

442440
* [x] Add the `like` route:
443441

@@ -525,7 +523,7 @@ When you click the "Like" button on a post, you will see the counter increasing
525523

526524
Great! We added a reactive form and reactive actions. We can now add some reactive feedback on top using the toggle component!
527525

528-
## Add Reactive Feedback Using the `toggle` Component
526+
### Add Reactive Feedback Using the `toggle` Component
529527

530528
* [x] Add failure event submission to the form config like: `failure: {emit: "form_failed"},`
531529
* [x] Add a `toggle` component in order to render the success message for 5 seconds
@@ -588,7 +586,7 @@ Great! Now we get instant feedback after performing successful or unsuccessful f
588586

589587
All of the above described reactivity only applies for one client. A second user wouldn't see the new post, unless he reloads his browser page. But of course, we want to sync all connected clients! It's time to integrate ActionCable!
590588

591-
## Integrate Action Cable
589+
### Integrate Action Cable
592590

593591
* [x] Generate an ActionCabel channel
594592

@@ -758,7 +756,7 @@ Wow! We just had to copy and paste a JavaScript snippet once in order to integra
758756

759757
We will take a short break before adding the next cool reactivity feature and refactor a little bit! Matestack encourages you to create a readable and maintainable UI implemetation. Therefore we will move some complexity from the current index page to a self contained Matestack component!
760758

761-
## Create a Matestack Component
759+
### Create a Matestack Component
762760

763761
* [x] Create a components folder within the matestack folder
764762

@@ -768,7 +766,7 @@ touch app/matestack/components/post.rb
768766
```
769767

770768
* [x] Move code from the index page to the new component
771-
* [x] adjust references to the given post parameter to be called as a method of the context object (`context.post.id`)
769+
* [x] adjust references to the given post parameter to be called as a method of the context object \(`context.post.id`\)
772770

773771
`app/matestack/components/post.rb`
774772

@@ -798,7 +796,6 @@ class Components::Post < Matestack::Ui::Component
798796
end
799797
```
800798

801-
802799
* [x] Adjust the index page in order to use the new component
803800

804801
`app/matestack/twitter_clone/posts/index.rb`
@@ -854,10 +851,9 @@ end
854851

855852
Everything should be the same! We just refactored some code in order to better manage complexity.
856853

854+
### Component Registry
857855

858-
## Component Registry
859-
860-
Components can be invoked as we have done above (`Components::Post.(post: post)`). But sometimes the namespace can get a little long and in the interest of keeping our code beautiful, we can register our components so we can call them like:
856+
Components can be invoked as we have done above \(`Components::Post.(post: post)`\). But sometimes the namespace can get a little long and in the interest of keeping our code beautiful, we can register our components so we can call them like:
861857

862858
```ruby
863859
# ...
@@ -874,7 +870,7 @@ Components can be invoked as we have done above (`Components::Post.(post: post)`
874870
# ...
875871
```
876872

877-
Let's refactor and set up a component registry and register our component.
873+
Let's refactor and set up a component registry and register our component.
878874

879875
* [x] Create a component registry file
880876

@@ -901,7 +897,6 @@ end
901897

902898
`app/matestack/twitter_clone/posts/index.rb`
903899

904-
905900
```ruby
906901
class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page
907902

@@ -934,23 +929,21 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page
934929
end
935930
```
936931

937-
938932
**Test the current state again**
939933

940934
* [x] Navigate to `localhost:3000/posts`
941935

942936
Everything should be the same after this small refactoring.
943937

944-
945-
## The Cable Component
938+
### The Cable Component
946939

947940
Now we will cover the last topic of this guide:
948941

949942
As described before, the `async` rerenders it's whole body. The `async` wrapping the whole post list therefore rerenders ALL posts. If our list of posts grows, the performance of the rerendering will decrease. In a lot of usecases, this will not be an issue since the UI is not too big/too complex. So go ahead and use `async` everywhere you're not rerendering big or complex UIs and enjoy the simplicity of that rerendering approach!
950943

951944
But now imagine, your post list will be too big at some point. We should switch the reactivity approach to a more granular one. Let's use the `cable` component alongside our already added ActionCable introduction and reuse pretty much all written code!
952945

953-
## Use the `cable` Component For List Rerendering
946+
### Use the `cable` Component For List Rerendering
954947

955948
* [x] Use the `cable` instead of the `async` component
956949

@@ -1023,7 +1016,7 @@ You probably don't realize any difference on the UI, but now ONLY the fresh post
10231016

10241017
The `cable` component can `prepend`, `append`, `update` and `delete` elements within its body or `replace` its whole body with something pushed from the server. We want to use the `update` feature in order to rerender a specific post when liked:
10251018

1026-
## Adjust the `cable` Component for Post Rerendering
1019+
### Adjust the `cable` Component for Post Rerendering
10271020

10281021
* [x] Add the `update_on` config to the `cable` config
10291022

@@ -1088,8 +1081,6 @@ end
10881081

10891082
* [x] Adjust the ActionCable broadcast on the `like` action on the post controller
10901083

1091-
# todo: cable__liked_post not working here
1092-
10931084
`app/controllers/posts_controller.rb`
10941085

10951086
```ruby
@@ -1157,7 +1148,7 @@ Ok, let's lazy load the list of posts in order to speed up initial page load whe
11571148

11581149
Relax, it's super simple:
11591150

1160-
## Lazy Load the Post List With Async's `defer` Feature
1151+
### Lazy Load the Post List With Async's `defer` Feature
11611152

11621153
* [x] Wrap an `async` component around the `cable` component
11631154
* [x] Configure this `async` to defer its rendering
@@ -1243,7 +1234,7 @@ import "./stylesheets/application.scss";
12431234

12441235
Speaking of fade effects: Let's add a second page in order to show, how you can use Matestacks app and `transition` component in order to implement dynamic page transitions without full browser page reload and without adding any JavaScript!
12451236

1246-
## Implement Dynamic Page Transitions
1237+
### Implement Dynamic Page Transitions
12471238

12481239
We will create a profile page in order to save the username in a session cookie rather than asking for the username on the post form! Obviously, you would use proper user management via something like `devise` in a real world example!
12491240

@@ -1268,7 +1259,6 @@ end
12681259
* [x] Remove the username input from the post form
12691260
* [x] Remove the toggle components from the post index page; we will add them to the app in a moment, enabling the new profile page to trigger them as well!
12701261
* [ ]
1271-
12721262
`app/matestack/twitter_clone/posts/index.rb`
12731263

12741264
```ruby
@@ -1582,11 +1572,12 @@ end
15821572

15831573
And now, let's do something that isn't possible in Twitter: Editing. Tweets. Inline. In pure Ruby! \(Just because it's nice to showcase that\)
15841574

1585-
## Inline Editing
1575+
### Inline Editing
15861576

15871577
* [x] Add an edit form
15881578
* [x] Add an `onclick` component emit an event indicating that we want to show the form now
15891579
* [x] Wrap your code into toggle components, switching the currently visible content
1580+
* [x] Adjust the cable component to react to an additional event
15901581

15911582
`app/matestack/components/post.rb`
15921583

@@ -1688,6 +1679,36 @@ end
16881679
# ...
16891680
```
16901681

1682+
`app/matestack/twitter_clone/posts/index.rb`
1683+
1684+
```ruby
1685+
class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page
1686+
1687+
def prepare
1688+
@posts = Post.all
1689+
end
1690+
1691+
def response
1692+
post_form_partial
1693+
post_list_partial
1694+
end
1695+
1696+
private
1697+
1698+
# ...
1699+
1700+
def post_list_partial
1701+
# cable prepend_on: "cable__created_post", update_on: "cable__liked_post", id: "post-list" do
1702+
cable prepend_on: "cable__created_post", update_on: "cable__liked_post, cable__updated_post", id: "post-list" do
1703+
@posts.each do |post|
1704+
post_component post: post
1705+
end
1706+
end
1707+
end
1708+
1709+
end
1710+
```
1711+
16911712
**Test the current state**
16921713

16931714
* [x] Navigate to `localhost:3000/posts`
@@ -1696,7 +1717,7 @@ end
16961717
* [x] Do it again. And again!
16971718
* [x] Party around! You've reached the end of the tutorial!
16981719

1699-
## Conclusion
1720+
### Conclusion
17001721

17011722
We've built a reactive Twitter clone in pure Ruby. Fantastic! :\)
17021723

0 commit comments

Comments
 (0)