3
3
4
4
### Prerequisites
5
5
6
- { [ Ruby On Rails] ( http://rubyonrails.org/ ) }\
6
+ { [ Ruby On Rails] ( http://rubyonrails.org/ ) }
7
7
{ [ Yarn] ( https://yarnpkg.com/en/docs/install ) }
8
8
9
9
### The Goals of this Tutorial
@@ -30,35 +30,35 @@ Basic knowledge of Ruby is needed, knowledge of Ruby on Rails is helpful.
30
30
### Chapter 1: Setting Things Up
31
31
32
32
First 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
+ ```
36
36
This command will create a new Rails project and run the template file to set up Hyperstack within this project.
37
37
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,
39
39
as this name will be needed later!*
40
40
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
42
42
[ url] ( https://rawgit.com/hyperstack-org/hyperstack/edge/install/rails-webpacker.rb ) (the part after ` --template= ` ) in a browser.
43
43
It 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
+ ```
47
47
Will change the working directory to your new todo rails project.
48
48
49
49
#### Start the Rails app
50
50
51
51
In 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
+ ```
55
55
For the rest of the tutorial you will want to keep foreman running in the background
56
56
and have a second console window open in the ` todo-demo ` directory to execute various commands.
57
57
58
58
Navigate to http://localhost:5000/ in your browser and you should see the word ** Hello world from Hyperstack!** displayed on the page.
59
59
Hyperstack will need a moment to start and pre-compile with the first request.
60
60
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.*
62
62
63
63
#### Make a Simple Change
64
64
@@ -122,70 +122,70 @@ Okay lets see it in action:
122
122
123
123
1 . ** Add the Todo Model:**
124
124
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.
149
149
150
150
2 . ** Make Your Model Public:**
151
151
152
- Move ` models/todo.rb ` to ` hyperstack/models `
152
+ Move ` models/todo.rb ` to ` hyperstack/models `
153
153
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.
155
155
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.*
158
158
159
159
3 . ** Try It:**
160
160
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} " }
168
167
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!
189
189
190
190
Are we having fun yet? I hope so! As you can see Hyperstack is synchronizing the Todo model between the client and server.
191
191
As the state of the database changes, Hyperstack buzzes around updating whatever parts of the DOM were dependent on that data
214
214
215
215
After saving you will see the following error displayed:
216
216
217
- ** Uncaught error: Header: undefined method `Header' for #< App:0x970 >
217
+ ** Uncaught error: Header: undefined method `Header' for #\ < App:0x970\ >
218
218
in App (created by Hyperstack::Internal::Component::TopLevelRailsComponent)
219
219
in Hyperstack::Internal::Component::TopLevelRailsComponent**
220
220
@@ -251,12 +251,12 @@ end
251
251
252
252
Once you add the Footer component you should see:
253
253
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 >
260
260
261
261
If you don't, restart the server (* foreman* in the first console), and reload the browser.
262
262
@@ -299,15 +299,15 @@ end
299
299
300
300
Now you will see something like
301
301
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 >
311
311
312
312
As you can see components can take parameters (or props in react.js terminology.)
313
313
@@ -321,7 +321,7 @@ Our `Index` component *mounts* a new `TodoItem` with each `Todo` record and pass
321
321
322
322
Now go back to Rails console and type
323
323
``` ruby
324
- Todo .last.update(title: ' updated todo' )
324
+ Todo .last.update(title: ' updated todo' )
325
325
```
326
326
and you will see the last Todo in the list changing.
327
327
@@ -350,7 +350,7 @@ You will notice that while it does display the checkboxes, you can not change th
350
350
351
351
For now we can change them via the console like we did before. Try executing
352
352
``` ruby
353
- Todo .last.update(completed: true )
353
+ Todo .last.update(completed: true )
354
354
```
355
355
and you should see the last Todo's ` completed ` checkbox changing state.
356
356
@@ -389,7 +389,7 @@ class TodoItem < HyperComponent
389
389
end
390
390
end
391
391
```
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
393
393
in the middle you have to wrap it a SPAN like we did above.*
394
394
395
395
I hope you are starting to see a pattern here.
419
419
```
420
420
421
421
Now 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.*
424
424
425
425
We would like the URL of our App to reflect which of these * filters* is being displayed. So if we load
426
426
@@ -527,13 +527,13 @@ Then we can replace the anchor tag with the Router's `NavLink` component:
527
527
Change
528
528
529
529
``` ruby
530
- A (href: " /#{ path } " , style: { marginRight: 10 }) { path.camelize }
530
+ A (href: " /#{ path } " , style: { marginRight: 10 }) { path.camelize }
531
531
```
532
532
to
533
533
534
534
``` 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
537
537
```
538
538
539
539
Our component should now look like this:
@@ -587,12 +587,12 @@ Before we use this component let's understand how it works.
587
587
Now update the ` TodoItem ` component replacing
588
588
589
589
``` ruby
590
- SPAN { @Todo .title }
590
+ SPAN { @Todo .title }
591
591
```
592
592
with
593
593
594
594
``` ruby
595
- EditItem (todo: @Todo )
595
+ EditItem (todo: @Todo )
596
596
```
597
597
Try 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.
598
598
@@ -725,9 +725,9 @@ All objects in Hyperstack respond to the `to_key` method which will return a sui
725
725
this will insure that as ` @Todo ` changes, we will re-initialize the ` INPUT ` tag.
726
726
727
727
``` 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
+ ...
731
731
```
732
732
733
733
@@ -857,36 +857,36 @@ At this point your Todo App should be properly styled.
857
857
858
858
### Chapter 12: Other Features
859
859
860
- + ** Show How Many Items Left In Footer** \
860
+ + ** Show How Many Items Left In Footer**
861
861
This is just a span that we add before the link tags list in the ` Footer ` component:
862
862
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
+ ```
872
872
+ ** Add 'placeholder' Text To Edit Item** \
873
873
` EditItem ` should display a meaningful placeholder hint if the title is blank:
874
874
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
+ ```
882
882
+ ** Don't Show the Footer If There are No Todos** \
883
883
In the ` App ` component add a * guard* so that we won't show the Footer if there are no Todos:
884
884
885
- ``` ruby
886
- ...
887
- Footer () unless Todo .count.zero?
888
- ...
889
- ```
885
+ ``` ruby
886
+ ...
887
+ Footer () unless Todo .count.zero?
888
+ ...
889
+ ```
890
890
891
891
892
892
Congratulations! you have completed the tutorial.
0 commit comments