camping 2.1.532 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|