Chap. 15 - kuroski.net

Download Report

Transcript Chap. 15 - kuroski.net

15.1 Overview of Rails
- Rails is a development framework for Web-based
applications
- Rails is written in Ruby and uses Ruby for its
applications - Ruby on Rails (RoR)
- Based on MVC architecture for applications
- MVC cleanly separates applications into three
parts:
- Model – the data and any restraints on it
- View – prepares and presents results to the
user
- Controller – controls the application
- One characterizing part of Rails is its approach
to connecting object-oriented software with a
relational database – ORM
- Maps tables to classes, rows to objects, and
columns to fields of the objects
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
1
15.1 Overview of Rails (continued)
- View documents are XHTML documents that may
include Ruby code
- Most of the controller code is provided by Rails
- A Rails application is a program that provides a
response when a client browser connects to a
Rails-driven Web site
- Rails can be used with Ajax
- Two fundamental principles that guided the
development of Rails:
1. DRY
2. Convention over configuration
- Rails does not use a GUI
- One simple way to get started with Rails is to
download a complete development system
http://instantrails.rubyforge.org/wiki/wiki.pl
- Includes Ruby, Rails, MySQL, Apache and
everything else that is necessary
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
2
15.2 Document Requests
- InstantRails is self-contained – not run through a
Windows command window
- InstantRails is usually installed in a user-defined
subdirectory
- Static Documents
- To use Rails:
1. Click the red I in the directory where Rails was
installed
2. Click the black I in the upper left part of the
resulting window
3. Select Rails Application to open an other menu
4. Select Open Ruby Console Window
- Opens a command-line window
- After creating a directory in rails_apps for all
related Rails applications, use the rails
command in that directory to create a specific
application (in our example, greet)
>rails greet
- This creates the framework for the new
application (more than 45 files in 30
directories)
- The app subdirectory has four subdirectories,
models, views, controllers, and helpers
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
3
15.2 Document Requests (continued)
- Static Documents (continued)
- The generate script can be used to create part of
the controller for the application
>ruby script/generate controller say
- The created controller will have the name say
- There are now two files with empty classes in the
controller directory, application.rb, and
say_controller.rb,. These contain
ApplicationController and SayController
class SayController < ApplicationController
end
- Next, add an empty method to the SayController
class
def hello
end
- The URL of the Rails application is
http://localhost:3000/say/hello
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
4
15.2 Document Requests (continued)
- Static Documents (continued)
- Next, build the view file, or template, which must
reside in the say subdirectory of the views
directory of the application and be named
hello.html.erb
- This is an XHTML document with the
following in its body element
<h1> Hello from Rails! </h1>
- To test the application, a Web server must be
started
>ruby script/server
- This starts the default server, named Mongrel
- Now, pointing the browser to the application
produces the displayed view template content
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
5
15.2 Document Requests (continued)
- Static Documents (continued)
- Response activities:
1. Instantiate SayController class
2. Call the hello action method
3. Search the views/say directory for hello.html.erb
4. Process hello.html.erb with Erb
5. Return the resulting hello.html.erb to the
requesting browser
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
6
15.2 Document Requests (continued)
- Dynamic Documents
- There are three ways in Rails to build dynamic
documents, but we discuss only one: Embed
Ruby code in the template document
- An example: display a greeting and the current
date and time and the number of seconds since
midnight
- Ruby code is embedded in a document by
placing it between <% and %>
- To insert the result of evaluating the code into
the document, use <%=
- The Time class has a method, now, that returns
the current day of the week, month, day of the
month, time, time zone, and year, as a string
It is now <%= t = Time.now %>
Number of seconds since midnight:
<%= t.hour * 3600 + t.min * 60 + t.sec %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
7
15.2 Document Requests (continued)
- Dynamic Documents (continued)
- It would be better to put the code in the controller
def hello
@t = Time.now
@tsec = @t.hour * 3600 + @t.min * 60 + @t.sec
end
- Now the Ruby code in the template is:
It is now <%= @t %> <br />
Number of seconds since midnight: <%= @tsec %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
8
15.3 Rails Applications with
Databases
- We will use MySQL
- Use a simple database with just one table
- The application will be named cars
- The application will present a welcome document
to the user, including the number of cars in the
database and a form to get the beginning and
ending years and a body style for the desired car
- Creating the application
- In the subdirectory of our examples:
>rails –d mysql cars
- It is customary to used three databases in a Rails
database application: one for development, one
for testing, and one for production
- To create the three (empty) databases:
>rake db:create:all
- Creates the database.yml file in the config
subdirectory of the application directory (cars)
- See next page
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
9
15.3 Rails Applications with
Databases (continued)
# MySQL. Versions 4.1 and 5.0 are recommended.
#
development:
adapter: mysql
encoding: utf8
database: cars_development
username: root
password:
host: localhost
test:
adapter: mysql
encoding: utf8
database: cars_test
username: root
password:
host: localhost
production:
adapter: mysql
encoding: utf8
database: cars_production
username: root
password:
host: localhost
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
10
15.3 Rails Applications with
Databases (continued)
- Build the model, migration script, database table,
and maintenance controller for the database
>ruby script/generate scaffold Corvette
body_style:string miles:float year:integer
- The migration class built by this in
cars/db/migrate is:
class CreateCorvettes < ActiveRecord::Migration
def self.up
create_table :corvettes do |t|
t.string :body_style
t.float :miles
t.integer :year
t.timestamps
end
end
def self.down
drop_table :corvettes
end
end
- We do not have a database—only the description
(a migration class) of a database
- To create the database, use rake again:
>rake db:migrate
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
11
15.3 Rails Applications with
Databases (continued)
- This second rake command, which executes the
self.up method of CreateCorvettes class in
001_create_corvettes.rb, produces the following
response:
(in C:/myrails/rails_apps/examples/cars)
== 1 CreateCorvettes: migrating==============
-> 0.2030s
== 2 CreateCorvettes: migrated (0.3440s) ====
- The scema for the new database, schema.rb, which
is in cars/db, is:
ActiveRecord::Schema.define(:version => 1) do
create_table "corvettes", :force => true do |t|
t.string
"body_style"
t.float
"miles"
t.integer "year"
t.datetime "created_at"
t.datetime "updated_at“
end
end
- The controller for the application is named
corvettes, so we can see the application at
http://localhost:3000/corvettes
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
12
15.3 Rails Applications with
Databases (continued)
- If we click New corvette, we get:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
13
15.3 Rails Applications with
Databases (continued)
- If we fill out the form, as in:
- Now we click Create, which produces:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
14
15.3 Rails Applications with
Databases (continued)
- Now if we click Back, we get:
- If we click Edit, we get:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
15
15.3 Rails Applications with
Databases (continued)
- If we click Destroy, we get:
- The model file, which is in cars/models, has the
empty class:
class Corvette < ActiveRecord::Base
end
- We can easily add some validation to this class
validate_presence_of :body_style, :miles, :year
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
16
15.3 Rails Applications with
Databases (continued)
- The controller built by Rails, named
CorvetteController, provides the action methods:
index – creates a list of rows of the table
show – creates the data for one row
new – creates a new row object
edit – handles editing a row
create – handles row creation
update – handles updating a row
delete – handles row deletion
- There are four documents in the views directory,
index.html.erb, new.html.erb, show.html.erb,
and edit.html.erb
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
17
15.3 Rails Applications with
Databases (continued)
<h1> &nbsp; </h1>
<h1>Listing corvettes</h1>
<table>
<tr>
<th>Body style</th>
<th>Miles</th>
<th>Year</th>
<th>State</th>
</tr>
<% for corvette in @corvettes %>
<tr>
<td><%=h corvette.body_style %></td>
<td><%=h corvette.miles %></td>
<td><%=h corvette.year %></td>
<td><%=h corvette.state %></td>
<td><%= link_to 'Show', corvette %></td>
<td><%= link_to 'Edit',
edit_corvette_path(corvette) %></td>
<td><%= link_to 'Destroy', corvette,
:confirm => 'Are you sure?',
:method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New corvette', new_corvette_path %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
18
15.3 Rails Applications with
Databases (continued)
- Notice that index.html.erb is only the content of the
body element
- The rest of the document comes from a layout
document, which is stored in the layout
subdirectory of views – built by scaffold
<!DOCTYPE html PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/
xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type"
content="text/html;charset=UTF-8" />
<title>Corvettes:
<%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<p style="color: green"><%= flash[:notice] %>
</p>
<%= yield %>
</body>
</html>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
19
15.3 Rails Applications with
Databases (continued)
- The new.html.erb document is:
<h1>New corvette</h1>
<%= error_messages_for :corvette %>
<% form_for(@corvette) do |f| %>
<p>
<b>Body style</b><br />
<%= f.text_field :body_style %>
</p>
<p>
<b>Miles</b><br />
<%= f.text_field :miles %>
</p>
<p>
<b>Year</b><br />
<%= f.text_field :year %>
</p>
<p>
<b>State</b><br />
<%= f.text_field :state %>
</p>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
<%= link_to 'Back', corvettes_path %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
20
15.3 Rails Applications with
Databases (continued)
- The show.html.erb document is:
<p>
<b>Body style:</b>
<%=h @corvette.body_style %>
</p>
<p>
<b>Miles:</b>
<%=h @corvette.miles %>
</p>
<p>
<b>Year:</b>
<%=h @corvette.year %>
</p>
<p>
<b>State:</b>
<%=h @corvette.state %>
</p>
<%= link_to 'Edit',
edit_corvette_path(@corvette) %>
<%= link_to 'Back', corvettes_path %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
21
15.3 Rails Applications with
Databases (continued)
- The edit.html.erb document is:
<h1>Editing corvette</h1>
<%= error_messages_for :corvette %>
<% form_for(@corvette) do |f| %>
<p>
<b>Body style</b><br />
<%= f.text_field :body_style %>
</p>
<p>
<b>Miles</b><br />
<%= f.text_field :miles %>
</p>
<p>
<b>Year</b><br />
<%= f.text_field :year %>
</p>
<p>
<b>State</b><br />
<%= f.text_field :state %>
</p>
<p>
<%= f.submit "Update" %>
</p>
<% end %>
<%= link_to 'Show', @corvette %> |
<%= link_to 'Back', corvettes_path %>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
22
15.3 Rails Applications with
Databases (continued)
- Now we must build the actual application
- Build a second controller for the required
processes
>ruby script/generate controller main
- Add an action method for the welcome screen
# main_controller.rb - for the cars application
class MainController < ApplicationController
# welcome method
# fetches the value for the initial view
def welcome
@num_cars = Corvette.count
end
end
- The count method of the table classes returns
the number of rows in the table
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
23
15.3 Rails Applications with
Databases (continued)
- To implement the searches of the table, use find
- The find method searches a table for a
specific row
mycar = Corvettes.find(8)
list_five = (1, 2, 3, 4, 5)
first_five = Corvettes.find(list_five)
The RecordNotFound exception is thrown if
find is asked to do something it cannot do
The find method can take more complex
parameters
sixty_five_conv = find(:all,
:conditions => "year = 1965
and body_style = 'convertible'")
- To use find with non-literal conditions, a
different parameter form is needed
some_year_conv = find(:all, :conditions =>
["year = ? and body_style = 'convertible'",
@year])
- If the first parameter is :first, it gets only the
first row that meets the specified condition
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
24
15.3 Rails Applications with
Databases (continued)
- Next, design the welcome template, which
has two tasks:
1. Display text boxes to get the model years
and body style of interest from the user
2. Display the number of cars furnished by the
welcome action method in the controller
<!– welcome.html.erb – initial view for the
cars application -->
<!– The initial information -->
<p>
<h1> Aidan’s Used Car Lot </h1>
<h2> Welcome to our home document </h2>
We currently have <%= @num_cars %> used
Corvettes listed <br /> To request information
on available cars, please fill out <br /> the
following form and submit it
</p>
<!– The form to collect input from the user
about their interests -->
<form action = "result" method = "post">
From year: <input type = "text" size = "4"
name = "year1" />
To year: <input type = "text" size = "4"
name = "year2" />
Body style: <input type = "text" size = "12"
name = "body" /> <br />
<input type = "submit" value = "Submit" />
<input type = "submit" value = "Reset" />
</form>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
25
15.3 Rails Applications with
Databases (continued)
- Next, design the result action method, which
is named result in the welcome template form
- Task: get form data and use find to compute the
required output data for the result
template
- The form data is made available by Rails through a
hash-like object params
- params can be indexed by either keys or symbols
If phone is the name of a control, we can use:
@phone = params[:phone]
- The result method of the main controller is:
# result method - fetches values for the result
#
template
def result
@year1 = params[:year1]
@year2 = params[:year2]
@body = params[:body]
@selected_cars = Corvette.find(:all,
:conditions => ["year >= ? and year <= ?
and body_style = ?",
@year1, @year2, @body])
end
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
26
15.3 Rails Applications with
Databases (continued)
- Last step: build the result template document
- Put the information about cars from
@selected_cars in a table
<!-- Display what the user asked for -->
<p> Cars from <%= @year1 %> to <%= @year2 %>
with the <%= @body %> body style </p>
<!-- Display the results in a table -->
<table border = "border">
<tr>
<th> Body Style </th>
<th> Miles </th>
<th> Year </th>
</tr>
<!-- Put the cars of @selected_cars in table -->
<% @selected_cars.each do |car|
<tr>
<td> <%= car.body_style %> </td>
<td> <%= car.miles %> </td>
<td> <%= car.year %> </td>
</tr>
<% end %> <!-- end of do loop -->
</table>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
27
15.3 Rails Applications with
Databases (continued)
- A filled out request:
- The result document:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
28
15.3 Rails Applications with
Databases (continued)
- Modifying a database
- Rails was designed for agile development, so it
makes it easy to change to new versions of
databases, and also to revert back to earlier
versions
- The name of the initial version of the migration for
the corvettes table was 001_create_corvettes.rb
(it is in db/migrate)
- To change a database table, a new migration file
is created and rake is used to update the table
- To illustrate a change, we add a state column to
the corvettes table
- To create the new migration file:
>ruby script/generate migration
AddStateToCorvette state:string
- Produces the response:
exists db/migrate
create db/migrate/002_add_state_to_corvettes.rb
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
29
15.3 Rails Applications with
Databases (continued)
- Modifying a database (continued)
- The resulting migration class, named
002_add_state_to_corvette/rb:
class AddStateToCorvette < ActiveRecord:Migration
def self.up
add_column :corvettes, :state, :string
end
def self.down
remove_column :corvettes, :state
end
end
- Now use rake to apply the migration to the table:
>rake db:migrate
- Rails response:
(in c:\myrails\rails_apps\examples\cars)
== 1 AddStateToCorvette: migrating =============
-- add_column(:corvettes, :state, :string)
-> 0.3750s
== 2 AddStateToCorvette: migrated (0.5160s) ====
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
30
15.3 Rails Applications with
Databases (continued)
- Modifying a database (continued)
- The revised schema is:
ActiveRecord::Schema.define(:version => 2) do
create_table "corvettes", :force => true do |t|
t.string
"body_style"
t.float
"miles"
t/integer "year"
t.datetime "created_at"
t.datetime "updated_at"
t.string
"state"
end
end
- Now the display of corvettes is:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
31
15.3 Rails Applications with
Databases (continued)
- Modifying a database (continued)
- To go back to the last migration form:
>rake db:rollback
- To go back to any migration:
>rake db:migrate VERSION=1
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
32
15.3 Rails Applications with
Databases (continued)
- Using MySQL in Rails
- Go to the mysql/bin directory and start MySQL
>mysql [-h host] [-u username] [database_name]
[-p]
- To fill a table using MySQL:
mysql> use cars_development;
- Put the INSERT command into the fill_table.sql
file
mysql>mysql –u root < fill_table.sql
- Layouts
- Rails provided one for the corvettes controller
- We could build one for the main controller
- Include the DOCTYPE, some headings, and a
footer for a copyright
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
33
15.3 Rails Applications with
Databases (continued)
<!DOCTYPE html PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD
/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<head> <title> Main </title>
</head>
<body>
<h1> Aidan's Used Car Lot </h1>
<h2> Welcome to our home document </h2>
<%= yield %>
<hr/>
<p> Copyright 2009, AUCL, Inc. </p>
</body>
</html>
- We could also add a stylesheet for the templates of
main
- Could be used for both the actual template file
and the layout
/* mainstyles.css - a style sheet for
the main controller */
h1 {font-style: italic; color: blue;}
h2 {color: blue;}
.labels {font-style: italic; color: red;}
- Stored in the cars/public/stylesheets directory
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
34
15.3 Rails Applications with
Databases (continued)
- To reference the stylesheet in the layout, add the
following to the head of the layout document
<%= stylesheet_link_tag "mainstyles" %>
- The form of the main template must be changed
to use the styles
<form action = "result" method = "post" >
<span class = "labels"> From year: </span>
<input type = "text" size = "4"
name = "year1" />
<span class = "labels"> To year: </span>
<input type = "text" size = "4"
name = "year2" />
<span class = "labels"> Body style: </span>
<input type = "text" size = "12"
name = "body" /> <br />
<input type = "submit"
value = "Submit request" /> <br />
<input type = "reset"
value = "Reset form" /> <br />
</form>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
35
15.3 Rails Applications with
Databases (continued)
- Now the welcome template appears as:
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
36
15.4 Rails with Ajax
- There is a library of JavaScript utilities named
Prototype, which has much of what is needed
- To access it, place the following in the Rails
template document:
<%= javascript_include_tag "prototype" %>
- Problems with using Rails and Ajax
- Not all elements can be modified or replaced on
all browsers using only the Rails tools
- A simple solution: Use div elements for
content that is to be replaced using Ajax
- Rails implements Ajax as follows:
1. Triggered by a user event or a timer
2. Data associated with the event is sent
asynchronously to a controller method (an
action handler) on the server using an XHR object
3. The controller action handler performs some
operation and returns text, XML or XHTML
4. JavaScript on the browser receives the response
and performs the update to the document
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
37
15.4 Rails with Ajax (continued)
- Example – popcorn form, again
- The application is named popcornA, the
controller is named popcorn, and the controller
class is named PopcornController
- The initial action method (and the view template)
are named show_form
 SHOW show_form.html.erb
- Rails uses several different helper methods to
trigger the Ajax process, most commonly
link_to_remote and observe_field
- These are JavaScript functions wrapped in
Ruby methods
- observe_field can take many parameters
- First parameter - a literal string with the id of
the control element to watch
- Other parameters appear as the elements of
a hash literal
- The name of the action method:
:url => (:action => process_form)
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
38
15.4 Rails with Ajax (continued)
- Example (continued)
- More parameters
:update
- When :update is specified, the controller
action given in :url produces the response
using the render method
- The :text parameter is passed to render
:text is set (with =>) to a string value
render :text => " <p> … </p>"
:with
- A JavaScript expression giving the first
parameter for the XHR request object
e.g., "’zip’=value"
:frequency
- The frequency in seconds at which changes
to the specified widget will be detected
- Not setting a frequency causes an event
to be used, instead of a timer (changed for
text boxes and click for buttons), rather
than time-based observations.
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
39
15.4 Rails with Ajax (continued)
- Example (continued)
:complete, :success, :failure
- To specify the callback function to be called
when the Ajax operation is completed
- Complete example call to observer_field:
<%= observe_field("my_button",
:update => "name"
:url => {:action => process_form}) %>
- Recall that the controller action method for the
application gets the response, splits it, and
updates the text boxes for city and state
- This code is the content of a javascript_tag,
because it will be in a view template, which is
an html.erb file
<%= javascript_tag <<-END
function update_city_state(xhr) {
result = xhr.responseText.split(', ');
document.getElementById('city').value =
result[0];
document.getElementById('state').value =
result[1];
}
END
%>
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
40
15.4 Rails with Ajax (continued)
- Example (continued)
- Because this application updates two elements,
:update is not used; rather, the name of the
update function is given with complete
<$= observe_field("zip",
:url => {:action => :fill_city_state},
:complete => 'update_city_state(request); ',
:with => 'zip'
) %>
- The Controller
- The action method, fill_city_state,
generates the city and state for the form,
given the zip code as a POST parameter
 SHOW popcorn_controller.rb
- In a Rails application, the new partial document
could be produced by either the controller method
or in the template document
- If the template does it, the action method of the
controller must include
render(:layout => false)
- If the action method does it, it uses render
Chapter 15
© 2009 by Addison Wesley Longman, Inc.
41