com531 multimedia technologies lecture 8 – ruby and rails

69
COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Upload: anis-mitchell

Post on 01-Jan-2016

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

COM531 Multimedia Technologies

Lecture 8 – Ruby and Rails

Page 2: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Origins and Uses of Ruby

Designed by Yukihiro Matsumoto (Matz); released in 1996

Use spread rapidly in Japan, Use is now growing in part because of Rails (will be covered later in lecture)

A pure object-oriented purely interpreted scripting language

Related to Perl and JavaScript, but not closely

Scalar Types and Their Operations

There are three categories of data types: scalars, arrays, and hashes

Two categories of scalars, numerics and strings

All numeric types are descendants of the Numeric class

Integers: Fixnum (usually 32 bits) and Bignum

Page 3: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Scalar Literals

An integer literal that fits in a machine word is a Fixnum (32 bit digit)

Other integer literals are Bignum objects (depending on size of number these two can be interchanged). Presentation of numbers in Ruby is easier as underscores (which are ignored) can be used, i.e. 123_456_789_321

Any numeric literal with an embedded decimal point or a following exponent is a Float object, the decimal point must be embedded (preceded and followed by at least one number) so in Ruby .435 is not a legal literal

All string literals are String objects – defined by single-quote and double-quotes

The Null string (one with no characters) can be denoted with either ‘ ‘ or “ “

Single-quoted literals cannot include apostrophes: these need to be preceded with \‘I\’ll meet you at O\’Malleys’

Double-quoted literals •can include escape sequences, e.g. “Runs \t Hits \t Errors” will be presented spaced with tabs•and can interpolate embedded variables - their values are substituted for their

names

Page 4: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Variables

Names of local variables begin with lowercase letters and are case sensitive

Variables embedded in double-quoted literal strings are interpolated if they appear in braces and are preceded by a hash sign (#)

“Tuesday’s high temperature was #{tue_high}”

If value of tue_high is 83, string has the following value“Tuesday’s high temperature was 83”

“The cost of our apple order is $#{price * quantity}”

If the value of price is 1.65 and quantity is 6, the value of this string is“The cost of our apple order is $9.90”

In Ruby (which is a pure object-orientated language) variables do not have types, they are all references to objects, every data value is an object – differs from C++ and Java where variables need to be defined, in Ruby there is no way to define a variable!

Page 5: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Numeric Operators

Arithmetic operators are like those of other languages,(binary operators), + for addition, - for subtraction, * for multiplication, / for division, ** for exponentiation and % for modulus

except Ruby has no increment (++) or decrement (--) found in other languages

Any operation on Bignum objects that produces a result that fits in a Fixnum coerces it to a Fixnum, Any operation on Fixnum objects that produces a result that is too large coerces it to a Bignum

Ruby included a Math module which methods for basic trigonometric and transcendental functions – referenced by prefixing their names with Math. e.g., Math.sin(x)

Interactive Rubyirb is an interactive interpreter for Ruby, allowing one to type any Ruby expression and get an immediate response from the interpreter

% irb – irb will respond with its own prompt which is,irb(main):001:0>

irb(main):001:0> 17 * 3=>51irb(main):002:0>

Shorten the prompt with irb(main):002:0>conf.prompt_i = ">>"

Try it out at http://tryruby.org

Page 6: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

String Methods

Ruby string class has more than 75 methods, many can be used as operators. String method for concatenation is plus (+), which creates a new string from its operands.

>>”Happy” + “ “ + “Holidays!”=> “Happy Holidays!”

The << method appends another string to the right end of a string,

>>mystr = “G’day ““G’day “>> mystr << “mate”=> “G’day mate”

Assign mystr to another variable >> mystr = "Wow!" => "Wow!" >> yourstr = mystr => "Wow!" >> mystr = "What?" => "What?" >> yourstr => "Wow!"

If you want to change the value of the location that is referenced by a variable, use replace >> mystr.replace("Oh boy!") => "Oh boy!"

Page 7: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Commonly used String Methods

Method Action

capitalize Converts the first letter to uppercase and the rest of the letters to lowercase

chop Removes the last character

chomp Removes a newline from the right end, if there is one

upcase Converts all of the lowercase letters in the object to uppercase

downcase Converts all of the uppercase letters in the object to lowercase

strip Removes the spaces on both ends

lstrip Removes the spaces on the left end

rstrip Removes the spaces on the right end

reverse Reverses the character of the string

swapcase Converts all uppercase letters to lowercase and all lowercase letters to uppercase

Page 8: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

String Methods (cont)

All of the aforementioned produce new strings, while bang or mutator methods can be used to modify the string in place– add an !

>> str = “Frank”“Frank”>> str.upcase!“FRANK”>> str=> “FRANK”

The == operator tests for equality of the objects

>> “snowstorm” == “snowstorm”true>>”snowie” == “snowy”=> false

In a similar vein to test whether two variables reference the same object, use the equal? method

And another alternative, the eql? method tests whether the receiver object and the parameter have the same type and the same value

Page 9: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Ordering

For ordering, use the “spaceship” operator It returns -1 if the second operand is greater than the first, 0 if they are equal and 1 if the

first operand is greater than the second

In this case greater than means belongs later alphabetically

>> “apple” “prune” -1

>> “grape” “grape” 0

>> “grape” “apple”

=> 1

The * operator takes a string and a numeric expression—it replicates the string

>> “More! “ * 3

=> “More! More! More! “

Repetition

Page 10: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Simple Output

Output directed to the screen with the puts operator (or method), implicitly attaches a newline

>> name = “Fudgy”“Fudgy”>> puts “My name is #{name}”My name is Fudgy

• Use print if you don’t want the newline• sprintf is also available for conversions to string

total = 352.70str = sprintf(“%7.2f”, total)

- means a total field width of seven spaces, with two digits to the right of the decimal point, which is perfect for money

Page 11: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Simple Keyboard Input The gets method gets a line of input from the keyboard and returns it, including the

newline (if newline not needed it can be discarded with chomp

>>name = gets.chomp

Apples “apples”

If the input is a number, it must be converted with either to_i (integer) or to_f

(floating-point value)

age = gets.to_i age = gets.to_f

27 27.5

=> 27 => 27.5

Running a Ruby script

> ruby filename

Add -c flag is compile only; -w flag is for warnings

> ruby –cw quadeval.rb where quadeval is filename and .rb is ruby extension

If program is found to be okay, the response to this command is

Syntax OK

Page 12: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Selection and Loop Statements

Selection Statements

if control_expression statement_sequence else statement_sequence end

if a > 10b = a * 2End

An if construct can include elsif (not spelled “elseif”)

if snowrate < 1 puts “light snow”elsif snowrate < 2 puts “moderate snow”else puts “heavy snow”end

- unless is inverse of ifunless sum > 1000 puts “we are not finished yet”end

Page 13: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Selection Statements

case expression when value then statement_sequence when value then statement_sequence … [else statement_sequence] end

The values could be expressions, ranges (e.g., (1..10)), class names, or regular expressions

Page 14: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Semantics of the case statement:

1. There is an implicit break at the end of every selectable segment

2. The value of the expression is compared with the when values, top to bottom, until a match is found

3. A different operator, ===, is used for the comparisons. If the value is a class name, it is a match if its class is the same as that of the expression or one of its superclasses; if the value is a regular expression, === is a simple pattern match

case in_val when -1 then neg_count += 1 when 0 then zero_count += 1 when 1 then pos_count += 1 else puts "Error – in_val is out of range" end

Page 15: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

• Unconditional Loop

loop body The body optionally begins with begin and always ends with end

• The break statement

-Control goes to the first statement after the body

• The next statement

-Control goes to the first statement in the body

• Ruby does not have a C-style for statement, iterators are used instead

Page 16: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

ArraysDifferences between Ruby arrays and those of other common languages:

1. Length is dynamic 2. An array can store different kinds of data

Array Creation - Ruby arrays can be created in two different ways. First, an array can be created by sending the new message to the predefined Array class. Second, simply assign a list literal to a variable, where list of literals is delimited by brackets.

1. Send new to the Array class

>>list1 = Array.new(5)[nil, nil, nil, nil, nil]>> list2 = Array.new(5, "Ho")=> ["Ho", "Ho", "Ho", "Ho", "Ho"] 2. Assign a list literal to a variable

>> list2 = [2, 4, 3.14159, "Fred", [] ]=> [2, 4, 3.14159, "Fred", [] ]

The length of an array is returned by length >> len = list.length=> 5

Page 17: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

The for-in Statement

The for-in Statement is used to process the elements of an array

>> sum = 0=> 0>> list = [2, 4, 6, 8]=> [2, 4, 6, 8]>> for value in list>> sum += value>> end=> [2,4,6,8]>> sum=> 20

Page 18: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Methods for Arrays and Lists

- Adding and deleting the end elements - unshift, shift, push, pop

- The concat method - takes one or more parameters, which are pushed onto the end of the array

- The reverse method - does what its name implies

- The include? predicate method - Searches the array for the given element

- The sort method

- For arrays of a single element type - Works for any type elements for which it has a comparison operation - Returns a new array; does not affect the array object to which it is sent

(See example on next slide)

Page 19: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Example A list of names is read from the keyboard, each name is converted to all uppercase letters and placed in an array. The array is then sorted and displayed.

# process_names.rb – a simple ruby program to illustrate the use of arrays

# Input: a list of lines of text, where each line is a person’s name

# Output: the input names, after all letters are converted to uppercase, in alphabetical order

index = 0

names = Array.new

#Loop to read the names and process them

while (name = gets)

#Convert the name’s letters to uppercase and put it in the names array

names[index] = name.chomp.upcase

index += 1

end

#Sort the array in place and display it

names.sort!

puts “The sorted array”

for name in names

puts name

end

Page 20: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Hashes - a.k.a. Associative Arrays

Two fundamental differences between arrays and hashes:

1. Arrays use numeric subscripts; hashes use string values

2. Elements of arrays are ordered and are stored in contiguous memory; elements of hashes are not

Hash Creation

1. Send new to the Hash class

my_hash = Hash.new

2. Assign a hash literal to a variable

ages = ("Mike" => 14, "Mary" => 12)

- Element references – through subscripting

ages["Mary"]

- Element are added by assignment

ages["Fred"] = 9

Page 21: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

- Element removal

ages.delete("Mike")

- Hash deletion

ages = () or ages.clear

- Testing for the presence of a particular element

>>kids_ages.has_key?(“John")

- Extracting the keys or values

>>kids_ages.keys=> [“Aiden”, “Darcie”, “John”, “Jake”]

>> kids_ages.values=> [8, 6, 4, 3]

Page 22: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Methods

All Ruby subprograms are methods, but they can be defined outside classes

def method_name[(formal_parameters)] statement_sequence end

When a method is called from outside the class in which it is defined, it must be called through an object of that class

When a method is called without an object reference, the default object is self

When a method is defined outside any class, it is called without an object reference

Method names must begin with lowercase letters

The parentheses around the formal parameters are optional

Neither the types of the formal parameters nor that of the return type is given

If the caller uses the returned value of the method, the call is in the place of an operand in an expression

Page 23: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Methods

If the caller does not use the returned value, the method is called with a standalone statement

The return statement is often used to specify the return value

If a return is not executed as the last statement of the method, the value returned is that of the last expression evaluated in the method

Local Variables

Local variables are either formal parameters or variables created in the method

A local variable hides a global variable with the same name

The names of local variables must begin with either a lowercase letter or an underscore

The lifetime of a local variable is from the time it is created until execution of the method is completed

Page 24: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Classes

A class defines the template for a category of objects, of which any number can be created. The methods and variables of a class are defined in the syntactic container that has the following form:

class Class_name … end

Class names must begin with uppercase lettersclass Stack2_class

The names of instance variables must begin with at signs (@) @stack_ref = Array.new(len)

Classes in Ruby are dynamic in the sense that members can be added at any time, done by simply including additional class definitions that specify new members.

Methods can be removed with remove_method in subsequent definitions

Allowing dynamic changes to classes clearly adds flexibility to the language, but harms readability. To determine the current definition of a class, one must find all of its definitions in the program and consider all of them.

Page 25: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Access Control

If needed, external access to instance variables is provided with getters and setters

class My_class # Constructor def initialize @one = 1 @two = 2 end # A getter for @one def one @one end # A setter for @one def one=(my_one) @one = my_one end end

Note the “=“ in the setter name

When an instance variable is referenced inside the class, the @ is included in the name; when referenced outside the class, it is excluded

Shortcuts for getters and setters

attr_reader :one, :two attr_writer :one

Page 26: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Inheritance

• Subclasses are defined in Ruby using the less than (<) symbol

class My_Subclass < Base_class

Ruby modules provide a naming encapsulation that is often used to define libraries of methods. Access to a module is specified with an include statement, such as

include Math

The methods in a module are mixed into those of the class that includes it – this is called a mixin. Mixins provide a way to include the functionality of a module in any class that needs it. They also provide the benefits of multiple inheritance (as the class still has a normal superclass from which it inherits members) without the naming collisions.

Page 27: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Code Blocks and Iterators

A block is a segment of code, delimited by either braces or do and end reserved words

By itself, a block does nothing but blocks can be sent to methods by attaching them to calls, this construct is used to build iterators

• Built-in Iterators

times – blocks are sent to number objects to build simple counting loops 4{puts "hey!"}

Blocks can have parameters; they appear at the beginning of the block in vertical bars (|)

each – blocks are sent to array objects; the block is applied to each element of the array

>> list = [2, 4, 6, 8]=> [2, 4, 6, 8]>>list.each {|value| puts value}2468

Page 28: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

upto – blocks are sent to number objects, including a parameter for the last value

>>5.upto(8) {|value| puts value}

step – blocks are sent to number objects, including two parameters for the last value and a step size >>0.step(6, 2) {|value| puts value}

collect – sent to an array, like each, but the block constructs and returns a new array

list.collect {|value| value -= 5}

- The mutator version of this is often useful – collect!

Page 29: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

User-defined blocks

User-defined blocks

Blocks are called in methods with yield, which can include parameters to the block

>> def get_name>> puts "Your name:">> name = gets>> yield(name)>>end=> nil>> get_name {|name| puts "Hello, " + name}Your name:SandraHello, Sandra=>nil

Page 30: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Pattern Matching

In Ruby the pattern-matching operand is specified with the matching operators, =~ for a positive match and !~ for a negative match. Patterns are placed between slashes (/), for example

>> street = “Hammel"“Hammel”>> street =~ /mm/=> 2 Remembering matches

>> str = “4 July 1776”“4 July 1776”>> str =~ /(\d+) (\w+) (\d+)/0>> puts “#{$2) “#{$1) “#{$3)”July 4 1776

Page 31: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Substitutions

Ruby has four methods of the String class for string substitutions

str.sub(pattern, replacement)

>> str = “The old car is great, but old” “The old car is great, but old”

>> str.sub (/old/, “new”)

=> “The new car is great, but old”

The gsub is similar to sub but finds all substring matches and replaces all of them with its second parameter, for example

>> str = “The old car is great, but old” “The old car is great, but old”

>> str.gsub (/old/, “new”) “The new car is great, but new”

>> str “The old car is great, but old”

There are also mutator versions sub! and gsub !

The i modifier tells the pattern matcher to ignore the case of the letters, for example

>> str = “Is it Rose, rose, or ROSE?” “Is it Rose, rose, or ROSE?”

>> str.gsub(/rose/i, “rose”)

=> “Is it rose, rose, or rose?”

Page 32: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

COM531 Multimedia Technologies

Rails

Page 33: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

http://rubyonrails.org/

http://guides.rubyonrails.org/getting_started.html

Page 34: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 Model-View-Controller (MVC) architecture for applications, which 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, using an object-relational mapping (ORM) approach which maps tables to classes, rows to objects, and columns to fields of the objects

The classes, objects, methods and attributes that represent a database in Ruby are automatically built in Rails

Page 35: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails components

Browser Controller

View Model Database

Request

Response

A request and response in a Rails application

Page 36: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Overview of Rails (2)

For web applications view documents are XHTML documents that may include Ruby code (where 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, part of “Agile Development” focus on quick development of working software rather than elaborate documentation and visual aesthetics. Rails does not use a GUI, but is a command-line-orientated system.

Rails can be used in conjunction with Ajax. Rails uses a JavaScript library named Prototype to support Ajax, also produces some visual effects

Two fundamental principles that guided the development of Rails: 1. DRY – Do not Repeat Yourself (every element of information appears just once in the system – minimizes memory required, changes to system are highly localized making them easier and less error prone) 2. Convention over configuration – structure of an application is established and maintained by convention, rather than being specified in a config document

One simple way to get started with Rails is to download a complete development system

http://instantrails.rubyforge.org/wiki/wiki.pl

Instant Rails developed by Curt Hibbs and includes Ruby, Rails, MySQL, Apache and everything else that is necessary. Instant Rails is self-contained – not run through a Windows command window

Page 37: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Launching Rails

To use Rails: 1. Click the red I (icon of the InstantRails application) in the directory where Rails is installed 2. Click the black I in the upper left part of the resulting window 3. Select Rails Application to open another menu 4. Select Open Ruby Console Window - Opens a command-line window in the rails_apps subdirectory of the directory in which InstantRails was installed

If Windows and the IIS server is running, it must be stopped; ditto for MySQL

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 new greet

This creates the framework for the new application (launches more than 45 files in 30 directories)The app subdirectory has four subdirectories, models, views, controllers, and helpers

Page 38: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Document Requests – for static documents The generate script can be used to create part of the controller for the application

>rails generate controller say

The created controller will have the name say, response produced by the execution of this command follows:

exists app/controllers/exists app/helpers/create app/views/sayexists test/functional/create app/controllers/say_controller.rbcreate test/functional/say_controller_test.rbcreate app/helpers/say_helpers.rb

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 – action method

def hello end

The URL of the Rails application is (3000 is server port)http://localhost:3000/say/hello

Page 39: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Static Document Requests (cont)

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 erb instead of doc.type

This is an XHTML document as follows:<html><head> <title> greet </title></head><body> <h1> Hello from Rails! </h1></body></html>

To test the application, a Web server must be started

>rails s

This starts the default server, named Mongrel

Now, pointing the browser to the application produces the displayed view template content(You may need to edit routes.rb in config to make this accessible)

Page 40: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Static Document Requests (cont) http://localhost/say/hello

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

Rails

Page 41: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Dynamic Document Requests Dynamic documents can be built with Rails by embedding 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 %> <br/> Number of seconds since midnight: <%= t.hour * 3600 + t.min * 60 + t.sec %>

Page 42: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Dynamic Document Requests It would be better to put Rails code for time computation in the controller as that would separate code from the markup

class SayController < ApplicationController 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 %>

Page 43: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases

• We will use MySQL (Rails compliant) • 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

Create new application named cars in examples subdirectory:

>rails new cars –d mysql

The d flag followed by mysql tells Rails that this application will use a MySQL DB

It is customary to use three databases in a Rails database application: one for development, one for testing, and one for production - To create the three (empty) databases, change directory to cars, then type:

>rake db:create:all

The Rails response to the command is as follows:

(in C:/myrails/rails_apps/examples/cars)

Creates the database.yml file in the config subdirectory of the application directory (cars)

Page 44: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

database.yml file

# MySQL. Versions 4.1 and 5.0 are recommended.#development: adapter: mysql encoding: utf8 database: cars_development username: root password: host: localhosttest: adapter: mysql encoding: utf8 database: cars_test username: root password: host: localhostproduction: adapter: mysql encoding: utf8 database: cars_production username: root password: host: localhost

Document shows that descriptionsOf all three databases were createdcars_developmentcars_testcars_production

Page 45: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

Next the following command is used to build the model, the required database migration script, the database table,and maintenance controller and testing support files for the database

>rails 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 endend

- Note at this stage we do not have a database—only the description (a migration class) of a database

Page 46: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

To create the database, use the following command:

>rake db:migrate

This command, which executes the self.up method of CreateCorvettes class, produces the following response:

(in C:/myrails/rails_apps/examples/cars) == 1 CreateCorvettes: migrating============== -> 0.2030s == 2 CreateCorvettes: migrated (0.3440s) ====

The schema (in Ruby code) for the newly created database appears in the db subdirectory of the application

ActiveRecord: :Schema.define(:version => 1) docreate_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

The controller for the application is named corvettes, so we can see the application at http://localhost:3000/corvettes

Page 47: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

- If we click New corvette, we get:

Note: Rails built the basic table maintenance operations - create, read, update, and delete (CRUD)

Page 48: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

- If we fill out the form, as in:

- Now we click Create, which produces:

Page 49: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

- Now if we click Back, we get:

- If we click Edit, we get:

Page 50: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

- 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 to produce an error message ifany fields are left blank

validate_presence_of :body_style, :miles, :year

Page 51: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails Applications with Databases (cont)

The model class is now:

class Corvette < ActiveRecord::Base validate_presence_of :body_style, :miles, :year validates_numericality_of :year, :greater_than => 1952, :less_than_or_equal_to => Time.now.year end

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 (see overpage)

Page 52: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Index.html.erb document

<h1>Listing corvettes</h1><table> <tr> <th>Body style</th> <th>Miles</th> <th>Year</th> </tr><% for corvette in @corvettes %> <tr> <td><%=h corvette.body_style %></td> <td><%=h corvette.miles %></td> <td><%=h corvette.year %></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 %>

Page 53: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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>

The call to yield tells Rails the template belongs in thelayout.The call to stylesheet_link_tagspecifies the stylesheet to be usedwith the layout document. In thiscase the stylesheet was furnishedby scaffold

Page 54: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

- 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 %>

The calls to text_field create XHTML textboxesThe call to submit creates an XHTMLsubmit buttonThe call to link_to creates an XHTML link

Page 55: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 %>

The embedded Ruby code, for [email protected] fetches the inputfrom the corresponding text boxThe h in the opening tag specifies that all < and > characters are to be convertedto character entities to prevent problems

Page 56: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 %>

Page 57: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Now we must build the actual application

- Build a second controller, which we will call main to implement the required actions of the application

>rails generate controller main

- Next we add an empty action method named welcome to the new controller. This action method will provide the initial display to the user for the application. welcome method must also provide the number of cars in the db

# main_controller.rb - for the cars applicationclass MainController < ApplicationController

# welcome method # fetches the value for the initial view

def welcome @num_cars = Corvette.count endend

- The count method of the table classes returns the number of rows in the table

Page 58: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

To implement searches of the table, use find

The find method searches a table for a specific row

mycar = Corvette.find(8)

If given more than one key, find returns an array of the requested row objects, for example list_five = [1, 2, 3, 4, 5] first_five = Corvette.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

Page 59: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 = "reset" value = "Reset" /> </form>

Page 60: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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].to_i @year2 = params[:year2].to_i @body = params[:body] @selected_cars = Corvette.find(:all, :conditions => ["year >= ? and year <= ? and body_style = ?", @year1, @year2, @body]) end

Page 61: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 <%= h(@year1) %> to <%= h(@year2) %> with the <%= h(@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>

Page 62: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

- A filled out request:

- The result document:

Page 63: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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 20091018031809_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:

>rails generate migration AddStateToCorvette state:string

- Produces the response: exists db/migratecreate db/migrate/ 20091018033700_add_state_to_corvettes.rb

Page 64: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Modifying a database (cont)

The resulting migration class, named 20091018033700_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 endend

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) ===

Page 65: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Modifying a database (cont)

Now the display of corvettes is:

- To go back to the last migration form: >rake db:rollback

- To go back to any migration: >rake db:migrate VERSION=1

NOTE: The scaffold-provided methods for listing database tables, creating new rows, editing rows, and deleting rows. However, for creating real database MySQL is a better option (ask me if you want the code for creating MySQL file)

Page 66: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Layouts

Rails provided the layout for the corvettes controllerWe could build one for the main controller by including the DOCTYPE, some headings, and a footer for a copyright

<!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 which 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

Page 67: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

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>

Page 68: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Now the welcome template appears as:

Page 69: COM531 Multimedia Technologies Lecture 8 – Ruby and Rails

Rails with Ajax

There is a library of JavaScript utilities named Prototype, which has much of what is neededTo access it, place the following in the Rails template document:

<%= javascript_include_tag "prototype" %>

Problems 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 or markup 4. JavaScript on the browser receives the response and performs the update to the document