forked from otobrglez/webruby
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter9.html
419 lines (340 loc) · 21.4 KB
/
chapter9.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
<!doctype html>
<html>
<head>
<title>Programming for the Web with Ruby</title>
<meta charset="utf-8">
<meta name="author" content="Satish Talim" >
<meta name="keywords" content="programming, Ruby, Rack, Sinatra" >
<meta name="description" content="A Ruby programming tutorial on topics that hopefully will help those that have some knowledge of Ruby programming to get started with web programming." >
<link rel="stylesheet" href="stylesheets/intruby.css">
</head>
<body>
<div>
<p>
<strong>
<a href="chapter8.html"><Chapter 8 | </a>
<a href="toc.html">TOC | </a>
<a href="chapter9.html">Chapter 9></a>
</strong>
</p>
<h1 class="title">Day 10</h1>
<h2>Sinatra with MongoDB</h2>
<p>Some concepts that are core to web development (and which we have covered earlier - the HTTP specification, HTML, CSS, etc.) are critical to understanding how to be productive with Sinatra; I recommend that you have at least a passing familiarity with these concepts to make the Sinatra experience a little easier.</p>
<h3>What's Sinatra?</h3>
<p><a href="http://www.sinatrarb.com/">Sinatra</a> is a Ruby-based web application library. Sinatra is not a <a href="http://en.wikipedia.org/wiki/Web_application_framework">web application framework</a> and unlike Rails, there's no enforcement of concepts like <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a> or <a href="http://en.wikipedia.org/wiki/Representational_state_transfer">REST</a> in Sinatra.</p>
<p>It doesn't assume much about your application, apart from that:</p>
<ul>
<li>it will be written in the Ruby programming language</li>
<li>it will have URLs</li>
</ul>
<p>Sinatra serves as a lightweight wrapper around Rack middleware, with syntax that maps closely to functions exposed by HTTP verbs.</p>
<p>Sinatra is used to build websites, web services and web applications in Ruby.</p>
<h3>Create a folder on your hard disk</h3>
<p>Create a folder <code>sinatraapp</code>. This is where we will store our Sinatra app.</p>
<h3>Install Sinatra</h3>
<p>The simplest way to obtain Sinatra is through Rubygems.</p>
<p>In the folder <code>sinatraapp</code>, open a command window and type:</p>
<pre>$ gem install sinatra
</pre>
<h3>Which web server?</h3>
<p>The <code>Thin</code> web server is recommended. <code>Thin</code> uses code from <code>Mongrel</code> web server to parse HTTP requests but improves network I/O performance via EventMachine, which manages evented network communication. To install <code>Thin</code>, in the already open command window, type:</p>
<pre>$ gem install thin
</pre>
<p>If <code>Thin</code> is not installed, Sinatra will first try to run with <code>Mongrel</code>, choosing <code>WEBrick</code> if <code>Mongrel</code> isn't available either.</p>
<h3>Our trivial Sinatra application</h3>
<p>In the folder <code>sinatraapp</code> write a program, call it <code>myapp1.rb</code>, as follows:</p>
<pre>require 'sinatra'
get '/' do
"Hello Ruby participants from across the globe!"
end
</pre>
<p>In the open command window, type:</p>
<pre>$ ruby myapp1.rb
[2011-11-25 10:15:18] INFO WEBrick 1.3.1
[2011-11-25 10:15:18] INFO ruby 1.9.3 (2011-10-30) [i386-mingw32]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2011-11-25 10:15:18] INFO WEBrick::HTTPServer#start: pid=7644 port=4567
</pre>
<p>As you can see above, you will be notified that Sinatra has taken the stage.</p>
<p>Sinatra uses port 4567 by default. Open a web browser and navigate to <a href="http://localhost:4567/">http://localhost:4567/</a>. Your Sinatra application should respond with our greeting namely:</p>
<pre>Hello Ruby participants from across the globe!
</pre>
<p>Let's look at what the following does:</p>
<pre>get '/' do
</pre>
<p>To declare a route in Sinatra, you must supply the HTTP verb to respond to, the specific URL, and then optionally define the behavior desired for the route.</p>
<p>The form <code>verb 'route' do</code> in our code instructs the application to respond to HTTP GET requests to the path '/'; our response is composed by the block we provided for behavior. This composite endpoint is referred to as a <em>route</em>.</p>
<p>Now let's use <code>cURL</code> to see what happens when this route is executed. Open a new command window, type:</p>
<pre>$ curl http://localhost:4567
Hello Ruby participants from across the globe!
</pre>
<p>Let us use the <code>-v</code> switch with <code>cURL</code>, type:</p>
<pre>$ curl -v http://localhost:4567
* About to connect() to localhost port 4567 (#0)
* Trying 127.0.0.1... connected
> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (i386-pc-win32) libcurl/7.22.0 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:4567
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Frame-Options: sameorigin
< X-Xss-Protection: 1; mode=block
< Content-Type: text/html;charset=utf-8
< Content-Length: 26
< Server: WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
< Date: Fri, 25 Nov 2011 08:51:01 GMT
< Connection: Keep-Alive
<
Hello Ruby participants from across the globe!* Connection #0 to host localhost left intact
* Closing connection #0
</pre>
<p>Close this command window.</p>
<p><b>Note</b>: The switch <code>-v</code> or <code>--verbose</code> makes the fetching more verbose/talkative. Mostly useful for debugging. A line starting with '>' means "header data" sent by <code>cURL</code>, '<' means "header data" received by <code>cURL</code> that is hidden in normal cases, and a line starting with '*' means additional info provided by <code>cURL</code>.</p>
<p>Remember that routes in your application are matched in top-down order; the first route that matches the incoming request is the one that gets used. Routes in Sinatra can also accept parameters that are exposed in code via the <code>params</code> array. Example:</p>
<pre>require 'sinatra'
post '/login' do
username = params[:username]
password = params[:password]
end
</pre>
<p>In the open command window, press Ctrl C to stop Sinatra. Close the command window.</p>
<h3>ERB and View</h3>
<h4>ERB</h4>
<p>ERB is written in pure Ruby and is included with the standard Sinatra distribution. ERB allows you to embed Ruby statements in an HTML page.</p>
<p>The important thing to know about an <code>.erb</code> file is that <code><%= ruby_code %></code> evaluates the ruby code and outputs the result, and <code><% ruby_code %></code> evaluates the code, but doesn't output anything.</p>
<h4>View</h4>
<p><em>A view is responsible for generating a user interface, normally based on data</em>. For example, an online store will have a list of products to be displayed on a catalogue screen. The view accesses the data and formats it for the end user.</p>
<p><em>All file-based views are looked up in</em>:</p>
<pre>root
| - views/
</pre>
<p><em>Sinatra has built-in support for ERB, Haml, Sass and Builder (we do not use the latter three here) templating languages</em>. Let's use ERB for our example. In the folder <code>sinatraapp</code> write a program, call it <code>myapp2.rb</code>, as follows:</p></p>
<pre>require 'sinatra'
get '/' do
erb :index
end
</pre>
<p><em>This tells Sinatra that when a GET request for '/' comes in, that we should use the ERB helper to render the <code>index.erb</code> template, which is stored in the <code>views/</code> subdirectory by convention and marked up with embedded Ruby (ERB).</em></p>
<p>Create a <code>views</code> sub folder under the existing <code>sinatraapp</code> folder and create the file <code>index.erb</code> in it, which contains the following:</p>
<pre><h1>Introduction to Sinatra Course by RubyLearning</h1>
<p>The first and only free Sinatra course on the planet!!</p>
<p>The current time is: <%= Time.now %></p>
</pre>
<p>Open a new command window and type:</p>
<pre>$ ruby myapp2.rb
[2011-12-22 15:04:10] INFO WEBrick 1.3.1
[2011-12-22 15:04:10] INFO ruby 1.9.3 (2011-10-30) [i386-mingw32]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2011-12-22 15:04:10] INFO WEBrick::HTTPServer#start: pid=4404 port=4567
</pre>
<p>Open a web browser and navigate to <a href="http://localhost:4567/">http://localhost:4567/</a>. Your Sinatra application should respond with:</p>
<pre>Introduction to Sinatra Course by RubyLearning
The first and only free Sinatra course on the planet!!
The current time is: 2011-12-22 15:05:48 +0530
</pre>
<p>In the open command window, press Ctrl C to stop Sinatra. Close the command window.</p>
<h4>Handlers and Form parameters</h4>
<p>Handler is the generic term that Sinatra uses for the "controllers". <em>A handler is the initial point of entry for new HTTP requests into your application</em>.</p>
<p>In handlers you can reach submitted form parameters directly via the <code>params</code> hash, namely:</p>
<pre>params[:post]
</pre>
<p>Also, the support of nested parameters is built-in Sinatra. For example:</p>
<pre><form>
<input ... name="post[title]" /><br />
<input ... name="post[body]" /><br />
<input ... name="post[author]" />
</form>
</p>
</pre>
<p>The parameters in this case become as a hash:</p>
<pre>{:post=>{ :title=>"", :body=>"", :author=>"" }}
</pre>
<p>Therefore in handlers you can use nested parameters like a regular hash:</p>
<pre>params[:post][:title]
</pre>
<p>An example will illustrate what we have learned so far about form parameters:</p>
<p>In the folder <code>sinatraapp</code> write a program, call it <code>myapp3.rb</code>, as follows:</p>
<pre># myapp3.rb
require 'sinatra'
get '/' do
erb :home
end
post '/display' do
erb :show
end
</pre>
<p>Create the files <code>home.erb</code> and <code>show.erb</code> in the <code>views</code> folder, as follows:</p>
<p><b>home.erb</b></p>
<pre><h1>Form Parameters</h1>
<p>The example will display submitted form parameters directly via the params hash</p>
<form action="/display" method="post" accept-charset="utf-8">
<input type="text" name="post[fname]" value="Type your first name..." id="fname" /><br />
<input type="text" name="post[lname]" value="Type your last name...." id="lname" /><br />
<input type="submit" value=".. and display it!">
</form>
</pre>
<p><b>show.erb</b></p>
<pre><h1>Form Parameters Display</h1>
<p>You had entered:</p>
<p>First Name - <%= params[:post][:fname] %></p>
<p>Last Name - <%= params[:post][:lname] %></p>
<p>Click <a href="/">here</a> to try a new name.</p>
</pre>
<p>Open a new command window and type:</p>
<pre>$ ruby myapp3.rb
[2011-12-23 08:28:25] INFO WEBrick 1.3.1
[2011-12-23 08:28:25] INFO ruby 1.9.3 (2011-10-30) [i386-mingw32]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2011-12-23 08:28:25] INFO WEBrick::HTTPServer#start: pid=7924 port=4567
</pre>
<p>Open a web browser and navigate to <a href="http://localhost:4567/">http://localhost:4567/</a>. Your Sinatra application should respond with:</p>
</div>
<div style="width:image 560 px; font-size:80%; text-align:center;"><img src="images/form.jpg" alt="Form" style="padding-bottom:0.5em;" /><br />Sinatra Form</div>
<div>
<p>In the open command window, press Ctrl C to stop Sinatra. Close the command window.</p>
<h2>Exercise: A simple text reversing service</h2>
<p>Build a simple text reversing Sinatra app that accepts a text string from the user and displays to the user the text string reversed. Store your code in a GitHub repo and post your repo URL in the technical forum.</p>
<h2>Deploy a Sinatra app to Heroku</h2>
<p>In order for Heroku to know what to do with your Sinatra app, create a <code>config.ru</code> in the root-directory i.e. folder <code>sinatraapp</code>. The contents are:</p>
<pre>require './myapp3'
run Sinatra::Application
</pre>
<p>The key line is <code>require 'myapp3'</code> (we are going to use the program <code>myapp3.rb</code> written above). Be sure to change that to whatever your application's name is. This line helps to load rubygems, Sinatra, rack and everything that we need. Heroku sets <code>RACK_ENV</code> to production for you. Finally we tell rack to run our Sinatra application with the line <code>run Sinatra::Application</code>. This will run "myapp3" in our case.</p>
<p>Next, we will install the required gems via bundler. Open a Bash shell for folder <code>sinatraapp</code> and type:</p>
<pre>$ bundle init
Writing new Gemfile to c:/sinatraapp/Gemfile
</pre>
<p>Edit the created Gemfile with your preferred text editor to let it look like this:</p>
<pre>source "http://rubygems.org"
gem 'sinatra'
</pre>
<p>Now we need to tell Bundler to check if we're missing the gems our application depends on, if so, tell it to install them. In your open Bash shell type:</p>
<pre>$ bundle check
The following gems are missing ...
</pre>
<p>Finally in the open Bash shell, type:</p>
<pre>$ bundle install
</pre>
<p>This will ensure all gems specified on Gemfile, together with their dependencies, are available for your application. Running "bundle install" will also generate a "Gemfile.lock" file. The Gemfile.lock ensures that your deployed versions of gems on Heroku match the version installed locally on your development machine.</p>
<p>Set up your local app to use Git. I have the <code>myapp3.rb</code> and <code>config.ru</code> files already in <code>sinatraapp</code>. Open a command window in folder <code>sinatraapp</code> and type the following:</p>
<pre>$ git init
$ git add .
$ git commit -m "myapp3 first commit"
</pre>
<p><b>Note</b>: The location of the <code>config.ru</code> file is in the folder <code>sinatraapp</code>.</p>
<p>Next we create the app on heroku. In the already open Bash shell, type:</p>
<pre>$ heroku create
Creating afternoon-winter-7405... done, stack is bamboo-mri-1.9.2
http://afternoon-winter-7405.heroku.com/ | [email protected]:afternoon-winter-7405.
git
</pre>
<p>The final line of output from the create command <em>will be different for each one of you</em> and is something like this:</p>
<pre>http://afternoon-winter-7405.heroku.com/ | [email protected]:afternoon-winter-7405.git
</pre>
<p>The app has been created and two URLs are provided. One is for the web face of your new app i.e. <a href="http://afternoon-winter-7405.heroku.com/">http://afternoon-winter-7405.heroku.com/</a>. The other one is for the Git repository that you will push your code to. Normally you would need to add this as a git remote; the "heroku create" command has done this for you automatically.</p>
<p>Let us now deploy our code:</p>
<pre>$ git push heroku master
</pre>
<p><b>Note</b>: At this stage you can rename your app by:</p>
<pre>$ heroku rename app_newname
</pre>
<p>Congrats, you have successfully deployed your first Sinatra app. For other deployment options, refer the URL - <a href="http://sinatra-book.gittr.com/#deployment">http://sinatra-book.gittr.com/#deployment</a>.</p>
<h2>Exercise: Deploy the simple text reversing service app to Heroku</h2>
<p>Deploy to Heroku the simple text reversing Sinatra app that you just built. Post the URL in the technical forum.</p>
<h2>Sinatra and Rack Middleware</h2>
<p>Sinatra rides on Rack, a minimal standard interface for Ruby web frameworks. As seen earlier, one of Rack's most interesting capabilities for application developers is support for "middleware" - components that sit between the server and your application monitoring and/or manipulating the HTTP request/response to provide various types of common functionality.</p>
<p>Sinatra makes building Rack middleware easier by using the top-level <code>use</code> method. Let's use our middleware program namely <code>my_middleware.rb</code> which is in the folder <code>my_ruby_programs</code>. In this folder write a program, call it <code>my_sinatra.rb</code>, as follows:
<pre>require 'sinatra'
require './my_middleware'
use MyMiddleware::Hello
get '/' do
"Hello Ruby participants from across the globe!"
end
</pre>
<p>Open a command window and type:</p>
<pre>$ ruby my_sinatra.rb
[2012-02-12 08:22:09] INFO WEBrick 1.3.1
[2012-02-12 08:22:09] INFO ruby 1.9.3 (2011-10-30) [i386-mingw32]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2012-02-12 08:22:09] INFO WEBrick::HTTPServer#start: pid=4288 port=4567
</pre>
<p>Open a web browser and navigate to <a href="http://localhost:4567/">http://localhost:4567/hello</a>. Your Sinatra application should respond with our greeting namely:</p>
<pre>Hello from the middleware!
</pre>
<p>In the open command window, press Ctrl C to stop Sinatra. Close the command window.</p>
<h2>Sinatra and Rack HTTP Basic Authentication</h2>
<p>You can easily protect your Sinatra application using HTTP Basic Authentication with the help of Rack middlewares. In the folder <code>my_ruby_programs</code> type the program <code>my_sinatra2.rb</code:</p>
<pre>require 'sinatra'
use Rack::Auth::Basic, "Restricted Area" do |user, password|
user == 'super' && password == 'secretsauce'
end
get '/' do
"This is a secret page"
end
get '/files' do
"Here are the secret files"
end
</pre>
<p>Open a command window and type:</p>
<pre>$ ruby my_sinatra2.rb
[2012-02-12 08:22:09] INFO WEBrick 1.3.1
[2012-02-12 08:22:09] INFO ruby 1.9.3 (2011-10-30) [i386-mingw32]
== Sinatra/1.3.1 has taken the stage on 4567 for development with backup from WEBrick
[2012-02-12 08:22:09] INFO WEBrick::HTTPServer#start: pid=4288 port=4567
</pre>
<p>Open a web browser and navigate to <a href="http://localhost:4567">http://localhost:4567</a>. Your Sinatra application should respond by asking you for the User Name and Password. Enter "super" and "secretsauce" respectively and the browser page would display:</p>
<pre>This is a secret page
</pre>
<p>If you type the url: <a href="http://localhost:9292/files">http://localhost:9292/files</a> in your browser window you should see something like this:</p>
<pre>Here are the secret files
</pre>
<p>In the open command window, press Ctrl C to stop Sinatra. Close the command window.</p>
<h2>Introduction to Sinatra eBook (Updated 15th Sept. 2011)</h2>
<p>We have had a very quick look at Sinatra. For a more detailed look, you could consider buying the <a href="http://rubylearning.com/blog/introduction-to-sinatra-ebook/">Introduction to Sinatra eBook</a>, an easy-to-follow guide to everything on Sinatra.</p>
<p>It is priced at a reasonable <b>US$ 14.95</b>. The money collected helps me maintain the site and provide quality content to you all.</p>
<p>Purchase of this eBook is <b>not mandatory</b> for this course.</p>
<p>WIP...</p>
<!--
http://ruby.bastardsbook.com/chapters/web-scraping/
http://ruby.bastardsbook.com/chapters/html-parsing/
http://ruby.bastardsbook.com/chapters/methods-and-gems/
-->
<h2>References</h2>
<ul>
<li><a href="http://rubylearning.com/blog/using-git-github-ebook/">http://rubylearning.com/blog/using-git-github-ebook/</a></li>
<li><a href="http://progit.org/book/">Pro Git</a></li>
<li><a href="http://learningwebdesign.com/">http://learningwebdesign.com/</a></li>
<li><a href="http://www.html-5-tutorial.com/">http://www.html-5-tutorial.com/</a></li>
<li><a href="http://www.w3schools.com/html/html_primary.asp">http://www.w3schools.com/html/html_primary.asp</a></li>
<li><a href="http://www.cssbasics.com/">http://www.cssbasics.com/</a></li>
<li><a href="http://www.w3schools.com/js/">http://www.w3schools.com/js/</a></li>
<li><a href="http://ruby.bastardsbook.com/chapters/html-parsing/">Parsing HTML with Nokogiri</a></li>
<li><a href="http://blog.segment7.net/2010/11/15/how-to-name-gems">http://blog.segment7.net/2010/11/15/how-to-name-gems</a></li>
<li><a href="http://rubylearning.com/blog/2010/10/06/gem-sawyer-modern-day-ruby-warrior/">http://rubylearning.com/blog/2010/10/06/gem-sawyer-modern-day-ruby-warrior/</a></li>
<li><a href="http://guides.rubygems.org/make-your-own-gem/">http://guides.rubygems.org/make-your-own-gem/</a></li>
<li><a href="http://coderack.org/">http://coderack.org/</a></li>
<li><a href="http://m.onkey.org/ruby-on-rack-2-the-builder">http://m.onkey.org/ruby-on-rack-2-the-builder</a></li>
<li><a href="http://rubysource.com/php-vs-ruby-whats-the-point/">http://rubysource.com/php-vs-ruby-whats-the-point/</a></li>
<li><a href="http://rubysource.com/rack-for-middlewares/">http://rubysource.com/rack-for-middlewares/</a></li>
<li><a href="http://devcenter.heroku.com/articles/static-sites-on-heroku">http://devcenter.heroku.com/articles/static-sites-on-heroku</a></li>
<li><a href="http://www.w3schools.com/json/default.asp">http://www.w3schools.com/json/default.asp</a></li>
<li><a href="https://github.com/karlseguin/the-little-mongodb-book">https://github.com/karlseguin/the-little-mongodb-book</a></li>
<li><a href="http://rubylearning.com/blog/2010/12/21/being-awesome-with-the-mongodb-ruby-driver/">http://rubylearning.com/blog/2010/12/21/being-awesome-with-the-mongodb-ruby-driver/</a></li>
<li><a href="http://api.mongodb.org/ruby/current/file.TUTORIAL.html">http://api.mongodb.org/ruby/current/file.TUTORIAL.html</a></li>
<li><a href="http://shop.oreilly.com/product/0636920019664.do">http://shop.oreilly.com/product/0636920019664.do</a></li>
<li><a href="http://sinatra.rubylearning.org/">Sinatra and only Sinatra!</a></li>
</ul>
<p>
<strong>
<a href="chapter8.html"><Chapter 8 | </a>
<a href="toc.html">TOC | </a>
<a href="chapter9.html">Chapter 9></a>
</strong>
</p>
<div id="footer">
<p>© 2006-2012 <strong>RubyLearning.org - Programming for the Web with Ruby</strong> Page Updated: 23rd Jan. 2012</p>
</div>
</div>
</body>
</html>