ramaze 2011.07.25 → 2011.10.23
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.mailmap +3 -2
- data/.travis.yml +17 -0
- data/.yardopts +13 -0
- data/README.md +95 -352
- data/examples/app/blog/app.rb +25 -64
- data/examples/app/blog/config.ru +11 -9
- data/examples/app/blog/controller/init.rb +29 -86
- data/examples/app/blog/controller/posts.rb +232 -0
- data/examples/app/blog/controller/users.rb +160 -0
- data/examples/app/blog/layout/default.xhtml +61 -0
- data/examples/app/blog/migrations/01_create_schema.rb +50 -0
- data/examples/app/blog/model/comment.rb +41 -54
- data/examples/app/blog/model/init.rb +41 -13
- data/examples/app/blog/model/post.rb +35 -0
- data/examples/app/blog/model/user.rb +105 -0
- data/examples/app/blog/public/.htaccess +24 -0
- data/examples/app/blog/public/css/grid.css +107 -0
- data/examples/app/blog/public/css/layout.css +203 -0
- data/examples/app/blog/public/css/reset.css +123 -0
- data/examples/app/blog/public/css/text.css +109 -0
- data/examples/app/blog/public/dispatch.fcgi +11 -0
- data/examples/app/blog/public/favicon.ico +0 -0
- data/examples/app/blog/public/images/bg.png +0 -0
- data/examples/app/blog/start.rb +18 -3
- data/examples/app/blog/view/feed.xhtml +23 -0
- data/examples/app/blog/view/form.xhtml +11 -0
- data/examples/app/blog/view/index.xhtml +44 -0
- data/examples/app/blog/view/users/form.xhtml +12 -0
- data/examples/app/blog/view/users/index.xhtml +30 -0
- data/examples/app/blog/view/users/login.xhtml +8 -0
- data/examples/app/blog/view/view.xhtml +68 -0
- data/{doc → guide}/AUTHORS +5 -3
- data/{doc → guide}/CHANGELOG +428 -0
- data/{doc/GPL → guide/GPL_LICENSE} +0 -0
- data/{doc/COPYING → guide/RUBY_LICENSE} +3 -6
- data/guide/_static/logo.png +0 -0
- data/guide/_static/logo.svg +49 -0
- data/guide/_static/ramaze_console.png +0 -0
- data/guide/css/common.css +20 -0
- data/guide/general/cache.md +167 -0
- data/guide/general/configuration.md +168 -0
- data/guide/general/contributing.md +108 -0
- data/guide/general/controllers.md +115 -0
- data/guide/general/helpers.md +76 -0
- data/guide/general/installation.md +58 -0
- data/guide/general/logging.md +99 -0
- data/guide/general/middlewares.md +100 -0
- data/guide/general/models.md +78 -0
- data/guide/general/principles.md +53 -0
- data/guide/general/ramaze_command.md +155 -0
- data/guide/general/routes.md +81 -0
- data/guide/general/sessions.md +140 -0
- data/guide/general/special_thanks.md +67 -0
- data/guide/general/testing.md +61 -0
- data/guide/general/views.md +322 -0
- data/guide/tutorials/introduction.md +259 -0
- data/lib/proto/config.ru +1 -1
- data/lib/proto/public/favicon.ico +0 -0
- data/lib/proto/view/index.xhtml +7 -7
- data/lib/ramaze.rb +4 -4
- data/lib/ramaze/app.rb +11 -11
- data/lib/ramaze/app_graph.rb +2 -4
- data/lib/ramaze/bin/console.rb +3 -3
- data/lib/ramaze/bin/create.rb +2 -2
- data/lib/ramaze/bin/restart.rb +4 -4
- data/lib/ramaze/bin/runner.rb +5 -5
- data/lib/ramaze/bin/start.rb +19 -4
- data/lib/ramaze/bin/status.rb +3 -3
- data/lib/ramaze/bin/stop.rb +3 -3
- data/lib/ramaze/cache.rb +1 -0
- data/lib/ramaze/cache/lru.rb +8 -4
- data/lib/ramaze/cache/memcache.rb +32 -13
- data/lib/ramaze/cache/redis.rb +164 -0
- data/lib/ramaze/cache/sequel.rb +43 -28
- data/lib/ramaze/controller.rb +1 -2
- data/lib/ramaze/dependencies.rb +40 -3
- data/lib/ramaze/helper/bench.rb +26 -16
- data/lib/ramaze/helper/blue_form.rb +46 -73
- data/lib/ramaze/helper/cache.rb +10 -6
- data/lib/ramaze/helper/csrf.rb +35 -39
- data/lib/ramaze/helper/disqus.rb +5 -4
- data/lib/ramaze/helper/email.rb +35 -24
- data/lib/ramaze/helper/erector.rb +9 -13
- data/lib/ramaze/helper/flash.rb +7 -9
- data/lib/ramaze/helper/formatting.rb +194 -179
- data/lib/ramaze/helper/gravatar.rb +4 -8
- data/lib/ramaze/helper/identity.rb +3 -3
- data/lib/ramaze/helper/layout.rb +23 -8
- data/lib/ramaze/helper/markaby.rb +1 -1
- data/lib/ramaze/helper/paginate.rb +46 -39
- data/lib/ramaze/helper/request_accessor.rb +3 -1
- data/lib/ramaze/helper/simple_captcha.rb +18 -17
- data/lib/ramaze/helper/stack.rb +1 -1
- data/lib/ramaze/helper/tagz.rb +4 -2
- data/lib/ramaze/helper/upload.rb +523 -0
- data/lib/ramaze/helper/user.rb +4 -8
- data/lib/ramaze/helper/xhtml.rb +11 -15
- data/lib/ramaze/log.rb +9 -6
- data/lib/ramaze/log/rotatinginformer.rb +62 -27
- data/lib/ramaze/log/syslog.rb +20 -15
- data/lib/ramaze/log/xosd.rb +2 -1
- data/lib/ramaze/reloader.rb +2 -0
- data/lib/ramaze/request.rb +11 -10
- data/lib/ramaze/setup.rb +23 -6
- data/lib/ramaze/snippets/array/put_within.rb +3 -9
- data/lib/ramaze/snippets/binding/locals.rb +5 -10
- data/lib/ramaze/snippets/fiber.rb +1 -23
- data/lib/ramaze/snippets/kernel/pretty_inspect.rb +3 -6
- data/lib/ramaze/snippets/numeric/filesize_format.rb +3 -5
- data/lib/ramaze/snippets/numeric/time.rb +3 -7
- data/lib/ramaze/snippets/object/__dir__.rb +3 -7
- data/lib/ramaze/snippets/object/instance_variable_defined.rb +3 -6
- data/lib/ramaze/snippets/object/pretty.rb +3 -7
- data/lib/ramaze/snippets/object/scope.rb +7 -9
- data/lib/ramaze/snippets/proc/locals.rb +12 -12
- data/lib/ramaze/snippets/ramaze/acquire.rb +15 -14
- data/lib/ramaze/snippets/ramaze/deprecated.rb +1 -1
- data/lib/ramaze/snippets/ramaze/fiber.rb +1 -1
- data/lib/ramaze/snippets/ramaze/lru_hash.rb +2 -3
- data/lib/ramaze/snippets/ramaze/struct.rb +2 -4
- data/lib/ramaze/snippets/string/camel_case.rb +8 -10
- data/lib/ramaze/snippets/string/color.rb +3 -4
- data/lib/ramaze/snippets/string/end_with.rb +3 -6
- data/lib/ramaze/snippets/string/esc.rb +3 -8
- data/lib/ramaze/snippets/string/ord.rb +3 -8
- data/lib/ramaze/snippets/string/snake_case.rb +6 -9
- data/lib/ramaze/snippets/string/start_with.rb +3 -8
- data/lib/ramaze/snippets/string/unindent.rb +3 -6
- data/lib/ramaze/snippets/thread/into.rb +1 -3
- data/lib/ramaze/spec.rb +2 -31
- data/lib/ramaze/spec/bacon.rb +18 -2
- data/lib/ramaze/version.rb +1 -1
- data/lib/ramaze/view.rb +1 -1
- data/ramaze.gemspec +1 -1
- data/spec/helper.rb +2 -1
- data/spec/ramaze/bin/start.rb +16 -20
- data/spec/ramaze/cache/localmemcache.rb +4 -7
- data/spec/ramaze/cache/memcache.rb +3 -1
- data/spec/ramaze/cache/redis.rb +62 -0
- data/spec/ramaze/helper/blue_form.rb +33 -4
- data/spec/ramaze/helper/layout.rb +40 -7
- data/spec/ramaze/helper/upload.rb +149 -0
- data/spec/ramaze/helper/uploads/text_1.txt +1 -0
- data/spec/ramaze/helper/uploads/text_2.txt +1 -0
- data/spec/ramaze/log/growl.rb +4 -6
- data/spec/ramaze/log/syslog.rb +6 -0
- data/spec/ramaze/view/lokar.rb +5 -0
- data/spec/ramaze/view/nagoro.rb +5 -0
- data/tasks/authors.rake +1 -1
- data/tasks/bacon.rake +14 -5
- data/tasks/changelog.rake +1 -1
- data/tasks/yard.rake +12 -4
- metadata +277 -239
- data/doc/LEGAL +0 -26
- data/examples/app/blog/README +0 -3
- data/examples/app/blog/controller/comment.rb +0 -45
- data/examples/app/blog/controller/entry.rb +0 -85
- data/examples/app/blog/controller/main.rb +0 -20
- data/examples/app/blog/controller/tag.rb +0 -9
- data/examples/app/blog/layout/default.nag +0 -31
- data/examples/app/blog/model/entry.rb +0 -89
- data/examples/app/blog/model/tag.rb +0 -36
- data/examples/app/blog/public/css/screen.css +0 -273
- data/examples/app/blog/spec/blog.rb +0 -87
- data/examples/app/blog/view/comment/form.nag +0 -10
- data/examples/app/blog/view/comment/show.nag +0 -16
- data/examples/app/blog/view/entry/edit.nag +0 -14
- data/examples/app/blog/view/entry/feed.atom.nag +0 -8
- data/examples/app/blog/view/entry/feed.rss.nag +0 -7
- data/examples/app/blog/view/entry/index.nag +0 -7
- data/examples/app/blog/view/entry/new.nag +0 -13
- data/examples/app/blog/view/entry/show.nag +0 -36
- data/examples/app/blog/view/feed.atom.nag +0 -18
- data/examples/app/blog/view/feed.rss.nag +0 -25
- data/examples/app/blog/view/index.nag +0 -6
- data/examples/app/blog/view/tag/index.nag +0 -5
- data/lib/proto/public/ramaze.png +0 -0
- data/lib/ramaze/rest.rb +0 -36
- data/spec/ramaze/rest.rb +0 -28
- data/tasks/rcov.rake +0 -22
@@ -0,0 +1,78 @@
|
|
1
|
+
# Models
|
2
|
+
|
3
|
+
Unlike other frameworks Ramaze does not ship with a database toolkit. One of the
|
4
|
+
ideas of Ramaze is that it allows you to choose your own set of tools, you're
|
5
|
+
not forced to use what we think is best. Ramaze allows you to use
|
6
|
+
[ActiveRecord][ar], [Sequel][sequel] or anything else. For the simplicity of
|
7
|
+
this user guide we'll use Sequel. In short, Sequel is a database toolkit that
|
8
|
+
allows you to write SQL statements using Ruby methods as well as providing an
|
9
|
+
ORM (Object Relationship Mapper).
|
10
|
+
|
11
|
+
Let's say we're creating a simple blog application. Each blog has posts,
|
12
|
+
comments, users and perhaps some categories. We're not going to create a model
|
13
|
+
for each of these entities in this guide but instead we'll focus on the Post
|
14
|
+
model. The most basic form of a model looks like the following:
|
15
|
+
|
16
|
+
class Post < Sequel::Model
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
From this point on we can load our model (given we have established a database
|
21
|
+
connection) and call methods from it. For example, if we want to retrieve the
|
22
|
+
post with ID #1 we'd do the following:
|
23
|
+
|
24
|
+
Post[1] # => SELECT * FROM posts WHERE id = 1
|
25
|
+
|
26
|
+
Performing a WHERE clause and retrieving a single record can be done by passing
|
27
|
+
a hash to the [] method:
|
28
|
+
|
29
|
+
Post[:title => 'Ramaze is Great'] # => SELECT * FROM posts WHERE title = 'Ramaze is Great'
|
30
|
+
|
31
|
+
## Controllers And Models
|
32
|
+
|
33
|
+
Of course using a model on its own isn't really going to work. Let's combine
|
34
|
+
our Post model mentioned earlier with a controller called "Posts".
|
35
|
+
|
36
|
+
require 'ramaze'
|
37
|
+
require 'model/post'
|
38
|
+
|
39
|
+
class Posts < Ramaze::Controller
|
40
|
+
map '/'
|
41
|
+
|
42
|
+
def index
|
43
|
+
@posts = Post.all
|
44
|
+
end
|
45
|
+
|
46
|
+
def edit(id)
|
47
|
+
# Arguments are passed as strings so it's a good idea to convert them
|
48
|
+
@post = Post[id.to_i]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
This is a somewhat more advanced example of how to use controllers and models.
|
53
|
+
However, it's nothing ground breaking and shouldn't be too hard to understand.
|
54
|
+
In the index() method we're simply retrieving all posts by calling Post#all and
|
55
|
+
storing them in an instance variable. In the edit() method we're retrieving the
|
56
|
+
post based on the given ID.
|
57
|
+
|
58
|
+
In the edit() method the "id" variable is also converted to an integer. The
|
59
|
+
reason for this is that Ramaze doesn't know what types the URI segments should
|
60
|
+
be and thus passes them as a string to the called method. While Sequel itself
|
61
|
+
won't have any trouble handling this it's a good practice to send the correct
|
62
|
+
types as other database toolkits might trigger errors when they receive a string
|
63
|
+
value while expecting an integer.
|
64
|
+
|
65
|
+
## Supported Toolkits
|
66
|
+
|
67
|
+
* [ActiveRecord][ar]
|
68
|
+
* [M4DBI][m4dbi]
|
69
|
+
* [Sequel][sequel]
|
70
|
+
* [DataMapper][datamapper]
|
71
|
+
|
72
|
+
Besides these listed toolkits Ramaze should work with any other toolkit, these
|
73
|
+
however are the ones that have been confirmed to work just fine with Ramaze.
|
74
|
+
|
75
|
+
[sequel]: http://sequel.rubyforge.org/
|
76
|
+
[ar]: http://ar.rubyonrails.org/
|
77
|
+
[m4dbi]: https://github.com/Pistos/m4dbi
|
78
|
+
[datamapper]: http://datamapper.org/
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Principles
|
2
|
+
|
3
|
+
There are some basic principles that Ramaze tries to follow:
|
4
|
+
|
5
|
+
* KISS (Keep It Super Simple)
|
6
|
+
|
7
|
+
Ramaze doesn't introduce any major change of paradigm for everyone familiar
|
8
|
+
with Ruby and the basics of Web-development.
|
9
|
+
|
10
|
+
* POLS (Principle Of Least Surprise)
|
11
|
+
|
12
|
+
Ramaze tries to be intuitive and easy to learn. Most functionality is built in
|
13
|
+
a way to help, not to obfuscate or confuse.
|
14
|
+
|
15
|
+
* Modular design
|
16
|
+
|
17
|
+
Use what you want and how you want it.Through Ruby Ramaze provides one of the
|
18
|
+
most powerful programming-languages available, giving you full control over
|
19
|
+
your system.
|
20
|
+
|
21
|
+
Even the most essential parts of Ramaze can easily be replaced and/or modified
|
22
|
+
without losing the advantage of the whole framework.
|
23
|
+
|
24
|
+
* Minimal dependencies
|
25
|
+
|
26
|
+
Nothing besides Ruby is required for the basic features.
|
27
|
+
Of course you can take advantage of several wonderful libraries, but Ramaze is
|
28
|
+
built in a way to be run on any basic setup.
|
29
|
+
|
30
|
+
* Documentation
|
31
|
+
|
32
|
+
Document everything, classes, modules, methods, configuration
|
33
|
+
and so on. Through 100% documentation Ramaze gives the developer easy and
|
34
|
+
solid understanding of the underlying concepts and functionality.
|
35
|
+
|
36
|
+
* Open development
|
37
|
+
|
38
|
+
Everyone is welcome to contribute to Ramaze in the easiest
|
39
|
+
way possible. The repository is open for patches passing the Test-suite.
|
40
|
+
|
41
|
+
* Examples
|
42
|
+
|
43
|
+
Everyone learns different, some only read the source, others browse
|
44
|
+
documentation, but everyone loves examples for a quick and painless start.
|
45
|
+
Ramaze addresses this need and offers a wide variety of examples of usage,
|
46
|
+
basic functionality, project-layout and more advanced applications.
|
47
|
+
|
48
|
+
* Fully BDD (Behaviour Driven Design)
|
49
|
+
|
50
|
+
Ramaze has a very complete set of so-called specifications built by RSpec.
|
51
|
+
These specs define the way Ramaze has to behave. The specs are checked every
|
52
|
+
time a new patch is pushed into the repository, deciding whether the changes
|
53
|
+
the patch applies are valid and don't break the framework.
|
@@ -0,0 +1,155 @@
|
|
1
|
+
## Ramaze Command
|
2
|
+
|
3
|
+
Ramaze ships with a relatively simple command, named "ramaze". This command can
|
4
|
+
be used to create new applications as well as starting them. To make reading
|
5
|
+
this guide easier we'll call this command "bin/ramaze" from now on.
|
6
|
+
|
7
|
+
<div class="note deprecated">
|
8
|
+
<p>
|
9
|
+
<strong>Warning</strong>: bin/ramaze is not a scaffolding application.
|
10
|
+
It can merely be used for some basic application management and creating
|
11
|
+
a basic Ramaze application.
|
12
|
+
</p>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
## Creating Applications
|
16
|
+
|
17
|
+
As mentioned earlier bin/ramaze can be used to create new applications. In order
|
18
|
+
to create a new application in the current directory all you have to do is
|
19
|
+
executing the following command:
|
20
|
+
|
21
|
+
$ ramaze create APPNAME
|
22
|
+
|
23
|
+
APPNAME is the name of your new application and will also be used as the
|
24
|
+
directory name. If the application was named "blog" there would now be a
|
25
|
+
directory called "blog" in the current one. This directory will contain all
|
26
|
+
basic files that can be used for a Ramaze powered application.
|
27
|
+
|
28
|
+
Each new application has the following structure:
|
29
|
+
|
30
|
+
.__ app.rb
|
31
|
+
|__ config.ru
|
32
|
+
|__ controller
|
33
|
+
| |__ init.rb
|
34
|
+
| |__ main.rb
|
35
|
+
|
|
36
|
+
|__ layout
|
37
|
+
| |__ default.xhtml
|
38
|
+
|
|
39
|
+
|__ model
|
40
|
+
| |__ init.rb
|
41
|
+
|
|
42
|
+
|__ public
|
43
|
+
| |
|
44
|
+
| |__ css
|
45
|
+
| | |__ screen.css
|
46
|
+
| |
|
47
|
+
| |__ dispatch.fcgi
|
48
|
+
| |__ favicon.ico
|
49
|
+
| |__ js
|
50
|
+
| | |__ jquery.js
|
51
|
+
| |
|
52
|
+
| |__ ramaze.png
|
53
|
+
|
|
54
|
+
|__ spec
|
55
|
+
| |__ main.rb
|
56
|
+
|
|
57
|
+
|__ start.rb
|
58
|
+
|__ view
|
59
|
+
|__ index.xhtml
|
60
|
+
|
61
|
+
## Application Prototypes
|
62
|
+
|
63
|
+
Due to Ramaze's nature it's very easy to create your own application prototype
|
64
|
+
if you dislike the default one. For example, I've made some small modifications
|
65
|
+
to the default prototype so that it looks like the followng:
|
66
|
+
|
67
|
+
.__ app.rb
|
68
|
+
|__ config
|
69
|
+
| |__ config.rb
|
70
|
+
| |__ database.rb
|
71
|
+
| |__ middlewares.rb
|
72
|
+
| |__ requires.rb
|
73
|
+
|
|
74
|
+
|__ config.ru
|
75
|
+
|__ controller
|
76
|
+
|__ layout
|
77
|
+
| |__ default.xhtml
|
78
|
+
|
|
79
|
+
|__ log
|
80
|
+
|__ public
|
81
|
+
|__ spec
|
82
|
+
|__ start.rb
|
83
|
+
|__ view
|
84
|
+
|
85
|
+
This prototype is basically a minimal version of the default one but with a
|
86
|
+
special directory for all configuration files. In order to use this prototype I
|
87
|
+
had to make some small changes to app.rb, the look like the following:
|
88
|
+
|
89
|
+
require 'ramaze'
|
90
|
+
|
91
|
+
# Load the file that in turn will load all gems, keeps this file clean
|
92
|
+
require __DIR__('config/requires')
|
93
|
+
|
94
|
+
# Configure our application
|
95
|
+
require __DIR__('config/config')
|
96
|
+
|
97
|
+
# Load our database settings
|
98
|
+
require __DIR__('config/database')
|
99
|
+
|
100
|
+
# Load all Rack middlewares
|
101
|
+
require __DIR__('config/middlewares')
|
102
|
+
|
103
|
+
# Load all controllers
|
104
|
+
Dir.glob(__DIR__('controller') + '/**/*.rb').each do |f|
|
105
|
+
require f
|
106
|
+
end
|
107
|
+
|
108
|
+
This is only a basic example of the flexibility of Ramaze, I highly recommend
|
109
|
+
you playing around with your own prototypes as it's a great way to learn the
|
110
|
+
basics of Ramaze and to really understand how flexible Ramaze is.
|
111
|
+
|
112
|
+
|
113
|
+
<div class="note todo">
|
114
|
+
<p>
|
115
|
+
<strong>Note</strong>: This prototype does not come with Ramaze, it's
|
116
|
+
just an example of what you could make yourself.
|
117
|
+
</p>
|
118
|
+
</div>
|
119
|
+
|
120
|
+
## Running Applications
|
121
|
+
|
122
|
+
When you've created an application there are three ways of running it. You can
|
123
|
+
either use your server's command such as `thin` or `unicorn` but you can also
|
124
|
+
use bin/ramaze. When starting your application with bin/ramaze it will use the
|
125
|
+
appropriate server according to the settings set in "config.ru" or "star.rb".
|
126
|
+
An example of using this command is as simple as the following:
|
127
|
+
|
128
|
+
$ ramaze start
|
129
|
+
|
130
|
+
On top of these two ways you can also start your Ramaze application by calling
|
131
|
+
the "start.rb" file using the ruby binary:
|
132
|
+
|
133
|
+
$ ruby start.rb
|
134
|
+
|
135
|
+
If you want to stop the running application you can simply close it by using the
|
136
|
+
key combination Ctrl+C.
|
137
|
+
|
138
|
+
<div class="note todo">
|
139
|
+
<p>
|
140
|
+
<strong>Note</strong>: There are many different ways to start your
|
141
|
+
application depending on the server you're using. Fore more information
|
142
|
+
it's best to look at the documentation of your favorite webserver.
|
143
|
+
</p>
|
144
|
+
</div>
|
145
|
+
|
146
|
+
## Ramaze Console
|
147
|
+
|
148
|
+
The bin/ramaze command allows you to run an interactive Ramaze session just
|
149
|
+
like IRB. In fact, Ramaze actually uses IRB. To invoke the Ramaze console simple
|
150
|
+
execute `ramaze console` and you're good to go. This console gives you full
|
151
|
+
access to your application and thus can be very useful for debugging purposes.
|
152
|
+
|
153
|
+
An example of a Ramaze console session can be seen in the image below.
|
154
|
+
|
155
|
+
![Ramaze Console](_static/ramaze_console.png)
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Routes
|
2
|
+
|
3
|
+
While in many cases the default route system that comes with Ramaze is good
|
4
|
+
enough there will be times when you want pretty URLs (or just different ones).
|
5
|
+
Ramaze allows you to do all this using the class Ramaze::Route (it's an alias
|
6
|
+
of Innate::Route). This class allows you to create routes using simple strings,
|
7
|
+
regular expressions and lambdas. Let's say we have the following URLs:
|
8
|
+
|
9
|
+
* /users/index
|
10
|
+
* /users/profile/yorickpeterse
|
11
|
+
* /users/edit/yorickpeterse
|
12
|
+
|
13
|
+
Our goal is to rewrite these URLs to the following:
|
14
|
+
|
15
|
+
* /users/list
|
16
|
+
* /users/yorickpeterse
|
17
|
+
* /users/yorickpeterse/edit
|
18
|
+
|
19
|
+
In order to fully explain the routing system will use the three available
|
20
|
+
possibilities: strings, regular expressions and lambdas.
|
21
|
+
|
22
|
+
## String Routes
|
23
|
+
|
24
|
+
Routes that use a string are the most basic form of routing. You simply specify
|
25
|
+
a request URI and the action to call instead of the normal one:
|
26
|
+
|
27
|
+
Ramaze::Route['/foobar'] = '/baz/bar'
|
28
|
+
|
29
|
+
This route tells Ramaze that every request to /foobar should be sent to /baz/bar
|
30
|
+
instead. While string based routes are the easiest to use they're also the most
|
31
|
+
limited one, they can merely be used to redirect A to B. If we look at our list
|
32
|
+
of URLs the only one we can rewrite using this form of routing is the first one:
|
33
|
+
|
34
|
+
Ramaze::Route['/users/list'] = '/users/index'
|
35
|
+
|
36
|
+
This forwards all requests that were sent to /users/list to /users/index.
|
37
|
+
|
38
|
+
## Regular Expression Routes
|
39
|
+
|
40
|
+
Using regular expressions in routes makes it possible to have more dynamic
|
41
|
+
routes. Routes that use regular expressions look like the following:
|
42
|
+
|
43
|
+
Ramaze::Route[/user-([0-9]+)/] = '/users/%d'
|
44
|
+
|
45
|
+
This route forwards requests such as /user-10 and /user-1234 to /users/10 and
|
46
|
+
/users/1234. As you can see there's a "%d" in the value which is replaced with
|
47
|
+
the value of the group ([0-9]+). When using regular expressions for your routes
|
48
|
+
you can use sprintf characters in the value (%s, %d, etc).
|
49
|
+
|
50
|
+
So what about our list of URLs? Let's rewrite the second URL:
|
51
|
+
|
52
|
+
Ramaze::Route['/users/([\w]+)'] = '/users/profile/%s'
|
53
|
+
|
54
|
+
And there we go, all calls to /users/NAME (where NAME is the name of a user)
|
55
|
+
will be routed to /users/profile/NAME.
|
56
|
+
|
57
|
+
## Lambda Routes
|
58
|
+
|
59
|
+
The last method of routing calls can be done using lambdas. The key of the []=
|
60
|
+
method will be the name of a route (can be anything really) and the value a
|
61
|
+
lambda that takes two parameters, the request path and a variable containing the
|
62
|
+
request data:
|
63
|
+
|
64
|
+
Ramaze::Route['my funky lambda route'] = lambda do |path, request|
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
In this lambda you're free to do whatever you want as long as you either return
|
69
|
+
a new path or nil (anything else will result in an error). Say we wanted to
|
70
|
+
route our last URL we'd do it as following:
|
71
|
+
|
72
|
+
Ramaze::Route['edit users'] = lambda do |path, request|
|
73
|
+
if path =~ /users\/edit\/([\w]+)/
|
74
|
+
return "/users/#{$1}/edit"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
This route redirects everything from /users/NAME/edit to /users/edit/NAME.
|
79
|
+
Everything else is unaffected by this route since it only returns a value when
|
80
|
+
the path matches the given regular expression. Note that lambdas can actually
|
81
|
+
contain a "return" statement so the code above is perfectly valid.
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# Sessions
|
2
|
+
|
3
|
+
The term sessions is used for data associated to a specific client. The easiest
|
4
|
+
example of a session is a simple cookie containing some very basic data such as
|
5
|
+
a user's name.
|
6
|
+
|
7
|
+
## Initializing Sessions
|
8
|
+
|
9
|
+
Ramaze lazy-loads the session system that it's ship with. This means that if you
|
10
|
+
never use any session related data a session will not be created. As soon as you
|
11
|
+
call the main object for working with sessions (simply called "session") or add
|
12
|
+
data to the flash (more on that later) Ramaze will load the session adapter
|
13
|
+
automatically. This prevents you from having to manually write code that invokes
|
14
|
+
a session for all your projects.
|
15
|
+
|
16
|
+
So how do we actually start a session? As mentioned earlier this can be done in
|
17
|
+
two different ways, calling session or flash. If you want to store data in the
|
18
|
+
session until the client's session is destroyed (or the data is removed) it's
|
19
|
+
best to use session, if you only want to store something until the client is
|
20
|
+
redirected to another page (or just visits a page himself) you should use flash.
|
21
|
+
|
22
|
+
## The Session Object
|
23
|
+
|
24
|
+
As mentioned earlier session is used for data that should be stored until the
|
25
|
+
client's session is destroyed or the data is removed. A good example of this
|
26
|
+
sort of data is a boolean that indicates if the user is logged in or not, you
|
27
|
+
don't want the user to re-authenticate over and over again thus you store the
|
28
|
+
data using the session object. Storing data using this method is incredible
|
29
|
+
simple and works a bit like you're storing data in a hash:
|
30
|
+
|
31
|
+
session[:logged_in] = true
|
32
|
+
|
33
|
+
In the above example we stored a boolean with a value of "true" in the current
|
34
|
+
client's session under the name ":logged_in". If we want to retrieve this data
|
35
|
+
somewhere else in the application all we'd have to do is the following:
|
36
|
+
|
37
|
+
session[:logged_in] # => true
|
38
|
+
|
39
|
+
A better example would be a simple counter that tracks the amount of times a
|
40
|
+
user has visited your application:
|
41
|
+
|
42
|
+
class Counter < Ramaze::Controller
|
43
|
+
map '/'
|
44
|
+
|
45
|
+
def index
|
46
|
+
# If no data was found for the given key session returns nil
|
47
|
+
if !session[:visits].nil?
|
48
|
+
session[:visits] = 0
|
49
|
+
else
|
50
|
+
session[:visits] += 1
|
51
|
+
end
|
52
|
+
|
53
|
+
"You have visitied this page #{session[:visits]} times."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
In this relatively basic controller a user's amount of visits to the index()
|
58
|
+
method will be stored in the session and displayed afterwards. Now it's time
|
59
|
+
for the true magic. The session object is an instance of Innate::Session and
|
60
|
+
has a few extra methods besides [] and []=. These methods are delete(), clear(),
|
61
|
+
flush(), resid!() and sid(). We're not going to cover all methods but we will
|
62
|
+
look at the delete() and resid() methods.
|
63
|
+
|
64
|
+
## Session.delete
|
65
|
+
|
66
|
+
The method Session.delete can be used to remove a chunk of data from the
|
67
|
+
client's session. In order to delete our amount of visits all we'd have to do
|
68
|
+
is the following:
|
69
|
+
|
70
|
+
session.delete(:visits)
|
71
|
+
|
72
|
+
From this point on the "visits" key is set to nil until the user visits the
|
73
|
+
index page again.
|
74
|
+
|
75
|
+
## Session.resid!
|
76
|
+
|
77
|
+
Session.resid! can be used to regenerate the client's session ID without
|
78
|
+
destroying the session data. This method is extremely useful for authentication
|
79
|
+
systems as it can be used to prevent session fixation attacks by generating a
|
80
|
+
new session ID every N minutes or whenever a certain action is triggered (e.g.
|
81
|
+
the user logs in). Using this method is very simple and only requires the
|
82
|
+
following to be done:
|
83
|
+
|
84
|
+
session.resid!
|
85
|
+
|
86
|
+
## The Flash
|
87
|
+
|
88
|
+
First of all, this has nothing to do with Adobe's Flash or
|
89
|
+
[The Flash][the flash]. Flashdata is a form of session data that is removed as
|
90
|
+
soon as the client requests a new resource. This means that if something is
|
91
|
+
stored in the flash and the user is redirected the data will be automatically
|
92
|
+
removed. One of the things the flash data can be used for is storing
|
93
|
+
notifications that are displayed if a blog post has been saved successfully.
|
94
|
+
Storing data in the flash works similar to storing data in the session and can
|
95
|
+
be done by calling the flash object:
|
96
|
+
|
97
|
+
flash[:message] = "Hello, Ramaze!"
|
98
|
+
|
99
|
+
If we want to remove something from the flash we can call Flash.delete similar
|
100
|
+
to Session.delete:
|
101
|
+
|
102
|
+
flash.delete(:message)
|
103
|
+
|
104
|
+
Note that due to the nature of the flash data you'd have to do this before the
|
105
|
+
client requests a new resource as the data will be deleted automatically at
|
106
|
+
that point.
|
107
|
+
|
108
|
+
To integrate flash with your application views include {Ramaze::Helper::Flash}
|
109
|
+
in your controller and call function ``flashbox`` inside the view.
|
110
|
+
|
111
|
+
To change the markup of the flashbox generated HTML, use the following trait
|
112
|
+
inside your controller:
|
113
|
+
|
114
|
+
trait :flashbox => "<div class=\"alert-message %key\"><p>%value</p></div>"
|
115
|
+
|
116
|
+
Below is an example of how the flash data can be used in a typical Ramaze
|
117
|
+
application:
|
118
|
+
|
119
|
+
class Blogs < Ramaze::Controller
|
120
|
+
map '/'
|
121
|
+
helper :flash
|
122
|
+
|
123
|
+
def index
|
124
|
+
flash[:message]
|
125
|
+
end
|
126
|
+
|
127
|
+
def set_message
|
128
|
+
flash[:message] = "Hello, Ramaze!"
|
129
|
+
redirect(Blogs.r(:index))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
If a client were to visit the index method for the first time nothing would be
|
134
|
+
displayed because the flash data isn't there yet. As soon as the client visits
|
135
|
+
/set_message he would be redirected back to the index method and the message
|
136
|
+
"Hello, Ramaze!" would be displayed. Refreshing the page would clear the flash
|
137
|
+
data and the message would no longer be displayed until the client visits
|
138
|
+
/set\_message again.
|
139
|
+
|
140
|
+
[the flash]: http://en.wikipedia.org/wiki/The_Flash_(comic_book)
|