Upload
sampetruda
View
968
Download
0
Embed Size (px)
Citation preview
SEG4110 – Advanced Software Design and Reengineering
TOPIC NRuby on Rails
SEG4110 - Topic N - Ruby on Rails 2
What is Ruby on Rails?
•Ruby is an object-oriented programming language-Incorporates ideas from Smalltalk, Java, etc.
-Very pure
•Rails is a Ruby framework for creating web applications quickly and easily
SEG4110 - Topic N - Ruby on Rails 3
The Ruby language - basicsAn open-source, dynamic language•Created by Yukihiro “matz” Matsumoto
—Originated in 2001, Public release in 2005
•Supported by a large community
Main website:•www.ruby-lang.org
Rapidly growing library and online resources•http://rubyforge.org/softwaremap/trove_list.php
•http://www.sapphiresteel.com/The-Little-Book-Of-Ruby
Store programs in files with extension .rb•Or run the irb interpreter
SEG4110 - Topic N - Ruby on Rails 4
Until last year, the fastest growing language http://www.tiobe.com/tpci.htm
SEG4110 - Topic N - Ruby on Rails 5
Ruby: Flexibility, simplicity and power• Everything is an object•Inherits from the Smalltalk legacy
• No variable declarations needed
• Dynamic typing
• ‘Blocks’ allow you to define new control structures
• ‘Mixins’ (modules) give power of multiple inheritance without the drawbacks.
• Code can be added to a class dynamically
• Easy to•Add C code (or code in another language)•Extend the language
SEG4110 - Topic N - Ruby on Rails 6
Defining functions
def helloworld puts "Hello World"end
def hello(arg) puts "hello "+argend
Example runshello "Tim”hello ("Tim") # preferred - usually helps prevent bugs
SEG4110 - Topic N - Ruby on Rails 7
A few more details 1
Placeholder substitution – works with "", but not with ' ' puts "hello #{arg} Your argument is #{arg.length} long!"
Default argument to a method – and concatenationdef hello(arg="World") puts "hello "+argend
Defining an arrayx=[1, 2 ,3]y= %w(an array of strings with the words of this phrase)
Sorting - the ! Means alter (side-effect) the objectx.sort!
SEG4110 - Topic N - Ruby on Rails 8
A few more details 2To access array elementsx [1..3] #elements 0 to 3x [1,3] # elements 0 for 3x [-3,1] # from 3rd-from-the-end for 1
Non numeric collections are called hashesz = Hash.newz [‘SEG4210’] = ‘Advanced Software Engineering’anotherhash = {‘test’ => 12334, ‘test2’ => 98776}
A Ruby method will always return the value of the last expression evaluated•Although using ‘return’ is good practice for clarity
Use ` to execute a program in the operating system`ls`
SEG4110 - Topic N - Ruby on Rails 9
A few more details 3
Symbols•E.g. :all•Represent specific language keywords used in various contexts
SEG4110 - Topic N - Ruby on Rails 10
Iteration
@names.each do |name| print nameend
For number in [1,2,3] do print numberend
while tired sleepend
Ruby has various other allowed syntaxes, including allowing { }
SEG4110 - Topic N - Ruby on Rails 11
“Duck typing”
In Ruby you don't declare the type of a variable•You can put any object in a variable.•You can determine the type in order to make a decision
if @names.respond_to?("join")
“if it talks like a duck, it is a duck”
SEG4110 - Topic N - Ruby on Rails 12
Defining a class The initialize method is used to construct the object•@name is an instance variable•all instance variables are private by default
class Greeter def initialize(name = "World") @name = name end
def say_hi puts "Hi #{@name}!" endend
To create an objectg = Greeter.new("Pat")
SEG4110 - Topic N - Ruby on Rails 13
Attributes: To make instance variables public
attr_accessor :name, :studentNumber
Now I can say in another classg.name="Tim"
andg.name
I can also separately sayattr_reader :studentNumberattr_writer :age
SEG4110 - Topic N - Ruby on Rails 14
Creating a subclass
def specialGreeter < greeter
To call the same method with same arguments in a superclasssuper
SEG4110 - Topic N - Ruby on Rails 15
Class variables (static variables)
@@defaultSize = 5
SEG4110 - Topic N - Ruby on Rails 16
Introspection
Greeter.instance_methods
["method", "send", "object_id", "singleton_methods", "say_hi", "__send__", "equal?", "taint", "frozen?", "instance_variable_get", "kind_of?", "to_a", "hello", "instance_eval", "type", "protected_methods", "extend", "eql?", "display", "instance_variable_set", "hash", "is_a?", "to_s", "class", "tainted?", "private_methods", "untaint", "id", "inspect", "dello", "==", "===", "clone", "public_methods", "respond_to?", "freeze", "__id__", "=~", "methods", "nil?", "dup", "instance_variables", "instance_of?"]
Note that the "hello" method we defined earlier is here•It is inherited from class Object
Inspecting an objectg.inspect or p(g)
SEG4110 - Topic N - Ruby on Rails 17
Dynamic classes
Ruby is a very dynamic language•You can modify a class at any time!•Add new methods, variables, etc.
SEG4110 - Topic N - Ruby on Rails 18
Modules - have some similarities to interfaces
You can achieve multiple inheritance by simply adding “mixin” modules to several classes
module MyModule def func(arg) doSomethingWith arg endend
def myclass include MyModule …end
Modules also provide namespaces
SEG4110 - Topic N - Ruby on Rails 19
Loading modules from files
require (MyModule.rb)
Standard modules already loaded in every Ruby class
Comparable, EnumerableFileTestGC, KernelMathObjectSpace, Precision, Process, Signal
Use notation: X::Y to refer to class X in module Y
SEG4110 - Topic N - Ruby on Rails 20
The Ruby on Rails frameworkMakes it easy to develop web applications•Most manipulate data in a database such as MySQL or Postgres
•Can also manipulate flat files
Integrates with AJAX
Suggested book: Agile Web Development with Rails•By
—Dave Thomas—and David Heinemeier Hansson (creater of Rails)
•Second edition Jan 2007, www.pragprog.com
SEG4110 - Topic N - Ruby on Rails 21
Rails philosophies
Model-View-Controller (MVC)•Separation of the data from the presentation from the control logic
Don’t Repeat Yourself•E.g. define your database structure in just one place
Convention over Configuration•Sensible defaults
Agility•The application can be quickly changed
SEG4110 - Topic N - Ruby on Rails 22
Models MVC
Models•Whatever is shown in the class diagram plus business rules
•The Ruby model and the Database are separated using ORM (Object Relational Mapping)
•Avoids any need to embed SQL code in an application
SEG4110 - Topic N - Ruby on Rails 23
Active Record as the basis for the Model
Database tables map to Rails classes•Rows map to objects
require 'active_record’
# The following is generated from the database and attributes are filled # in from database columnsclass Order < ActiveRecord::Base end
order = Order.find(1)order.discount = 0.5order.save
SEG4110 - Topic N - Ruby on Rails 24
Querying the model in Ruby code
Order.find(:all, :conditions => "name='dave'" ).each do |order| puts order.amountend
SEG4110 - Topic N - Ruby on Rails 25
The View - Three mechanisms
rhtml•Embedded Ruby code in html, using Erb (embedded Ruby)
rxml•Construct XML using Ruby code
rjs•Create javascript in Ruby code to create AJAX applications
•The JavaScript runs in the client, of course
SEG4110 - Topic N - Ruby on Rails 26
The Controller
Routes http requests to Ruby methods•Allows you to create people-friendly URLs
Manages Caching•Database data stored in memory for a speed boost
Manages Sessions•E.g. a shopping session
SEG4110 - Topic N - Ruby on Rails 27
Getting started
You need to install•Ruby•Rails•A database•I leave it to the TA and/or reference manuals to do that
The hard part of application development is now done!!
SEG4110 - Topic N - Ruby on Rails 28
Really getting startedCreate a new empty default application with the commandrails myapplication
This will install directories neededREADME components/ doc/ public/ tmp/Rakefile config/ lib/ script/ vendor/app/ db/ log/ test/
app contains controllers/, models/ and views/
Start the built-in serverruby script/server
SEG4110 - Topic N - Ruby on Rails 29
Here’s what the default application looks like
SEG4110 - Topic N - Ruby on Rails 30
Next step: Add a controller
ruby script/generate controller Airline
This will generate an empty (hook, or stub) class •airline_controller.rb
class AirlineController < ApplicationControllerend
Now let us add a method addflight to the Airline class def addflight end
We would call this from a URL as followshttp://www.mysite.ca/airline/addflight
SEG4110 - Topic N - Ruby on Rails 31
Next step: Add a view using the Erb/rhtml approach
We need a ‘template’ file called addflight.rhtml
<html> <head> <title>Add a flight/title> </head> <body> <h1>Add a flight</h1> <%= AirlineView.addFlightForm %> </body></html>
SEG4110 - Topic N - Ruby on Rails 32
Some things you can embed in rhtml code
Create an href to another ruby action <%= link_to "Airline help", :action => "help" %>
SEG4110 - Topic N - Ruby on Rails 33
We need to actually build a database to go any further
It is possible that the database is already there•But Ruby provides nice facilities for setting up a database incrementally in Ruby code
First create an empty database using your database package•MySQL is the easiest
Next test that Ruby can connectrake db:migrate
SEG4110 - Topic N - Ruby on Rails 34
Creating a simple database
The rule is one table per classruby script/generate model regularflight
You will then find a filedb/migrate/file 001_create_regularflights.rb
class CreateRegularflights < ActiveRecord::Migration def self.up create_table :regularFlights do |t| t.column :number, :integer t.column :departuretime, :string t.column :origin, :string t.column :destination, :string endend
SEG4110 - Topic N - Ruby on Rails 35
Next steps
Make Ruby upgrade the databaserake db:migrate
Now create a controller adminruby script/generate controller admin
And edit app/controllers/admin_controller.rbclass AdminController < ApplicationControllerscaffold :regularflightend
Go to http://www.mysite.ca/airline/adminAnd you will see a page where you can add flights
SEG4110 - Topic N - Ruby on Rails 36
Making Ruby upgrade the database:Adding a new column
class AddPrice < ActiveRecord::Migration def self.up add_column :products, :price, :decimal, :precision => 8, :scale => 2, :default => 0 end
def self.down remove_column :products, :price end
end
SEG4110 - Topic N - Ruby on Rails 37
Ruby on Rails’ naming
If you have a table called People, RoR will generate a class called Person and vice-versa
Other transformations:•Specific_flights <-> SpecificFlight•Person_roles <-> PersonRole
SEG4110 - Topic N - Ruby on Rails 38
Enhancing model classes
When we create a new class/table the model code for the class is empty:
class Product < ActiveRecord::Baseend
SEG4110 - Topic N - Ruby on Rails 39
Validation
If we want to force certain data to be present
class Product < ActiveRecord::Base
validates_presence_of :title, :description, :image_url
end
The generated web page for adding products will automatically ensure this data is filled in•Fields with errors are highlighted•Errors are summarized at the top of the form
SEG4110 - Topic N - Ruby on Rails 40
Example generated web page
SEG4110 - Topic N - Ruby on Rails 41
Other validationsvalidates_numericality_of :price
validates_uniqueness_of :title
def validate errors.add(:price, "should be at least 0.01" ) if price.nil? || price < 0.01end
validates_format_of :image_url, :with => %r{\.(gif|jpg|png)$}i, :message => "must be a URL for a GIF, JPG, or PNG image"
SEG4110 - Topic N - Ruby on Rails 42
Class methods in the model to return a set of instances
class Product < ActiveRecord::Base # The self. Means it is a class (static) method def self.find_products_for_sale find(:all, :order => "title" ) end# validation stuff...end
SEG4110 - Topic N - Ruby on Rails 43
Specifying associations in model classesclass Order < ActiveRecord::Base has_many :line_items …end
class Product < ActiveRecord::Base has_many :line_items has_many :orders, :through => :line_items …end
class LineItem < ActiveRecord::Base belongs_to :order belongs_to :product …end
SEG4110 - Topic N - Ruby on Rails 44
Generating automatic documentationrake doc:app
rake stats(in /Users/dave/Work/depot)+----------------------+-------+-------+---------+---------+-----+-------+| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |+----------------------+-------+-------+---------+---------+-----+-------+| Helpers | 17 | 15 | 0 | 1 | 0 | 13 || Controllers | 229 | 154 | 5 | 23 | 4 | 4 || Components | 0 | 0 | 0 | 0 | 0 | 0 || Functional tests | 206 | 141 | 8 | 25 | 3 | 3 || Models | 261 | 130 | 6 | 18 | 3 | 5 || Unit tests | 178 | 120 | 5 | 13 | 2 | 7 || Libraries | 0 | 0 | 0 | 0 | 0 | 0 || Integration tests | 192 | 130 | 2 | 10 | 5 | 11 |+----------------------+-------+-------+---------+---------+-----+-------+| Total | 1083 | 690 | 26 | 90 | 3 | 5 |+----------------------+-------+-------+---------+---------+-----+-------+Code LOC: 299 Test LOC: 391 Code to Test Ratio: 1:1.3
SEG4110 - Topic N - Ruby on Rails 45
Automatic testing in RoR
Unit tests - test the model•In test/unit
Functional tests - test a controller action•In test/functional
Integration tests - test flow through the system•In test/integration
SEG4110 - Topic N - Ruby on Rails 46
Sample initially generated test for Product
require File.dirname(__FILE__) + '/../test_helper'class ProductTest < Test::Unit::TestCase #load test data fixtures :products def test_truth assert true endend
SEG4110 - Topic N - Ruby on Rails 47
A test to verify that an empty product is not valid and that empty variables are invalid
def test_invalid_with_empty_attributes product = Product.new assert !product.valid? assert product.errors.invalid?(:title) assert product.errors.invalid?(:description) assert product.errors.invalid?(:price) assert product.errors.invalid?(:image_url)end
SEG4110 - Topic N - Ruby on Rails 48
Checking some other propertiesdef test_positive_price product = Product.new(:title => "My Book Title" , :description => "yyy" , :image_url => "zzz.jpg" ) product.price = -1 assert !product.valid? assert_equal "should be at least 0.01" , product.errors.on(:price)
product.price = 0 assert !product.valid? assert_equal "should be at least 0.01" , product.errors.on(:price)
product.price = 1 assert product.valid?end