33
44### Prerequisites
55
6- { [ Ruby On Rails] ( http://rubyonrails.org/ ) }\
6+ { [ Ruby On Rails] ( http://rubyonrails.org/ ) }
77{ [ Yarn] ( https://yarnpkg.com/en/docs/install ) }
88
99### The Goals of this Tutorial
@@ -30,35 +30,35 @@ Basic knowledge of Ruby is needed, knowledge of Ruby on Rails is helpful.
3030### Chapter 1: Setting Things Up
3131
3232First you need to create a new project for this tutorial.
33- ``` shell
34- rails new todo-demo --skip-test --template=https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb
35- ```
33+ ``` shell
34+ rails new todo-demo --skip-test --template=https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb
35+ ```
3636This command will create a new Rails project and run the template file to set up Hyperstack within this project.
3737
38- *** Caution:** you can name the app anything you want, we recommend todo-demo, but whatever you do DON'T call it todo,
38+ ** Caution:** * you can name the app anything you want, we recommend todo-demo, but whatever you do DON'T call it todo,
3939as this name will be needed later!*
4040
41- *** Note:** if you like you can read the contents of the template file by pasting the
41+ ** Note:** * if you like you can read the contents of the template file by pasting the
4242[ url] ( https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb ) (the part after ` --template= ` ) in a browser.
4343It shows how a Hyperstack Rails project differs from a plain Rails project.*
44- ``` shell
45- cd todo-demo
46- ```
44+ ``` shell
45+ cd todo-demo
46+ ```
4747Will change the working directory to your new todo rails project.
4848
4949#### Start the Rails app
5050
5151In the console run the following command to start the Rails server and Hotloader.
52- ``` shell
53- bundle exec foreman start
54- ```
52+ ``` shell
53+ bundle exec foreman start
54+ ```
5555For the rest of the tutorial you will want to keep foreman running in the background
5656and have a second console window open in the ` todo-demo ` directory to execute various commands.
5757
5858Navigate to http://localhost:5000/ in your browser and you should see the word ** Hello world from Hyperstack!** displayed on the page.
5959Hyperstack will need a moment to start and pre-compile with the first request.
6060
61- *** Note:** you will be using port 5000 not the more typical 3000, this is because of the way the Hotloader is configured.*
61+ ** Note:** * you will be using port 5000 not the more typical 3000, this is because of the way the Hotloader is configured.*
6262
6363#### Make a Simple Change
6464
@@ -122,70 +122,70 @@ Okay lets see it in action:
122122
1231231 . ** Add the Todo Model:**
124124
125- As stated earlier we keep * foreman* running in the first console and open a second console.
126- In this second console window run ** on a single line** :
127- ``` shell
128- bundle exec rails g model Todo title:string completed:boolean priority:integer
129- ```
130- This runs a Rails * generator* which will create the skeleton Todo model class, and create a * migration* which will
131- add the necessary tables and columns to the database.
132-
133- Now look in the db/migrate/ directory, and edit the migration file you have just created.
134- The file will be titled with a long string of numbers then "create_todos" at the end.
135- Change the line creating the completed boolean field so that it looks like this:
136- ``` ruby
137- ...
138- t.boolean :completed , null: false , default: false
139- ...
140- ```
141- For details on 'why' see [ this blog post.] ( https://robots.thoughtbot.com/avoid-the-threestate-boolean-problem )
142- Basically this insures ` completed ` is treated as a true boolean, and will avoid having to check between ` false ` and ` null ` later on.
143-
144- Now run:
145- ``` shell
146- bundle exec rails db:migrate
147- ```
148- which will create the table.
125+ As stated earlier we keep * foreman* running in the first console and open a second console.
126+ In this second console window run ** on a single line** :
127+ ``` shell
128+ bundle exec rails g model Todo title:string completed:boolean priority:integer
129+ ```
130+ This runs a Rails * generator* which will create the skeleton Todo model class, and create a * migration* which will
131+ add the necessary tables and columns to the database.
132+
133+ Now look in the db/migrate/ directory, and edit the migration file you have just created.
134+ The file will be titled with a long string of numbers then "create_todos" at the end.
135+ Change the line creating the completed boolean field so that it looks like this:
136+ ``` ruby
137+ ...
138+ t.boolean :completed , null: false , default: false
139+ ...
140+ ```
141+ For details on 'why' see [ this blog post.] ( https://robots.thoughtbot.com/avoid-the-threestate-boolean-problem )
142+ Basically this insures ` completed ` is treated as a true boolean, and will avoid having to check between ` false ` and ` null ` later on.
143+
144+ Now run:
145+ ``` shell
146+ bundle exec rails db:migrate
147+ ```
148+ which will create the table.
149149
1501502 . ** Make Your Model Public:**
151151
152- Move ` models/todo.rb ` to ` hyperstack/models `
152+ Move ` models/todo.rb ` to ` hyperstack/models `
153153
154- This will make the model accessible on the clients * and the server* , subject to any data access policies.
154+ This will make the model accessible on the clients * and the server* , subject to any data access policies.
155155
156- *** Note:** The hyperstack installer adds a policy that gives full permission to all clients but only in
157- development and test modes. Have a look at ` app/policies/application_policy ` if you are interested.*
156+ ** Note:** * The hyperstack installer adds a policy that gives full permission to all clients but only in
157+ development and test modes. Have a look at ` app/policies/application_policy ` if you are interested.*
158158
1591593 . ** Try It:**
160160
161- Now change your ` App ` component's render method to:
162- ``` ruby
163- class App < HyperComponent
164- include Hyperstack ::Router
165- render do
166- H1 { " Number of Todos: #{ Todo .count} " }
167- end
161+ Now change your ` App ` component's render method to:
162+ ``` ruby
163+ class App < HyperComponent
164+ include Hyperstack ::Router
165+ render do
166+ H1 { " Number of Todos: #{ Todo .count} " }
168167 end
169- ```
170-
171- You will now see ** Number of Todos: 0** displayed.
172-
173- Now start a rails console
174- ``` shell
175- bundle exec rails c
176- ```
177- and type:
178- ``` ruby
179- Todo .create(title: ' my first todo' )
180- ```
181- This will create a new Todo in the server's database, which will cause your Hyperstack application to be
182- updated and you will see the count change to 1!
183-
184- Try it again:
185- ``` ruby
186- Todo .create(title: ' my second todo' )
187- ```
188- and you will see the count change to 2!
168+ end
169+ ```
170+
171+ You will now see ** Number of Todos: 0** displayed.
172+
173+ Now start a rails console
174+ ``` shell
175+ bundle exec rails c
176+ ```
177+ and type:
178+ ``` ruby
179+ Todo .create(title: ' my first todo' )
180+ ```
181+ This will create a new Todo in the server's database, which will cause your Hyperstack application to be
182+ updated and you will see the count change to 1!
183+
184+ Try it again:
185+ ``` ruby
186+ Todo .create(title: ' my second todo' )
187+ ```
188+ and you will see the count change to 2!
189189
190190Are we having fun yet? I hope so! As you can see Hyperstack is synchronizing the Todo model between the client and server.
191191As the state of the database changes, Hyperstack buzzes around updating whatever parts of the DOM were dependent on that data
214214
215215After saving you will see the following error displayed:
216216
217- ** Uncaught error: Header: undefined method `Header' for #< App:0x970 >
217+ ** Uncaught error: Header: undefined method `Header' for #\ < App:0x970\ >
218218in App (created by Hyperstack::Internal::Component::TopLevelRailsComponent)
219219in Hyperstack::Internal::Component::TopLevelRailsComponent**
220220
@@ -251,12 +251,12 @@ end
251251
252252Once you add the Footer component you should see:
253253
254- <div style =" border :solid ; margin-left : 10px ; padding : 10px " >
255- <div>Header will go here</div>
256- <div>List of Todos will go here</div>
257- <div>Footer will go here</div>
258- </div >
259- <br >
254+ <div style =" border :solid ; margin-left : 10px ; padding : 10px " >
255+ <div >Header will go here</div >
256+ <div >List of Todos will go here</div >
257+ <div >Footer will go here</div >
258+ </div >
259+ <br >
260260
261261If you don't, restart the server (* foreman* in the first console), and reload the browser.
262262
@@ -299,15 +299,15 @@ end
299299
300300Now you will see something like
301301
302- <div style =" border :solid ; margin-left : 10px ; padding : 10px " >
303- <div>Header will go here</div>
304- <ul>
305- <li>my first todo</li>
306- <li>my second todo</li>
307- </ul>
308- <div>Footer will go here</div>
309- </div >
310- <br >
302+ <div style =" border :solid ; margin-left : 10px ; padding : 10px " >
303+ <div >Header will go here</div >
304+ <ul >
305+ <li>my first todo</li>
306+ <li>my second todo</li>
307+ </ul >
308+ <div >Footer will go here</div >
309+ </div >
310+ <br >
311311
312312As you can see components can take parameters (or props in react.js terminology.)
313313
@@ -321,7 +321,7 @@ Our `Index` component *mounts* a new `TodoItem` with each `Todo` record and pass
321321
322322Now go back to Rails console and type
323323``` ruby
324- Todo .last.update(title: ' updated todo' )
324+ Todo .last.update(title: ' updated todo' )
325325```
326326and you will see the last Todo in the list changing.
327327
@@ -350,7 +350,7 @@ You will notice that while it does display the checkboxes, you can not change th
350350
351351For now we can change them via the console like we did before. Try executing
352352``` ruby
353- Todo .last.update(completed: true )
353+ Todo .last.update(completed: true )
354354```
355355and you should see the last Todo's ` completed ` checkbox changing state.
356356
@@ -389,7 +389,7 @@ class TodoItem < HyperComponent
389389 end
390390end
391391```
392- *** Note:** If a component or tag block returns a string it is automatically wrapped in a SPAN, to insert a string
392+ ** Note:** * If a component or tag block returns a string it is automatically wrapped in a SPAN, to insert a string
393393in the middle you have to wrap it a SPAN like we did above.*
394394
395395I hope you are starting to see a pattern here.
419419```
420420
421421Now we can say ` Todo.all ` , ` Todo.completed ` , and ` Todo.active ` , and get the desired subset of Todos.
422- You might want to try it now in the rails console.\
423- *** Note:** you will have to do a ` reload! ` to load the changes to the Model.*
422+ You might want to try it now in the rails console.
423+ ** Note:** * you will have to do a ` reload! ` to load the changes to the Model.*
424424
425425We would like the URL of our App to reflect which of these * filters* is being displayed. So if we load
426426
@@ -527,13 +527,13 @@ Then we can replace the anchor tag with the Router's `NavLink` component:
527527Change
528528
529529``` ruby
530- A (href: " /#{ path } " , style: { marginRight: 10 }) { path.camelize }
530+ A (href: " /#{ path } " , style: { marginRight: 10 }) { path.camelize }
531531```
532532to
533533
534534``` ruby
535- NavLink (" /#{ path } " , style: { marginRight: 10 }) { path.camelize }
536- # note that there is no href key in NavLink
535+ NavLink (" /#{ path } " , style: { marginRight: 10 }) { path.camelize }
536+ # note that there is no href key in NavLink
537537```
538538
539539Our component should now look like this:
@@ -587,12 +587,12 @@ Before we use this component let's understand how it works.
587587Now update the ` TodoItem ` component replacing
588588
589589``` ruby
590- SPAN { @Todo .title }
590+ SPAN { @Todo .title }
591591```
592592with
593593
594594``` ruby
595- EditItem (todo: @Todo )
595+ EditItem (todo: @Todo )
596596```
597597Try it out by changing the text of some our your Todos followed by the enter key. Then refresh the page to see that the Todos have changed.
598598
@@ -725,9 +725,9 @@ All objects in Hyperstack respond to the `to_key` method which will return a sui
725725this will insure that as ` @Todo ` changes, we will re-initialize the ` INPUT ` tag.
726726
727727``` ruby
728- ...
729- INPUT (defaultValue: @Todo .title, key: @Todo ) # add the special key param
730- ...
728+ ...
729+ INPUT (defaultValue: @Todo .title, key: @Todo ) # add the special key param
730+ ...
731731```
732732
733733
@@ -857,36 +857,36 @@ At this point your Todo App should be properly styled.
857857
858858### Chapter 12: Other Features
859859
860- + ** Show How Many Items Left In Footer** \
860+ + ** Show How Many Items Left In Footer**
861861This is just a span that we add before the link tags list in the ` Footer ` component:
862862
863- ``` ruby
864- ...
865- render(DIV , class : :footer) do
866- SPAN (class : ' todo-count' ) do
867- " #{ Todo .active.count} item#{ ' s' if Todo .active.count != 1 } left"
868- end
869- UL (class : :filters) do
870- ...
871- ```
863+ ``` ruby
864+ ...
865+ render(DIV , class : :footer) do
866+ SPAN (class : ' todo-count' ) do
867+ " #{ Todo .active.count} item#{ ' s' if Todo .active.count != 1 } left"
868+ end
869+ UL (class : :filters) do
870+ ...
871+ ```
872872+ ** Add 'placeholder' Text To Edit Item** \
873873` EditItem ` should display a meaningful placeholder hint if the title is blank:
874874
875- ``` ruby
876- ...
877- INPUT (@Etc , placeholder: ' What is left to do today?' ,
878- defaultValue: @Todo .title, key: @Todo )
879- .on(:enter ) do |evt |
880- ...
881- ```
875+ ``` ruby
876+ ...
877+ INPUT (@Etc , placeholder: ' What is left to do today?' ,
878+ defaultValue: @Todo .title, key: @Todo )
879+ .on(:enter ) do |evt |
880+ ...
881+ ```
882882+ ** Don't Show the Footer If There are No Todos** \
883883In the ` App ` component add a * guard* so that we won't show the Footer if there are no Todos:
884884
885- ``` ruby
886- ...
887- Footer () unless Todo .count.zero?
888- ...
889- ```
885+ ``` ruby
886+ ...
887+ Footer () unless Todo .count.zero?
888+ ...
889+ ```
890890
891891
892892Congratulations! you have completed the tutorial.
0 commit comments