From ea0309f22f559126fedc6a9036e5524c27046df5 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 13:52:28 +1000 Subject: [PATCH 01/36] import Vue manually --- docs/getting-started/quick-start.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index f72aa1d1d..e17516bc5 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -68,6 +68,8 @@ end ## Import Matestack's JavaScript +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. + * [x] Modify the JavaScript pack in order to require `matestack-ui-core` and deactivate `turbolinks`: `app/javascript/packs/application.js` @@ -82,10 +84,14 @@ require("@rails/ujs").start() // require("turbolinks").start() //remove require("@rails/activestorage").start() require("channels") -import MatestackUiCore from 'matestack-ui-core' //add + +import Vue from 'vue/dist/vue.esm' +import Vuex from 'vuex' + +import MatestackUiCore from 'matestack-ui-core' ``` -## Application layout and views +## Application Layout and Views On `app/views/layouts/application.html.erb` do: @@ -100,11 +106,11 @@ On `app/views/layouts/application.html.erb` do: TwitterClone + <%= csrf_meta_tags %> <%= csp_meta_tag %> - From a80c73d3bb0585c5c7227ddded0ad930a7ec94b6 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 13:58:12 +1000 Subject: [PATCH 02/36] indentaion of private methods in line with ruby style conventions --- docs/getting-started/quick-start.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index e17516bc5..4086d8bc0 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -173,10 +173,10 @@ class PostsController < ApplicationController private - # Only allow a list of trusted parameters through. - def post_params - params.require(:post).permit(:username, :body) - end + # Only allow a list of trusted parameters through. + def post_params + params.require(:post).permit(:username, :body) + end end ``` From 776f6d6b9efc1ad0815df11dc27d6eee605cd4f2 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 14:05:02 +1000 Subject: [PATCH 03/36] title case --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 4086d8bc0..eac0dfcae 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -180,7 +180,7 @@ class PostsController < ApplicationController end ``` -## Matestack app and pages +## Matestack App and Pages * [x] Add a `matestack` folder and create a Matestack app and a Matestack `Post` index page file: From 81b3f9d49d17c04fa2e048f6d74caf037cf900a4 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:52:51 +1000 Subject: [PATCH 04/36] title case --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index eac0dfcae..0a9eaeca9 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -232,7 +232,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page end ``` -## Add Matestack to the controller +## Add Matestack to the Controller * [x] Reference Matestack's app and page on the controller and `index` action: From f305f4a3542050724947494711f7499ff3a088ec Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:53:03 +1000 Subject: [PATCH 05/36] change sentence --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 0a9eaeca9..1b6c5f326 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -256,7 +256,7 @@ end **Test the current state** -* [x] Fire up the Rails server and see what we got until now \(heads up: we need a little bit more code\) +* [x] Fire up the Rails server and see what we got at this point \(heads up: we still need a little more code yet.\) ```bash rails s From 5efccec1192122fc3a5d9e997417b4414d11dbf3 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:53:20 +1000 Subject: [PATCH 06/36] ApplicationHelper to Helper --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 1b6c5f326..c7cef4e20 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -137,7 +137,7 @@ On `app/views/layouts/application.html.erb` do: ```ruby class ApplicationController < ActionController::Base - include Matestack::Ui::Core::ApplicationHelper + include Matestack::Ui::Core::Helper end ``` From bd8c25432fba097504832e679597f6444a539377 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:54:29 +1000 Subject: [PATCH 07/36] yield_page to yield --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index c7cef4e20..b2d023456 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -201,7 +201,7 @@ class TwitterClone::App < Matestack::Ui::App def response div class: "container" do heading size: 1, text: "Twitter Clone", class: "mb-5" - yield_page + yield if block_given? end end From bd1446d8941d7069a379ec8c89f53ceddc56cd99 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:55:07 +1000 Subject: [PATCH 08/36] removed full stop in keeping current style --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index b2d023456..1153ddae6 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -256,7 +256,7 @@ end **Test the current state** -* [x] Fire up the Rails server and see what we got at this point \(heads up: we still need a little more code yet.\) +* [x] Fire up the Rails server and see what we got at this point \(heads up: we still need a little more code yet\) ```bash rails s From 780804c7fb7feb56e9a49114ac6686390bc41687 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 15:55:34 +1000 Subject: [PATCH 09/36] title case --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 1153ddae6..4bd87a249 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -266,7 +266,7 @@ rails s 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! -## Add a reactive form +## Add a Reactive Form * [x] Add a reactive `form` to the index page * [x] Use the `form_config_helper` method returning a config hash in order to inject a hash into the form without polluting the code From 7bb58af45b635d4eb40249c2f20424b82e9435c7 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 16:04:15 +1000 Subject: [PATCH 10/36] form to matestack_form --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 4bd87a249..1220a9d1c 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -291,7 +291,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page def post_form_partial div class: "mb-3 p-3 rounded shadow-sm" do heading size: 4, text: "New Post", class: "mb-3" - form form_config_helper do + matestack_form form_config_helper do div class: "mb-3" do form_input key: :username, type: :text, placeholder: "Username", class: "form-control" end From aa373d4072857baaaf961200aaec0cc3dc7389e5 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 16:04:39 +1000 Subject: [PATCH 11/36] form_submit to button --- docs/getting-started/quick-start.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 1220a9d1c..c66220ec4 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -299,9 +299,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page form_textarea key: :body, placeholder: "What's up?", class: "form-control" end div class: "mb-3" do - form_submit do - button type: :submit, class: "btn btn-primary", text: "Post!" - end + button 'submit', type: :submit, class: "btn btn-primary", text: "Post!" end end end From 1fe95d331568c9096c4f40c1cdee634390e29883 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 16:49:07 +1000 Subject: [PATCH 12/36] added missing matestackUiApp setup --- docs/getting-started/quick-start.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index c66220ec4..fef157b0c 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -89,6 +89,15 @@ import Vue from 'vue/dist/vue.esm' import Vuex from 'vuex' import MatestackUiCore from 'matestack-ui-core' + +let matestackUiApp = undefined + +document.addEventListener('DOMContentLoaded', () => { + matestackUiApp = new Vue({ + el: "#matestack-ui", + store: MatestackUiCore.store + }) +}) ``` ## Application Layout and Views From 8a5cb19f2270459871f2eaebf6a327ce709ab6d6 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 16:51:59 +1000 Subject: [PATCH 13/36] text change --- docs/getting-started/quick-start.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index fef157b0c..912c0d8ba 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -382,9 +382,11 @@ end * [x] Navigate to `localhost:3000/posts` -You should see a basic index page with a form on top. When submitting the form without any values, ActiveRecord errors should appear below the inputs without browser page reload. When submitting valid data, the form should reset automatically without browser page reload, but you would have to reload the browser in order to see the new post! That's why we need to add the `async` component. +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! -## Add Matestack's async component +To get that reactivity to work, we need to add the `async` component. + +## Add Matestack's Async Component * [x] Add `success: { emit: "submitted" }` to the form config * [x] Wrap the `post_list_partial` with an `async`, configured to rerender when the event `submitted` is received From 9cf2ce555f4052829db5f4ebb597aacd3e63caab Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 16:53:23 +1000 Subject: [PATCH 14/36] put back the shink to fit --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 912c0d8ba..da2f8ceb3 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -115,7 +115,7 @@ On `app/views/layouts/application.html.erb` do: TwitterClone - + <%= csrf_meta_tags %> <%= csp_meta_tag %> From 4a4c098263c4cb0b5cf518dfe4396a2ce981c36b Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 18:58:19 +1000 Subject: [PATCH 15/36] text change --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index da2f8ceb3..057b06269 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -384,7 +384,7 @@ end 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! -To get that reactivity to work, we need to add the `async` component. +To get that reactivity to work, we need make use of the `async` component. ## Add Matestack's Async Component From 3a3ab65a10fc9af93eb206da0617aff98faa8ea1 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 18:59:21 +1000 Subject: [PATCH 16/36] text change --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 057b06269..4ca5c3c6b 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -428,7 +428,7 @@ end * [x] Navigate to `localhost:3000/posts` -Cool! Now you should see the list automatically updating itself after form submission without a browser page reload! And we didn't write any JavaScript for that. Just two lines of simple Ruby code! How cool is that? +Cool! Now you should see the list automatically updating itself after form submission without a browser page reload! And we didn't have to write any JavaScript. Just two lines of simple Ruby code! How cool is that? Now we need to add some `action` components in order to "like" the posts. From a662280a8591a675c1e1e69dce9588362b7e0720 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 19:12:47 +1000 Subject: [PATCH 17/36] text change --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 4ca5c3c6b..4c9c8fdcc 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -520,7 +520,7 @@ When you click the "Like" button on a post, you will see the counter increasing Great! We added a reactive form and reactive actions. We can now add some reactive feedback on top using the toggle component! -## Add reactive feedback using the `toggle` component +## Add Reactive Feedback Using the `toggle` Component * [x] Add failure event submission to the form config like: `failure: { emit: "form_failed" },` * [x] Add a `toggle` component in order to render the success message for 5 seconds From 624506c31327a39acd183e5635bca329dae20983 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 21:31:21 +1000 Subject: [PATCH 18/36] text change and readded failure event form_config_helper --- docs/getting-started/quick-start.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 4c9c8fdcc..11e81128d 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -581,7 +581,7 @@ end * [x] Navigate to `localhost:3000/posts` -Great! Now we get instant feedback after performing successful or non successful form submissions! And still no line of JavaScript involved! The same approach would work for our actions, but we do not want to have that feedback after performing the actions in this example! +Great! Now we get instant feedback after performing successful or unsuccessful form submissions! And still no line of JavaScript involved! The same approach would work for our actions, but we do not want to have that feedback after performing the actions in this example! 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! @@ -690,8 +690,9 @@ end def form_config_helper { for: Post.new, path: posts_path, method: :post, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } }, - success: { emit: "submitted" } + success: { emit: "submitted" }, + failure: { emit: "form_failed" }, + errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } } end From 61ba179ff4d7121aad1db2f7fa4e025a801e57cd Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 21:32:04 +1000 Subject: [PATCH 19/36] added MatestackUiCore to MatestackUiCoreChannel --- docs/getting-started/quick-start.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 11e81128d..33f2b44a4 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -599,6 +599,7 @@ rails generate channel MatestackUiCoreChannel ```javascript import consumer from "./consumer" +import MatestackUiCore from 'matestack-ui-core' consumer.subscriptions.create("MatestackUiCoreChannel", { connected() { From bc3736ddeb7b9361935acd76c4703909af61956b Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 21:40:17 +1000 Subject: [PATCH 20/36] text change --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 33f2b44a4..0766d7148 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -753,7 +753,7 @@ end Wow! We just had to copy and paste a JavaScript snippet once in order to integrate ActionCable, broadcast an event from the controller action and without any more added complexity, we get synced clients, implemented in pure Ruby! Fantastic! -We will take a short break before adding the next cool reactivity feature add 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! +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! ## Create a Matestack component From 2435ae2bf0ccba669f76b4373c371ed0ee2fe3ba Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 22:13:37 +1000 Subject: [PATCH 21/36] Component Registry --- docs/getting-started/quick-start.md | 152 +++++++++++++++++++--------- 1 file changed, 104 insertions(+), 48 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 0766d7148..7132b5473 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -755,7 +755,7 @@ Wow! We just had to copy and paste a JavaScript snippet once in order to integra 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! -## Create a Matestack component +## Create a Matestack Component * [x] Create a components folder within the matestack folder @@ -765,6 +765,7 @@ touch app/matestack/components/post.rb ``` * [x] Move code from the index page to the new component +* [x] adjust references to the given post parameter to be called as a method of the context object (`context.post.id`) `app/matestack/components/post.rb` @@ -775,16 +776,16 @@ class Components::Post < Matestack::Ui::Component def response # copied from the index page - async rerender_on: "cable__liked_post_#{post.id}", id: "post-#{post.id}" do + async rerender_on: "cable__liked_post_#{context.post.id}", id: "post-#{context.post.id}" do div class: "mb-3 p-3 rounded shadow-sm" do heading size: 5 do - plain post.username - small text: post.created_at.strftime("%d.%m.%Y %H:%M") + plain context.post.username + small text: context.post.created_at.strftime("%d.%m.%Y %H:%M") end - paragraph text: post.body, class: "mb-5" - action path: like_post_path(post), method: :put do + paragraph text: context.post.body, class: "mb-5" + action path: like_post_path(context.post), method: :put do button class: "btn btn-light" do - plain "Like (#{post.likes_count})" + plain "Like (#{context.post.likes_count})" end end end @@ -794,43 +795,109 @@ class Components::Post < Matestack::Ui::Component end ``` -* [x] Create a component registry file -```bash -touch app/matestack/components/registry.rb +* [x] Adjust the index page in order to use the new component + +`app/matestack/twitter_clone/posts/index.rb` + +```ruby +class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page + + def prepare + @posts = Post.all + end + + def response + post_form_partial + post_list_partial + end + + private + + # ... + + def post_list_partial + async rerender_on: "submitted", id: "post-list" do + @posts.each do |post| + # post_partial(post) + Components::Post.(post: post) + end + end + end + + # def post_partial post + # async rerender_on: "cable__liked_post_#{post.id}", id: "post-#{post.id}" do + # div class: "mb-3 p-3 rounded shadow-sm" do + # heading size: 5 do + # plain post.username + # small text: post.created_at.strftime("%d.%m.%Y %H:%M") + # end + # paragraph text: post.body, class: "mb-5" + # action path: like_post_path(post), method: :put do + # button class: "btn btn-light" do + # plain "Like (#{post.likes_count})" + # end + # end + # end + # end + # end + +end ``` -* [x] Register the new component +**Test the current state** + +* [x] Navigate to `localhost:3000/posts` + +Everything should be the same! We just refactored some code in order to better manage complexity. -`app/matestack/components/registry.rb` + +## Component Registry + +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: ```ruby -module Components::Registry + # ... - Matestack::Ui::Core::Component::Registry.register_components( - post_component: Components::Post, - ) + def post_list_partial + async rerender_on: "submitted", id: "post-list" do + @posts.each do |post| + # post_partial(post) + post_component post: post + end + end + end -end + # ... ``` -* [x] Include the component registry in your application controller +Let's refactor and set up a component registry and register our component. -`app/controllers/application_controller.rb` +* [x] Create a component registry file + +```bash +touch app/matestack/components/registry.rb +``` + +* [x] Register the new component + +`app/matestack/components/registry.rb` ```ruby -class ApplicationController < ActionController::Base +module Components::Registry - include Matestack::Ui::Core::ApplicationHelper - include Components::Registry + def post_component(post) + Components::Post.(post: post) + end end ``` -* [x] Adjust the index page in order to use the new component +* [x] Adjust the index page in order to use the component in the new way `app/matestack/twitter_clone/posts/index.rb` + ```ruby class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page @@ -845,42 +912,31 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - # ... + # ... - def post_list_partial - async rerender_on: "submitted", id: "post-list" do - @posts.each do |post| - # post_partial(post) - post_component post: post - end + def post_list_partial + async rerender_on: "submitted", id: "post-list" do + @posts.each do |post| + # post_partial(post) + post_component post: post end end + end - # def post_partial post - # async rerender_on: "cable__liked_post_#{post.id}", id: "post-#{post.id}" do - # div class: "mb-3 p-3 rounded shadow-sm" do - # heading size: 5 do - # plain post.username - # small text: post.created_at.strftime("%d.%m.%Y %H:%M") - # end - # paragraph text: post.body, class: "mb-5" - # action path: like_post_path(post), method: :put do - # button class: "btn btn-light" do - # plain "Like (#{post.likes_count})" - # end - # end - # end - # end - # end + # ... end ``` -**Test the current state** + +**Test the current state again** * [x] Navigate to `localhost:3000/posts` -Everything should be the same! We just refactored some code in order to better manage complexity. +Everything should be the same after this small refactoring. + + + Now we will cover the last topic of this guide: From 9ea9b11e865fd4bc47f1900a19e7ba7225ee3d1e Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Thu, 8 Apr 2021 22:16:59 +1000 Subject: [PATCH 22/36] Component Registry --- docs/getting-started/quick-start.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 7132b5473..8cb9c6093 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -886,13 +886,14 @@ touch app/matestack/components/registry.rb ```ruby module Components::Registry - def post_component(post) + def post_component(post:) Components::Post.(post: post) end end ``` +* [x] Adjust the index page to include the Components::Registry * [x] Adjust the index page in order to use the component in the new way `app/matestack/twitter_clone/posts/index.rb` @@ -901,6 +902,8 @@ end ```ruby class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page + include Components::Registry + def prepare @posts = Post.all end From fdd16b25c7db55b96f716e1045918139cae74638 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 07:04:13 +1000 Subject: [PATCH 23/36] title case --- docs/getting-started/quick-start.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 8cb9c6093..5d82da235 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -939,7 +939,7 @@ end Everything should be the same after this small refactoring. - +## The Cable Component Now we will cover the last topic of this guide: @@ -947,7 +947,7 @@ As described before, the `async` rerenders it's whole body. The `async` wrapping But now imagine, your post list will be too big at some point. We should switch the reactivity approach to a more granular on. Let's use the `cable` component alongside our already added ActionCable introduction and reuse pretty much all written code! -## Use the `cable` component for list rerendering +## Use the `cable` Component For List Rerendering * [x] Use the `cable` instead of the `async` component From b66f3044ddee20ed3ff2aebb4f5281ea6872ee2b Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 07:05:24 +1000 Subject: [PATCH 24/36] ttext corection --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 5d82da235..3e60a1e9c 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -945,7 +945,7 @@ Now we will cover the last topic of this guide: 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! -But now imagine, your post list will be too big at some point. We should switch the reactivity approach to a more granular on. Let's use the `cable` component alongside our already added ActionCable introduction and reuse pretty much all written code! +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! ## Use the `cable` Component For List Rerendering From 9305e7f4f0ab1af88fc65ad1945ec6032aa25c41 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 07:17:40 +1000 Subject: [PATCH 25/36] new way of referencing post_component --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 3e60a1e9c..897e26183 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -995,7 +995,7 @@ def create if @post.save ActionCable.server.broadcast('matestack_ui_core', { event: 'cable__created_post', - data: matestack_component(:post_component, post: @post) # add this line + data: post_component(post: @post) # add this line }) render json: { message: 'Post was successfully created.' From 211ee29d95d798d75fa8a0e76a8561b211ccc6b3 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 07:20:17 +1000 Subject: [PATCH 26/36] to --- docs/getting-started/quick-start.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 897e26183..433db02cd 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -450,7 +450,7 @@ end * [x] Add the `like` action on the controller: -`app/controller/posts_controller.rb` +`app/controllers/posts_controller.rb` ```ruby # ... @@ -634,7 +634,7 @@ end * [x] Broadcast the `cable__created_post` event from the `create` action on the posts controller * [x] Broadcast the `cable__liked_post_xyz` event from the `like` action on the posts controller -`app/controller/posts_controller.rb` +`app/controllers/posts_controller.rb` ```ruby # ... @@ -983,7 +983,7 @@ end * [x] Adjust the ActionCable broadcast on the `create` action on the post controller -`app/controller/posts_controller.rb` +`app/controllers/posts_controller.rb` ```ruby # ... @@ -1085,7 +1085,7 @@ end * [x] Adjust the ActionCable broadcast on the `like` action on the post controller -`app/controller/posts_controller.rb` +`app/controllers/posts_controller.rb` ```ruby # ... @@ -1648,7 +1648,7 @@ end * [x] Add the update action to the posts controller -`app/controller/posts_controller.rb` +`app/controllers/posts_controller.rb` ```ruby # ... From 051c945931882d4e09d5eef75d4af25dc01c6242 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 07:37:55 +1000 Subject: [PATCH 27/36] title case --- docs/getting-started/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 433db02cd..d38426626 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1020,7 +1020,7 @@ You probably don't realize any difference on the UI, but now ONLY the fresh post 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: -## Adjust the `cable` component for post rerendering +## Adjust the `cable` Component for Post Rerendering * [x] Add the `update_on` config to the `cable` config From c58b4f022154f0d3f6fec57177c58197dc3e2042 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 14:44:31 +1000 Subject: [PATCH 28/36] Adjust the Component for Post Rerendering --- docs/getting-started/quick-start.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index d38426626..8dd3aeaad 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1064,16 +1064,16 @@ class Components::Post < Matestack::Ui::Component requires :post def response - # async rerender_on: "cable__liked_post_#{post.id}", id: "post-#{post.id}" do - div class: "mb-3 p-3 rounded shadow-sm", id: "post-#{post.id}" do + # async rerender_on: "cable__liked_post_#{post.id}", id: "post-#{context.post.id}" do + div class: "mb-3 p-3 rounded shadow-sm", id: "post-#{context.post.id}" do heading size: 5 do - plain post.username - small text: post.created_at.strftime("%d.%m.%Y %H:%M") + plain context.post.username + small text: context.post.created_at.strftime("%d.%m.%Y %H:%M") end - paragraph text: post.body, class: "mb-5" - action path: like_post_path(post), method: :put do + paragraph text: context.post.body, class: "mb-5" + action path: like_post_path(context.post), method: :put do button class: "btn btn-light" do - plain "Like (#{post.likes_count})" + plain "Like (#{context.post.likes_count})" end end end @@ -1085,6 +1085,8 @@ end * [x] Adjust the ActionCable broadcast on the `like` action on the post controller +# todo: cable__liked_post not working here + `app/controllers/posts_controller.rb` ```ruby @@ -1101,7 +1103,7 @@ def like # no id required in the event name, the cable component will figure out which post # should be updated using the root element ID of the pushed component event: "cable__liked_post", # change the event name - data: matestack_component(:post_component, post: @post) # add this line + data: post_component(post: @post) # add this line }) render json: { message: 'Post was successfully liked.' @@ -1121,7 +1123,7 @@ def create if @post.save ActionCable.server.broadcast('matestack_ui_core', { event: 'cable__created_post', - data: matestack_component(:post_component, post: @post) # add this line + data: post_component(post: @post) }) render json: { message: 'Post was successfully created.' @@ -1144,7 +1146,7 @@ end Again: you probably don't realize any difference on the UI, but now ONLY the updated post will be rendered on the server and pushed to the `cable` component mounted in the browser. -The `cable` component is configured to `updated` the component pushed from the server on the `cable__liked_post` event. The `cable` component then reads the ID of the root element of the pushed component, looks for that ID within it's body and updates this element with the pushed component. +The `cable` component is configured to `update` the component pushed from the server on the `cable__liked_post` event. The `cable` component then reads the ID of the root element of the pushed component, looks for that ID within it's body and updates this element with the pushed component. Now, we're rerendering the list and its elements completely with the `cable` component. As described, this is an ALTERNATIVE approach to the introduced `async` component approach. The `cable` component requires a bit more implementation and brain power but makes our reactivity more scalable. Use the `cable` component wherever you think `async` would be too slow at some point! @@ -1576,6 +1578,8 @@ And now we do something, what's not possible in Twitter: Editing. Tweets. Inline `app/matestack/components/post.rb` +# todo: context.post + ```ruby class Components::Post < Matestack::Ui::Component @@ -1650,6 +1654,8 @@ end `app/controllers/posts_controller.rb` +# todo: matestack_component + ```ruby # ... From 541b54e72e062997600b9d0fe8a86da2ec0a3bd7 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 15:52:10 +1000 Subject: [PATCH 29/36] Lazy Load the Post List With Async's Feature --- docs/getting-started/quick-start.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 8dd3aeaad..91605ba64 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1154,7 +1154,7 @@ Ok, let's lazy load the list of posts in order to speed up initial page load whe Relax, it's super simple: -## Lazy load the post list with async's `defer` feature +## Lazy Load the Post List With Async's `defer` Feature * [x] Wrap an `async` component around the `cable` component * [x] Configure this `async` to defer its rendering @@ -1162,6 +1162,8 @@ Relax, it's super simple: `app/matestack/twitter_clone/posts/index.rb` +# todo: indetation of private sections + ```ruby class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page From ff20b652717570fbdd5b42580850ef667c1a565d Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:17:03 +1000 Subject: [PATCH 30/36] added some bash script lines title case updated some code --- docs/getting-started/quick-start.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 91605ba64..f6f59ca2f 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1210,6 +1210,11 @@ Using this approach, it is super simple to speed up initial page loads without a Want some sugar? How about adding a CSS animation while lazy loading the post list? +```bash +mkdir -p app/javascript/packs/stylesheets +touch app/javascript/packs/stylesheets/application.scss +``` + `app/javascript/packs/stylesheets/application.scss` ```css @@ -1237,12 +1242,16 @@ import "./stylesheets/application.scss"; 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! -## Implement dynamic page transitions +## Implement Dynamic Page Transitions 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! * [x] Add an view helper method in order to access the session cookie from a Matestack page +```bash +touch app/helpers/cookie_helper.rb +``` + `app/helpers/cookie_helper.rb` ```ruby @@ -1256,7 +1265,8 @@ end ``` * [x] Remove the username input from the post form -* [x] Remove the toggle components from the post index page; we will add them to the app in a bit enabling the new profile page to trigger them as well! +* [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! +* [ ] `app/matestack/twitter_clone/posts/index.rb` @@ -1355,7 +1365,7 @@ touch app/matestack/twitter_clone/pages/profile/edit.rb * [x] Add some code to the profile edit page -`app/matestack/twitter_clone/pages/profile` +`app/matestack/twitter_clone/pages/profile/edit.rb` ```ruby class TwitterClone::Pages::Profile::Edit < Matestack::Ui::Page @@ -1363,14 +1373,12 @@ class TwitterClone::Pages::Profile::Edit < Matestack::Ui::Page def response div class: "mb-3 p-3 rounded shadow-sm" do heading size: 4, text: "Your Profile", class: "mb-3" - form form_config_helper do + matestack_form form_config_helper do div class: "mb-3" do form_input key: :username, type: :text, placeholder: "Username", class: "form-control", init: current_username end div class: "mb-3" do - form_submit do - button type: :submit, class: "btn btn-primary", text: "Save!" - end + button 'submit', type: :submit, class: "btn btn-primary", text: "Save!" end end end @@ -1447,6 +1455,7 @@ class ProfileController < ApplicationController def profile_params params.require(:profile).permit(:username) end + end ``` @@ -1470,7 +1479,7 @@ class TwitterClone::App < Matestack::Ui::App button class: "btn btn-light", text: "Your Profile" end div class: "mt-5" do - yield_page + yield if block_given? end # add the toggle components here, this way all pages are able to trigger them! toggle show_on: "submitted", hide_after: 5000 do From 257f7a3d3b50d3cb3980bd212dea62bb5d28f0b0 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:38:09 +1000 Subject: [PATCH 31/36] title case, converted code --- docs/getting-started/quick-start.md | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index f6f59ca2f..0e8ee5f8a 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1318,6 +1318,8 @@ end `app/matestack/twitter_clone/posts/index.rb` +# todo: matestack_component + ```ruby # ... @@ -1579,7 +1581,7 @@ end * [x] Click on the transition components * [x] Enjoy the fade effects once again :\) -And now we do something, what's not possible in Twitter: Editing. Tweets. Inline. In pure Ruby! \(Just because it's nice to showcase that\) +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\) ## Inline Editing @@ -1597,21 +1599,21 @@ class Components::Post < Matestack::Ui::Component requires :post def response - div class: "mb-3 p-3 rounded shadow-sm", id: "post-#{post.id}" do + div class: "mb-3 p-3 rounded shadow-sm", id: "post-#{context.post.id}" do heading size: 5 do - plain post.username - small text: post.created_at.strftime("%d.%m.%Y %H:%M") + plain context.post.username + small text: context.post.created_at.strftime("%d.%m.%Y %H:%M") end - toggle hide_on: "edit-post-#{post.id}", show_on: "updated", init_show: true do + toggle hide_on: "edit-post-#{context.post.id}", show_on: "updated", init_show: true do show_partial end - toggle show_on: "edit-post-#{post.id}", hide_on: "updated" do + toggle show_on: "edit-post-#{context.post.id}", hide_on: "updated" do edit_partial end - # paragraph text: post.body, class: "mb-5" - # action path: like_post_path(post), method: :put do + # paragraph text: context.post.body, class: "mb-5" + # action path: like_post_path(context.post), method: :put do # button class: "btn btn-light" do - # plain "Like (#{post.likes_count})" + # plain "Like (#{context.post.likes_count})" # end # end end @@ -1620,16 +1622,16 @@ class Components::Post < Matestack::Ui::Component private def show_partial - paragraph text: post.body, class: "mb-5" - action path: like_post_path(post), method: :put do + paragraph text: context.post.body, class: "mb-5" + action path: like_post_path(context.post), method: :put do button class: "btn btn-light" do - plain "Like (#{post.likes_count})" + plain "Like (#{context.post.likes_count})" end end # onclick emits an event triggering the toggle components to show/hide # we use Bootstraps "d-inline" utility class here because onclick renders # a block element (will be changed to an inline element in a future release) - onclick emit: "edit-post-#{post.id}", class: "d-inline" do + onclick emit: "edit-post-#{context.post.id}", class: "d-inline" do button class: "btn btn-link" do plain "Edit" end @@ -1637,21 +1639,19 @@ class Components::Post < Matestack::Ui::Component end def edit_partial - form form_config_helper do + matestack_form form_config_helper do div class: "mb-3" do form_input key: :body, type: :text, placeholder: "What's up?", class: "form-control" end div class: "mb-3" do - form_submit do - button type: :submit, class: "btn btn-primary", text: "Update!" - end + button 'submit', type: :submit, class: "btn btn-primary", text: "Update!" end end end def form_config_helper { - for: post, path: post_path(id: post.id), method: :put, + for: context.post, path: post_path(id: context.post.id), method: :put, success: { emit: "updated" }, failure: { emit: "form_failed" }, errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } @@ -1677,7 +1677,7 @@ def update if @post.update(post_params) ActionCable.server.broadcast('matestack_ui_core', { event: "cable__updated_post", - data: matestack_component(:post_component, post: @post) + data: post_component(post: @post) }) render json: { message: 'Post was successfully updated.' From fd6f840570a792d502057971b3184f25e6356079 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:41:18 +1000 Subject: [PATCH 32/36] indentaion of provate sections --- docs/getting-started/quick-start.md | 215 ++++++++++++++-------------- 1 file changed, 106 insertions(+), 109 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 0e8ee5f8a..f9004f5b5 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -186,6 +186,7 @@ class PostsController < ApplicationController def post_params params.require(:post).permit(:username, :body) end + end ``` @@ -297,42 +298,42 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - def post_form_partial - div class: "mb-3 p-3 rounded shadow-sm" do - heading size: 4, text: "New Post", class: "mb-3" - matestack_form form_config_helper do - div class: "mb-3" do - form_input key: :username, type: :text, placeholder: "Username", class: "form-control" - end - div class: "mb-3" do - form_textarea key: :body, placeholder: "What's up?", class: "form-control" - end - div class: "mb-3" do - button 'submit', type: :submit, class: "btn btn-primary", text: "Post!" - end + def post_form_partial + div class: "mb-3 p-3 rounded shadow-sm" do + heading size: 4, text: "New Post", class: "mb-3" + matestack_form form_config_helper do + div class: "mb-3" do + form_input key: :username, type: :text, placeholder: "Username", class: "form-control" + end + div class: "mb-3" do + form_textarea key: :body, placeholder: "What's up?", class: "form-control" + end + div class: "mb-3" do + button 'submit', type: :submit, class: "btn btn-primary", text: "Post!" end end end + end - def form_config_helper - { - for: Post.new, path: posts_path, method: :post, - # optional: in order to map Bootstrap's CSS classes, you can adjust the form error rendering like so: - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } - } - end + def form_config_helper + { + for: Post.new, path: posts_path, method: :post, + # optional: in order to map Bootstrap's CSS classes, you can adjust the form error rendering like so: + errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + } + end - def post_list_partial - @posts.each do |post| - div class: "mb-3 p-3 rounded shadow-sm" do - heading size: 5 do - plain post.username - small text: post.created_at.strftime("%d.%m.%Y %H:%M") - end - paragraph text: post.body + def post_list_partial + @posts.each do |post| + div class: "mb-3 p-3 rounded shadow-sm" do + heading size: 5 do + plain post.username + small text: post.created_at.strftime("%d.%m.%Y %H:%M") end + paragraph text: post.body end end + end end ``` @@ -542,37 +543,35 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - def post_form_partial - div class: "mb-3 p-3 rounded shadow-sm" do - heading size: 4, text: "New Post", class: "mb-3" - form form_config_helper do - # ... - end + def post_form_partial + div class: "mb-3 p-3 rounded shadow-sm" do + heading size: 4, text: "New Post", class: "mb-3" + form form_config_helper do + # ... end - toggle show_on: "submitted", hide_after: 5000 do - div class: "container fixed-bottom w-100 bg-success text-white p-3 rounded-top" do - heading size: 4, text: "Success: {{ event.data.message }}" - end + end + toggle show_on: "submitted", hide_after: 5000 do + div class: "container fixed-bottom w-100 bg-success text-white p-3 rounded-top" do + heading size: 4, text: "Success: {{ event.data.message }}" end - toggle show_on: "form_failed", hide_after: 5000 do - div class: "container fixed-bottom w-100 bg-danger text-white p-3 rounded-top" do - heading size: 4, text: "Error: {{ event.data.message }}" - end + end + toggle show_on: "form_failed", hide_after: 5000 do + div class: "container fixed-bottom w-100 bg-danger text-white p-3 rounded-top" do + heading size: 4, text: "Error: {{ event.data.message }}" end end + end - private - - def form_config_helper - { - for: Post.new, path: posts_path, method: :post, - success: { emit: "submitted" }, - failure: { emit: "form_failed" }, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } - } - end + def form_config_helper + { + for: Post.new, path: posts_path, method: :post, + success: { emit: "submitted" }, + failure: { emit: "form_failed" }, + errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + } + end - # ... + # ... end ``` @@ -967,16 +966,16 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - # ... + # ... - def post_list_partial - # async rerender_on: "submitted", id: "post-list" do - cable prepend_on: "cable__created_post", id: "post-list" do - @posts.each do |post| - post_component post: post - end + def post_list_partial + # async rerender_on: "submitted", id: "post-list" do + cable prepend_on: "cable__created_post", id: "post-list" do + @posts.each do |post| + post_component post: post end end + end end ``` @@ -1040,16 +1039,16 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - # ... + # ... - def post_list_partial - # cable prepend_on: "cable__created_post", id: "post-list" do - cable prepend_on: "cable__created_post", update_on: "cable__liked_post", id: "post-list" do - @posts.each do |post| - post_component post: post - end + def post_list_partial + # cable prepend_on: "cable__created_post", id: "post-list" do + cable prepend_on: "cable__created_post", update_on: "cable__liked_post", id: "post-list" do + @posts.each do |post| + post_component post: post end end + end end ``` @@ -1162,8 +1161,6 @@ Relax, it's super simple: `app/matestack/twitter_clone/posts/index.rb` -# todo: indetation of private sections - ```ruby class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page @@ -1178,22 +1175,22 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - # ... + # ... - def posts - Post.all - end + def posts + Post.all + end - def post_list_partial - async defer: true, id: "deferred-post-list" do - cable prepend_on: "cable__created_post", update_on: "cable__liked_post", id: "post-list" do - # @posts.each do |post| - posts.each do |post| - post_component post: post - end + def post_list_partial + async defer: true, id: "deferred-post-list" do + cable prepend_on: "cable__created_post", update_on: "cable__liked_post", id: "post-list" do + # @posts.each do |post| + posts.each do |post| + post_component post: post end end end + end end ``` @@ -1280,36 +1277,36 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page private - def post_form_partial - div class: "mb-3 p-3 rounded shadow-sm" do - heading size: 4, text: "New Post", class: "mb-3" - form form_config_helper do - # div class: "mb-3" do - # form_input key: :username, type: :text, placeholder: "Username", class: "form-control" - # end - div class: "mb-3" do - form_input key: :body, type: :text, placeholder: "What's up?", class: "form-control" - end - div class: "mb-3" do - form_submit do - button type: :submit, class: "btn btn-primary", text: "Post!" - end + def post_form_partial + div class: "mb-3 p-3 rounded shadow-sm" do + heading size: 4, text: "New Post", class: "mb-3" + form form_config_helper do + # div class: "mb-3" do + # form_input key: :username, type: :text, placeholder: "Username", class: "form-control" + # end + div class: "mb-3" do + form_input key: :body, type: :text, placeholder: "What's up?", class: "form-control" + end + div class: "mb-3" do + form_submit do + button type: :submit, class: "btn btn-primary", text: "Post!" end end end - # toggle show_on: "submitted", hide_after: 5000 do - # div class: "container fixed-bottom w-100 bg-success text-white p-3 rounded-top" do - # heading size: 4, text: "Success: {{ event.data.message }}" - # end - # end - # toggle show_on: "form_failed", hide_after: 5000 do - # div class: "container fixed-bottom w-100 bg-danger text-white p-3 rounded-top" do - # heading size: 4, text: "Error: {{ event.data.message }}" - # end - # end end + # toggle show_on: "submitted", hide_after: 5000 do + # div class: "container fixed-bottom w-100 bg-success text-white p-3 rounded-top" do + # heading size: 4, text: "Success: {{ event.data.message }}" + # end + # end + # toggle show_on: "form_failed", hide_after: 5000 do + # div class: "container fixed-bottom w-100 bg-danger text-white p-3 rounded-top" do + # heading size: 4, text: "Error: {{ event.data.message }}" + # end + # end + end - # ... + # ... end ``` @@ -1453,10 +1450,10 @@ class ProfileController < ApplicationController private - # Only allow a list of trusted parameters through. - def profile_params - params.require(:profile).permit(:username) - end + # Only allow a list of trusted parameters through. + def profile_params + params.require(:profile).permit(:username) + end end ``` From 9145b707667af1766932230ac94690ee7b8c52c5 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:42:03 +1000 Subject: [PATCH 33/36] converted some final remaining matestack_component references --- docs/getting-started/quick-start.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index f9004f5b5..766af0f20 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1315,8 +1315,6 @@ end `app/matestack/twitter_clone/posts/index.rb` -# todo: matestack_component - ```ruby # ... @@ -1337,7 +1335,7 @@ def create if @post.save ActionCable.server.broadcast('matestack_ui_core', { event: 'cable__created_post', - data: matestack_component(:post_component, post: @post) + data: post_component(post: @post) }) render json: { message: 'Post was successfully created.' @@ -1662,8 +1660,6 @@ end `app/controllers/posts_controller.rb` -# todo: matestack_component - ```ruby # ... From 3eca642f20243f8e16349b3e7f1b9a22814c0900 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:44:11 +1000 Subject: [PATCH 34/36] converted form to matestack_form --- docs/getting-started/quick-start.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 766af0f20..350f61e93 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -546,7 +546,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page def post_form_partial div class: "mb-3 p-3 rounded shadow-sm" do heading size: 4, text: "New Post", class: "mb-3" - form form_config_helper do + matestack_form form_config_helper do # ... end end @@ -1280,7 +1280,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page def post_form_partial div class: "mb-3 p-3 rounded shadow-sm" do heading size: 4, text: "New Post", class: "mb-3" - form form_config_helper do + matestack_form form_config_helper do # div class: "mb-3" do # form_input key: :username, type: :text, placeholder: "Username", class: "form-control" # end @@ -1586,8 +1586,6 @@ And now, let's do something that isn't possible in Twitter: Editing. Tweets. Inl `app/matestack/components/post.rb` -# todo: context.post - ```ruby class Components::Post < Matestack::Ui::Component From 59eca7cfe01efe9a9bb89d8e750adffa8567d4e4 Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 16:47:56 +1000 Subject: [PATCH 35/36] converted {} hash syntax to not have spaces --- docs/getting-started/quick-start.md | 44 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 350f61e93..81571ea2f 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -319,7 +319,7 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page { for: Post.new, path: posts_path, method: :post, # optional: in order to map Bootstrap's CSS classes, you can adjust the form error rendering like so: - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + errors: {wrapper: {tag: :div, class: 'invalid-feedback'}, input: {class: 'is-invalid'}} } end @@ -389,7 +389,7 @@ To get that reactivity to work, we need make use of the `async` component. ## Add Matestack's Async Component -* [x] Add `success: { emit: "submitted" }` to the form config +* [x] Add `success: {emit: "submitted"}` to the form config * [x] Wrap the `post_list_partial` with an `async`, configured to rerender when the event `submitted` is received `app/matestack/twitter_clone/pages/posts/index.rb` @@ -400,11 +400,11 @@ To get that reactivity to work, we need make use of the `async` component. def form_config_helper { for: Post.new, path: posts_path, method: :post, - errors: { - wrapper: { tag: :div, class: 'invalid-feedback' }, - input: { class: 'is-invalid' } + errors: { + wrapper: {tag: :div, class: 'invalid-feedback'}, + input: {class: 'is-invalid'} }, - success: { emit: "submitted" } + success: {emit: "submitted"} } end @@ -501,7 +501,7 @@ def post_partial(post) small text: post.created_at.strftime("%d.%m.%Y %H:%M") end paragraph text: post.body, class: "mb-5" - action path: like_post_path(post), method: :put, success: { emit: "liked_post_#{post.id}" } do + action path: like_post_path(post), method: :put, success: {emit: "liked_post_#{post.id}"} do button class: "btn btn-light" do plain "Like (#{post.likes_count})" end @@ -523,7 +523,7 @@ Great! We added a reactive form and reactive actions. We can now add some reacti ## Add Reactive Feedback Using the `toggle` Component -* [x] Add failure event submission to the form config like: `failure: { emit: "form_failed" },` +* [x] Add failure event submission to the form config like: `failure: {emit: "form_failed"},` * [x] Add a `toggle` component in order to render the success message for 5 seconds * [x] Add a `toggle` component in order to render the failure message for 5 seconds @@ -565,9 +565,9 @@ class TwitterClone::Pages::Posts::Index < Matestack::Ui::Page def form_config_helper { for: Post.new, path: posts_path, method: :post, - success: { emit: "submitted" }, - failure: { emit: "form_failed" }, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + success: {emit: "submitted"}, + failure: {emit: "form_failed"}, + errors: {wrapper: {tag: :div, class: 'invalid-feedback'}, input: {class: 'is-invalid'}} } end @@ -690,9 +690,9 @@ end def form_config_helper { for: Post.new, path: posts_path, method: :post, - success: { emit: "submitted" }, - failure: { emit: "form_failed" }, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + success: {emit: "submitted"}, + failure: {emit: "form_failed"}, + errors: {wrapper: {tag: :div, class: 'invalid-feedback'}, input: {class: 'is-invalid'}} } end @@ -730,7 +730,7 @@ def post_partial post small text: post.created_at.strftime("%d.%m.%Y %H:%M") end paragraph text: post.body, class: "mb-5" - # action path: like_post_path(post), method: :put, success: { emit: "liked_post_#{post.id}" } do + # action path: like_post_path(post), method: :put, success: {emit: "liked_post_#{post.id}"} do action path: like_post_path(post), method: :put do button class: "btn btn-light" do plain "Like (#{post.likes_count})" @@ -1386,9 +1386,9 @@ class TwitterClone::Pages::Profile::Edit < Matestack::Ui::Page def form_config_helper { for: :profile, path: profile_update_path, method: :put, - success: { emit: "submitted" }, - failure: { emit: "form_failed" }, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + success: {emit: "submitted"}, + failure: {emit: "form_failed"}, + errors: {wrapper: {tag: :div, class: 'invalid-feedback'}, input: {class: 'is-invalid'}} } end @@ -1436,7 +1436,7 @@ class ProfileController < ApplicationController if profile_params[:username].blank? render json: { message: 'Profile could not be updated.', - errors: { username: ["can't be blank!"] } + errors: {username: ["can't be blank!"]} }, status: :unprocessable_entity else cookies[:username] = profile_params[:username] @@ -1645,9 +1645,9 @@ class Components::Post < Matestack::Ui::Component def form_config_helper { for: context.post, path: post_path(id: context.post.id), method: :put, - success: { emit: "updated" }, - failure: { emit: "form_failed" }, - errors: { wrapper: { tag: :div, class: 'invalid-feedback' }, input: { class: 'is-invalid' } } + success: {emit: "updated"}, + failure: {emit: "form_failed"}, + errors: {wrapper: {tag: :div, class: 'invalid-feedback'}, input: {class: 'is-invalid'}} } end From 0c1778e9a453cff7153b35ab12c2ad36ffcde6fe Mon Sep 17 00:00:00 2001 From: Keith Rowell Date: Sun, 11 Apr 2021 17:20:40 +1000 Subject: [PATCH 36/36] converted left over yield_page --- docs/getting-started/quick-start.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 81571ea2f..0f7fa75b0 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -1467,7 +1467,7 @@ class TwitterClone::App < Matestack::Ui::App def response div class: "container" do # heading size: 1, text: "Twitter Clone", class: "mb-5" - # yield_page + # yield if block_given? heading size: 1, text: "Twitter Clone" transition path: posts_path do button class: "btn btn-light", text: "Timeline" @@ -1507,7 +1507,7 @@ end * [x] Again: see how the page is updated without a full browser page reload, maybe even inspect your browsers network monitor ;\) * [x] Post something and enjoy not to enter a username anymore \(use a private tab if you want to act as a different user!\) -Great, we just added a second page and added some `transition` components to our app and without further effort, we implemented dynamic page transitions without touching any JavaScript. The `transition` component triggered the app to request the desired page at the server targeting the appropriate controller action through Rails routing and adjusted the DOM where we placed the `yield_page` on our app! +Great, we just added a second page and added some `transition` components to our app and without further effort, we implemented dynamic page transitions without touching any JavaScript. The `transition` component triggered the app to request the desired page at the server targeting the appropriate controller action through Rails routing and adjusted the DOM where we placed the `yield if block_given?` on our app! And you know what: let's add some CSS animations! @@ -1562,7 +1562,7 @@ class TwitterClone::App < Matestack::Ui::App button class: "btn btn-light", text: "Your Profile" end div class: "mt-5" do - yield_page + yield if block_given? end end end