camping 2.1.532 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +72 -53
- data/Rakefile +25 -20
- data/bin/camping +1 -0
- data/book/01_introduction.md +6 -6
- data/book/02_getting_started.md +348 -267
- data/book/03_more_about_controllers.md +124 -0
- data/book/04_more_about_views.md +118 -0
- data/book/05_more_about_markaby.md +173 -0
- data/book/06_more_about_models.md +58 -0
- data/book/06_rules_of_thumb.md +143 -0
- data/book/07_philosophy.md +23 -0
- data/book/08_publishing_an_app.md +118 -0
- data/book/09_upgrade_notes.md +96 -0
- data/book/10_middleware.md +69 -0
- data/book/11_gear.md +50 -0
- data/examples/blog.rb +38 -38
- data/lib/camping/ar.rb +20 -5
- data/lib/camping/commands.rb +388 -0
- data/lib/camping/gear/filters.rb +48 -0
- data/lib/camping/gear/inspection.rb +32 -0
- data/lib/camping/gear/kuddly.rb +178 -0
- data/lib/camping/gear/nancy.rb +170 -0
- data/lib/camping/loads.rb +15 -0
- data/lib/camping/mab.rb +1 -1
- data/lib/camping/reloader.rb +22 -17
- data/lib/camping/server.rb +145 -70
- data/lib/camping/session.rb +8 -5
- data/lib/camping/template.rb +1 -2
- data/lib/camping/tools.rb +43 -0
- data/lib/camping/version.rb +6 -0
- data/lib/camping-unabridged.rb +360 -133
- data/lib/camping.rb +78 -47
- data/lib/campingtrip.md +341 -0
- data/test/app_camping_gear.rb +121 -0
- data/test/app_camping_tools.rb +1 -0
- data/test/app_config.rb +30 -0
- data/test/app_cookies.rb +1 -1
- data/test/app_file.rb +3 -3
- data/test/app_goes_meta.rb +23 -0
- data/test/app_inception.rb +39 -0
- data/test/app_markup.rb +5 -20
- data/test/app_migrations.rb +16 -0
- data/test/app_partials.rb +1 -1
- data/test/app_prefixed.rb +88 -0
- data/test/app_reloader.rb +1 -2
- data/test/app_route_generating.rb +69 -2
- data/test/app_sessions.rb +24 -2
- data/test/app_simple.rb +18 -18
- data/test/apps/migrations.rb +82 -82
- data/test/apps/misc.rb +1 -1
- data/test/gear/gear_nancy.rb +129 -0
- data/test/test_helper.rb +69 -12
- metadata +152 -92
- data/CHANGELOG +0 -145
- data/book/51_upgrading.md +0 -110
data/book/02_getting_started.md
CHANGED
|
@@ -1,85 +1,104 @@
|
|
|
1
|
-
#Getting Started
|
|
1
|
+
# Getting Started
|
|
2
2
|
|
|
3
|
-
Start a new text file called
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Start a new text file called camp.rb. Here's what you put inside:
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
require 'camping'
|
|
7
|
+
Camping.goes :Nuts
|
|
8
|
+
```
|
|
6
9
|
|
|
7
10
|
Save it. Then, open a command prompt in the same directory. You'll want to
|
|
8
11
|
run:
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
```ruby
|
|
14
|
+
$ camping
|
|
15
|
+
```
|
|
11
16
|
|
|
12
17
|
And you should get a message which reads:
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
```ruby
|
|
20
|
+
** Camping running on 0.0.0.0:3301.
|
|
21
|
+
```
|
|
15
22
|
|
|
16
23
|
This means that right now The Camping Server is running on port 3301 on your
|
|
17
24
|
machine. Open your browser and visit http://localhost:3301/.
|
|
18
25
|
|
|
19
26
|
Your browser window should show:
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
```
|
|
29
|
+
Camping Problem!
|
|
30
|
+
|
|
31
|
+
/ Not found
|
|
32
|
+
```
|
|
24
33
|
|
|
25
34
|
No problem with that. The Camping Server is running, but it doesn't know what
|
|
26
|
-
to show. Let's tell
|
|
35
|
+
to show. Let's tell them.
|
|
27
36
|
|
|
28
|
-
##Hello clock
|
|
37
|
+
## Hello clock
|
|
29
38
|
|
|
30
39
|
So, you've got Camping installed and it's running. Keep it running. You can
|
|
31
40
|
edit files and The Camping Server will reload automatically. When you need to
|
|
32
41
|
stop the server, press Control-C.
|
|
33
42
|
|
|
34
|
-
Let's show something. At the bottom of
|
|
43
|
+
Let's show something. At the bottom of camp.rb add:
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
end
|
|
45
|
+
```ruby
|
|
46
|
+
module Nuts::Controllers
|
|
47
|
+
class Index < R '/'
|
|
48
|
+
def get
|
|
49
|
+
Time.now.to_s
|
|
42
50
|
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
```
|
|
43
54
|
|
|
44
55
|
Save the file and refresh the browser window. Your browser window should show
|
|
45
56
|
the time, e.g.
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
```
|
|
59
|
+
Sun Jul 15 12:56:15 +0200 2007
|
|
60
|
+
```
|
|
48
61
|
|
|
49
|
-
##Enjoying the view
|
|
62
|
+
## Enjoying the view
|
|
50
63
|
|
|
51
64
|
The Camping microframework allows us to separate our code using the MVC
|
|
52
65
|
(Model-View-Controller) design pattern. Let's add a view to our Nuts
|
|
53
66
|
application. Replace the <tt>module Nuts::Controllers</tt> with:
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
```ruby
|
|
69
|
+
module Nuts::Controllers
|
|
70
|
+
class Index < R '/'
|
|
71
|
+
def get
|
|
72
|
+
@time = Time.now
|
|
73
|
+
render :sundial
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
module Nuts::Views
|
|
81
|
+
def layout
|
|
82
|
+
html do
|
|
83
|
+
head do
|
|
84
|
+
title { "Nuts And GORP" }
|
|
61
85
|
end
|
|
86
|
+
body { self << yield }
|
|
62
87
|
end
|
|
88
|
+
end
|
|
63
89
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
body { self << yield }
|
|
71
|
-
end
|
|
72
|
-
end
|
|
90
|
+
def sundial
|
|
91
|
+
p "The current time is: #{@time}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
```
|
|
73
95
|
|
|
74
|
-
|
|
75
|
-
p "The current time is: #{@time}"
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
Save the file and refresh your browser window and it should show a message
|
|
96
|
+
Save the file, refresh your browser window and it should show a message
|
|
80
97
|
like:
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
```
|
|
100
|
+
The current time is: Sun Jul 15 13:05:41 +0200 2013
|
|
101
|
+
```
|
|
83
102
|
|
|
84
103
|
And the window title reads "Nuts And GORP".
|
|
85
104
|
|
|
@@ -94,7 +113,7 @@ Soon enough, you'll find that you can return anything from the controller, and
|
|
|
94
113
|
it will be sent to the browser. But let's keep that for later and start
|
|
95
114
|
investigating the routes.
|
|
96
115
|
|
|
97
|
-
##Routes
|
|
116
|
+
## Routes
|
|
98
117
|
|
|
99
118
|
You probably noticed the weird <tt>R '/'</tt> syntax in the previous page.
|
|
100
119
|
This is an uncommon feature of Ruby that is used in our favorite
|
|
@@ -104,73 +123,77 @@ on.
|
|
|
104
123
|
These routes can be very powerful, but we're going to have look at the
|
|
105
124
|
simplest ones first.
|
|
106
125
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class Digits < R '/nuts/(\d+)'
|
|
115
|
-
def get(number)
|
|
116
|
-
"You got here by: /nuts/#{number}"
|
|
117
|
-
end
|
|
118
|
-
end
|
|
126
|
+
```ruby
|
|
127
|
+
module Nuts::Controllers
|
|
128
|
+
class Words < R '/welcome/to/my/site'
|
|
129
|
+
def get
|
|
130
|
+
"You got here by: /welcome/to/my/site"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
119
133
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
class DigitsAndEverything < R '/nuts/(\d+)/([^/]+)'
|
|
127
|
-
def get(number, everything)
|
|
128
|
-
"You got here by: /nuts/#{number}/#{everything}"
|
|
129
|
-
end
|
|
130
|
-
end
|
|
134
|
+
class Digits < R '/nuts/(\d+)'
|
|
135
|
+
def get(number)
|
|
136
|
+
"You got here by: /nuts/#{number}"
|
|
131
137
|
end
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class Segment < R '/gorp/([^/]+)'
|
|
141
|
+
def get(everything_else_than_a_slash)
|
|
142
|
+
"You got here by: /gorp/#{everything_else_than_a_slash}"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class DigitsAndEverything < R '/nuts/(\d+)/([^/]+)'
|
|
147
|
+
def get(number, everything)
|
|
148
|
+
"You got here by: /nuts/#{number}/#{everything}"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Add this to `nuts.rb` and try if you can hit all of the controllers.
|
|
134
155
|
|
|
135
156
|
Also notice how everything inside a parenthesis gets passed into the method,
|
|
136
157
|
and is ready at your disposal.
|
|
137
158
|
|
|
138
|
-
###Simpler routes
|
|
159
|
+
### Simpler routes
|
|
139
160
|
|
|
140
161
|
This just in:
|
|
141
162
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
class NutsNX
|
|
168
|
-
def get(number, everything)
|
|
169
|
-
"You got here by: /nuts/#{number}/#{everything}"
|
|
170
|
-
end
|
|
171
|
-
end
|
|
163
|
+
```ruby
|
|
164
|
+
module Nuts::Controllers
|
|
165
|
+
class Index
|
|
166
|
+
def get
|
|
167
|
+
"You got here by: /"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class WelcomeToMySite
|
|
172
|
+
def get
|
|
173
|
+
"You got here by: /welcome/to/my/site"
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class NutsN
|
|
178
|
+
def get(number)
|
|
179
|
+
"You got here by: /nuts/#{number}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
class GorpX
|
|
184
|
+
def get(everything_else_than_a_slash)
|
|
185
|
+
"You got here by: /gorp/#{everything_else_than_a_slash}"
|
|
172
186
|
end
|
|
173
|
-
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
class NutsNX
|
|
190
|
+
def get(number, everything)
|
|
191
|
+
"You got here by: /nuts/#{number}/#{everything}"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
174
197
|
Drop the <tt>< R</tt>-part and it attemps to read your mind. It won't always
|
|
175
198
|
succeed, but it can simplify your application once in a while.
|
|
176
199
|
|
|
@@ -181,15 +204,17 @@ playing a bit off-book, but it's time to take the next step: Storing data.
|
|
|
181
204
|
|
|
182
205
|
Let's start over again.
|
|
183
206
|
|
|
184
|
-
|
|
207
|
+
```ruby
|
|
208
|
+
Camping.goes :Nuts
|
|
209
|
+
|
|
210
|
+
module Nuts::Models
|
|
211
|
+
class Page < Base
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
```
|
|
185
215
|
|
|
186
|
-
module Nuts::Models
|
|
187
|
-
class Page < Base
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
216
|
Obviously, this won't do anything, since we don't have any controllers, but
|
|
192
|
-
let's rather have a look at we _do_ have.
|
|
217
|
+
let's rather have a look at what we _do_ have.
|
|
193
218
|
|
|
194
219
|
We have a model named Page. This means we now can store wiki pages and
|
|
195
220
|
retrieve them later. In fact, we can have as many models as we want. Need one
|
|
@@ -197,199 +222,255 @@ for your users and one for your blog posts? Well, I think you already know how
|
|
|
197
222
|
to do it.
|
|
198
223
|
|
|
199
224
|
However, our model is missing something essential: a skeleton.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def self.down
|
|
218
|
-
drop_table Page.table_name
|
|
219
|
-
end
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
Camping.goes :Nuts
|
|
228
|
+
|
|
229
|
+
module Nuts::Models
|
|
230
|
+
class Page < Base
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class BasicFields < V 1.0
|
|
234
|
+
def self.up
|
|
235
|
+
create_table Page.table_name do |t|
|
|
236
|
+
t.string :title
|
|
237
|
+
t.text :content
|
|
238
|
+
# This gives us created_at and updated_at
|
|
239
|
+
t.timestamps
|
|
220
240
|
end
|
|
221
241
|
end
|
|
222
|
-
|
|
242
|
+
|
|
243
|
+
def self.down
|
|
244
|
+
drop_table Page.table_name
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
```
|
|
249
|
+
|
|
223
250
|
Now we have our first version of our model. It says:
|
|
224
251
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
252
|
+
```
|
|
253
|
+
If you want to migrate up to version one,
|
|
254
|
+
create the skeleton for the Page model,
|
|
255
|
+
which should be able to store,
|
|
256
|
+
"title" which is a string,
|
|
257
|
+
"content" which is a larger text,
|
|
258
|
+
"created_at" which is the time it was created,
|
|
259
|
+
"updated_at" which is the previous time it was updated.
|
|
260
|
+
|
|
261
|
+
If you want to migrate down from version one,
|
|
262
|
+
remove the skeleton for the Page model.
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This is called a
|
|
266
|
+
[migration](http://api.rubyonrails.org/classes/ActiveRecord/Migration.html).
|
|
267
|
+
Whenever you want to change or add new models you simply add a new migration
|
|
268
|
+
below, where you increase the version number. All of these migrations builds
|
|
269
|
+
upon each other like LEGO blocks. Each new Migrations must have different
|
|
270
|
+
class's names, is a good idea name migration's explicit. For example:
|
|
271
|
+
|
|
272
|
+
```ruby
|
|
273
|
+
class AddTagColumn < V 1.1
|
|
274
|
+
def self.change
|
|
275
|
+
add_column Page.table_name, :tag, :string
|
|
276
|
+
Page.reset_column_information
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
```
|
|
237
280
|
|
|
238
281
|
Now we just need to tell Camping to use our migration. Write this at the bottom of nuts.rb
|
|
239
282
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
283
|
+
```ruby
|
|
284
|
+
def Nuts.create
|
|
285
|
+
Nuts::Models.create_schema
|
|
286
|
+
end
|
|
287
|
+
```
|
|
243
288
|
|
|
244
289
|
When The Camping Server boots up, it will automatically call
|
|
245
290
|
<tt>Nuts.create</tt>. You can put all kind of startup-code here, but right now
|
|
246
291
|
we only want to create our skeleton (or upgrade if needed). Start The Camping
|
|
247
292
|
Server again and observe:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
$ camping nuts.rb
|
|
296
|
+
** Starting Mongrel on 0.0.0.0:3301
|
|
297
|
+
-- create_table("nuts_schema_infos")
|
|
298
|
+
-> 0.1035s
|
|
299
|
+
== Nuts::Models::BasicFields: migrating ===================================
|
|
300
|
+
-- create_table(:nuts_pages)
|
|
301
|
+
-> 0.0033s
|
|
302
|
+
== Nuts::Models::BasicFields: migrated (0.0038s) ==========================
|
|
303
|
+
```
|
|
304
|
+
|
|
258
305
|
Restart it, and enjoy the silence. There's no point of re-creating the
|
|
259
306
|
skeleton this time.
|
|
260
307
|
|
|
261
|
-
Before we go on, there's one rule you must
|
|
308
|
+
Before we go on, there's one rule you must know: Always place your models
|
|
262
309
|
before your migrations.
|
|
263
310
|
|
|
264
311
|
## Using our model
|
|
265
312
|
|
|
266
|
-
Let's explore how our model works by going into the _console_
|
|
313
|
+
Let's explore how our model works by going into the _console_. The console
|
|
314
|
+
is good way to familiarize with your models. Test your models adding some
|
|
315
|
+
data by bare hand before addin it to the application.
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
$ camping -C nuts.rb
|
|
319
|
+
** Starting console
|
|
320
|
+
>>
|
|
321
|
+
```
|
|
267
322
|
|
|
268
|
-
$ camping -C nuts.rb
|
|
269
|
-
** Starting console
|
|
270
|
-
>>
|
|
271
|
-
|
|
272
323
|
Now it's waiting for your input, and will give you the answer when you press
|
|
273
324
|
Enter. Here's what I did, leaving out the boring answers. You should add your
|
|
274
325
|
own pages.
|
|
275
326
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
327
|
+
```bash
|
|
328
|
+
>> Page = Nuts::Models::Page
|
|
329
|
+
|
|
330
|
+
>> hiking = Page.new(:title => "Hiking")
|
|
331
|
+
>> hiking.content = "You can also set the values like this."
|
|
332
|
+
>> hiking.save
|
|
333
|
+
|
|
334
|
+
>> page = Page.find_by_title("Hiking")
|
|
335
|
+
=> #<Nuts::Models::Page id: 1, ... >
|
|
336
|
+
>> page = Page.find(1)
|
|
337
|
+
=> #<Nuts::Models::Page id: 1, ... >
|
|
338
|
+
>> page.title
|
|
339
|
+
>> page.content
|
|
340
|
+
>> page.created_at
|
|
341
|
+
>> page.updated_at
|
|
342
|
+
|
|
343
|
+
>> Page.find_by_title("Fishing")
|
|
344
|
+
=> nil
|
|
345
|
+
|
|
346
|
+
## Page.create automatically saves the page for you.
|
|
347
|
+
>> Page.create(:title => "Fishing", :content => "Go fish!")
|
|
348
|
+
|
|
349
|
+
>> Page.count
|
|
350
|
+
=> 2
|
|
351
|
+
```
|
|
352
|
+
|
|
300
353
|
Now I have two pages: One about hiking and one about fishing.
|
|
301
354
|
|
|
302
|
-
##Wrapping it up
|
|
355
|
+
## Wrapping it up
|
|
303
356
|
|
|
304
357
|
Wouldn't it be nice if we could show this wonderful our pages in a browser?
|
|
305
358
|
Update nuts.rb so it also contains something like this:
|
|
306
359
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
class PageX
|
|
317
|
-
def get(title)
|
|
318
|
-
@page = Page.find_by_title(title)
|
|
319
|
-
render :view
|
|
320
|
-
end
|
|
321
|
-
end
|
|
360
|
+
```ruby
|
|
361
|
+
module Nuts::Controllers
|
|
362
|
+
class Pages
|
|
363
|
+
def get
|
|
364
|
+
# Only fetch the titles of the pages.
|
|
365
|
+
@pages = Page.all(:select => "title")
|
|
366
|
+
render :list
|
|
322
367
|
end
|
|
368
|
+
end
|
|
323
369
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
370
|
+
class PageX
|
|
371
|
+
def get(title)
|
|
372
|
+
@page = Page.find_by_title(title)
|
|
373
|
+
render :view
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
module Nuts::Views
|
|
379
|
+
def list
|
|
380
|
+
h1 "All pages"
|
|
381
|
+
ul do
|
|
382
|
+
@pages.each do |page|
|
|
383
|
+
li do
|
|
384
|
+
a page.title, :href => R(PageX, page.title)
|
|
333
385
|
end
|
|
334
386
|
end
|
|
335
|
-
|
|
336
|
-
def view
|
|
337
|
-
h1 @page.title
|
|
338
|
-
self << @page.content
|
|
339
|
-
end
|
|
340
387
|
end
|
|
341
|
-
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def view
|
|
391
|
+
h1 @page.title
|
|
392
|
+
self << @page.content
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
```
|
|
396
|
+
|
|
342
397
|
Here we meet our first _helper_:
|
|
343
398
|
|
|
344
|
-
|
|
345
|
-
|
|
399
|
+
```ruby
|
|
400
|
+
R(PageX, page.title)
|
|
401
|
+
```
|
|
346
402
|
This is the <em>reversed router</em> and it generates a URL based on a
|
|
347
|
-
controller.
|
|
348
|
-
|
|
349
|
-
|
|
403
|
+
controller. R takes the controller you want to link to, followed by the router
|
|
404
|
+
parameters. . Instead of typing:
|
|
405
|
+
|
|
406
|
+
```ruby
|
|
407
|
+
:href=>'/welcome/to/my/site'
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
You can let Camping do the hard work for you.
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
:href=>R(Words)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
If the route would have some parameter, you shall write like this:
|
|
417
|
+
|
|
418
|
+
```ruby
|
|
419
|
+
:href=>R(WordsX,'someword')
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Camping ships with a few, but very useful, helpers, and you can easily add your
|
|
423
|
+
owns. Have a look at Camping::Helpers for how you use these.
|
|
424
|
+
|
|
350
425
|
There's a lot of improvements you could do here. Let me suggest:
|
|
351
426
|
|
|
352
427
|
* Show when the page was created and last updated.
|
|
353
428
|
* What happens when the page doesn't exist?
|
|
354
429
|
* What should the front page show?
|
|
430
|
+
* Allow or disallow authenticated users.
|
|
355
431
|
* Add a layout.
|
|
356
432
|
* Jazz it up a bit.
|
|
357
|
-
|
|
358
|
-
|
|
433
|
+
|
|
434
|
+
Helpers can work generating Markaby's code. You could write a helper for show
|
|
435
|
+
some kind of data and call it from your views (Add a layout).
|
|
436
|
+
|
|
437
|
+
## The last touch
|
|
359
438
|
|
|
360
439
|
We have one major flaw in our little application. You can't edit or add new
|
|
361
440
|
pages. Let's see if we can fix that:
|
|
362
441
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
def post(title)
|
|
374
|
-
# If it doesn't exist, initialize it:
|
|
375
|
-
@page = Page.find_or_initialize_by_title(title)
|
|
376
|
-
# This is the same as:
|
|
377
|
-
# @page = Page.find_by_title(title) || Page.new(:title => title)
|
|
378
|
-
|
|
379
|
-
@page.content = @input.content
|
|
380
|
-
@page.save
|
|
381
|
-
redirect PageX, title
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
class PageXEdit
|
|
386
|
-
def get(title)
|
|
387
|
-
@page = Page.find_or_initialize_by_title(title)
|
|
388
|
-
render :edit
|
|
389
|
-
end
|
|
442
|
+
```ruby
|
|
443
|
+
module Nuts::Controllers
|
|
444
|
+
class PageX
|
|
445
|
+
def get(title)
|
|
446
|
+
if @page = Page.find_by_title(title)
|
|
447
|
+
render :view
|
|
448
|
+
else
|
|
449
|
+
redirect PageXEdit, title
|
|
390
450
|
end
|
|
391
451
|
end
|
|
392
|
-
|
|
452
|
+
|
|
453
|
+
def post(title)
|
|
454
|
+
# If it doesn't exist, initialize it:
|
|
455
|
+
@page = Page.find_or_initialize_by_title(title)
|
|
456
|
+
# This is the same as:
|
|
457
|
+
# @page = Page.find_by_title(title) || Page.new(:title => title)
|
|
458
|
+
|
|
459
|
+
@page.content = @input.content
|
|
460
|
+
@page.save
|
|
461
|
+
redirect PageX, title
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
class PageXEdit
|
|
466
|
+
def get(title)
|
|
467
|
+
@page = Page.find_or_initialize_by_title(title)
|
|
468
|
+
render :edit
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
```
|
|
473
|
+
|
|
393
474
|
The core of this code lies in the new <tt>post</tt> method in the PageX
|
|
394
475
|
controller. When someone types an address or follows a link, they'll end up at
|
|
395
476
|
the <tt>get</tt> method, but you can easily create a form which rather sends
|
|
@@ -405,23 +486,24 @@ forms and those in the URL (<tt>/posts?page=50</tt>).
|
|
|
405
486
|
|
|
406
487
|
Here's an <tt>edit</tt>-view, but you can probably do better. See if you can
|
|
407
488
|
integrate all of this with what you already have.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
end
|
|
489
|
+
|
|
490
|
+
```ruby
|
|
491
|
+
module Nuts::Views
|
|
492
|
+
def edit
|
|
493
|
+
h1 @page.title
|
|
494
|
+
form :action => R(PageX, @page.title), :method => :post do
|
|
495
|
+
textarea @page.content, :name => :content,
|
|
496
|
+
:rows => 10, :cols => 50
|
|
497
|
+
|
|
498
|
+
br
|
|
499
|
+
|
|
500
|
+
input :type => :submit, :value => "Submit!"
|
|
421
501
|
end
|
|
422
|
-
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
```
|
|
423
505
|
|
|
424
|
-
##Phew.
|
|
506
|
+
## Phew.
|
|
425
507
|
|
|
426
508
|
You've taken quite a few steps in the last minutes. You deserve a break. But
|
|
427
509
|
let's recap for a moment:
|
|
@@ -437,7 +519,6 @@ let's recap for a moment:
|
|
|
437
519
|
* Place your models before your migrations.
|
|
438
520
|
* Helpers are helpful.
|
|
439
521
|
|
|
440
|
-
|
|
441
|
-
the mailing list to stay updated, and hopefully there's another chapter
|
|
442
|
-
waiting for you.
|
|
522
|
+
If you wanna dive deep, stay reading for a [more extended tutorial](03_more_about_controllers.md) step by step...
|
|
443
523
|
|
|
524
|
+
Enjoy the code
|