rails - appalachian state universitycan/classes/5530/slides/rails.pdf · rails 1 rails web...
TRANSCRIPT
Rails 1
Rails● web application framework that uses Ruby as
its programming language● builds skeleton applications for you
– applications come with lots of defaults which you can use as is or change as desired
– no XML required like in other frameworks● follows Model-View-Controller Architecture
Rails 2
Model-View-Controller Architecture
Browser Controller
Model
ActionView
User enters URL in Browser; server decodes the URL and sends request to controllerController passes request onto appropriate action which may interact with the modelView displays the result of the action
Rails 3
The Controller ● Supervises the entire application, handling
requests as needed http://localhost:3000/hello/therehello controller decodes the URL to know that there
action is requestedController application would look like:class HelloController < ApplicationController def there endend
● ApplicationController inherits from ActionController::Base class
Rails 4
The View● responsible for displaying the results of an
action● typically, action and model pass data onto the
view● views interact with the user and may display
text fields, text areas, check boxes, radio buttons, etc. When a submit button is clicked, data is passed to the controller which hands it to an action which passes it to a view
● views supported with the Rails ActionView module
Rails 5
The Model● handles the data processing that takes place in
the web application – including number crunching and database accesses
● completely separate from the web application (independent of its use)
● typically, data passed to the model via the action which then retrieves the result
● support for the model code is provided by the Rails ActiveRecord module
Rails 6
Documentation● enter the command: gem_server● use browser to open up page at:
http://localhost:8808
Rails 7
Creating application framework● At Ruby console prompt type:rails applicationName● creates multiple directories and files● README file in the applicationName directory
contains a description of Rails and the directories that are created
Rails 8
Application Directories● app - Holds all the code that's specific to this particular
application.● app/controllers - Holds controllers that should be
named like weblogs_controller.rb for automated URL mapping. All controllers should descend from ApplicationController which itself descends from ActionController::Base.
● app/models - Holds models that should be named like post.rb. Most models will descend from ActiveRecord::Base.
Rails 9
Application Directories● app/views - Holds the template files for the view that
should be named like weblogs/index.rhtml for the WeblogsController#index action. All views use eRuby syntax.
● app/views/layouts - Holds the template files for layouts to be used with views. This models the common header/footer method of wrapping views. In your views, define a layout using the <tt>layout :default</tt> and create a file named default.rhtml. Inside default.rhtml, call <% yield %> to render the view using this layout.
Rails 10
Application Directories● app/helpers - Holds view helpers that should be
named like weblogs_helper.rb. These are generated for you automatically when using script/generate for controllers. Helpers can be used to wrap functionality for your views into methods.
● config - Configuration files for the Rails environment, the routing map, the database, and other dependencies.
● components - Self-contained mini-applications that can bundle together controllers, models, and views.
Rails 11
Application Directories● db - Contains the database schema in schema.rb.
db/migrate contains all the sequence of Migrations for your schema.
● doc - This directory is where your application documentation will be stored when generated using <tt>rake doc:app</tt>
● lib - Application specific libraries. Basically, any kind of custom code that doesn't belong under controllers, models, or helpers. This directory is in the load path.
Rails 12
Application Directories● public- The directory available for the web server.
Contains subdirectories for images, stylesheets, and javascripts. Also contains the dispatchers and the default HTML files. This should be set as the DOCUMENT_ROOT of your web server.
● script - Helper scripts for automation and generation.● test - Unit and functional tests along with fixtures.
When using the script/generate scripts, template test files will be generated for you and placed in this directory.
Rails 13
Application Directories● vendor - External libraries that the application depends
on. Also includes the plugins subdirectory. This directory is in the load path.
Rails 14
To view application● Within applicationName directory at the Ruby
console prompt type:ruby script/server● This starts the WEBrick or Mongrel server that
comes with rails● To view the application home page, openhttp://localhost:3000/● Initially, this is just the default Rails page
available in public/index.html
Rails 15
Rails 16
Creating a controller● To create the controller (within new application
directory)ruby script/generate controller controllerName ● This creates three directories:
– app/controllers/controllerName_controller.rb– test/functional/controllerName_controller_test.rb– app/helpers/controllerName_helper.rb
Rails 17
Example● Want to create a web application that prompts a
user for two numbers (in a view)● The two numbers will be summed together
using a model● The result is displayed in another view
Rails 18
First create the application and controller
● create rails application called Addrails Add
● go into Add directory and create an Add controllercd Addruby script/generate controller Add
Rails 19
Add an index and sum actions to my controller
class AddController < ApplicationController def index end def sum #form data is in the params hash (no matter whether #GET or POST is used), indexed by #symbol for name value in form @num1 = params[:num1].to_i @num2 = params[:num2].to_i #use the model @summer = Summer.new @result = @summer.sum(@num1, @num2) endend
This is in Add/app/controllers/add_controller.rb
Rails 20
Create an index.rhtml view that is displayed in response to index
action
<html><head><title>Adding two numbers</title></head><body><% form_tag({:action => "sum"}, {:method => "post"}) do %>Please enter first number.<%= text_field_tag("num1", "", {"size" => 30}) %> <br />Please enter second number.<%= text_field_tag("num2", "", {"size" => 30}) %> <br /><%= submit_tag "submit" %><% end %></body></html>
This is in Add/app/views/add/index.rhtml
Rails 21
Create a Summer model to do the sum
This is in Add/app/models/summer.rbclass Summer def sum(val1, val2) val1 + val2 endend
Rails 22
Create a sum.rhtml that displays result
<html><head><title>Result of Sum</title></head><body><b>The sum of <%= @num1 %> and <%= @num2 %> is<%= @result %>.</b></body></html>
This is in Add/app/views/sum.rhtml
Rails 23
Displaying the application● Start webrick or mongrel server (from within
Sum/app)ruby server/script
● Open up applicationhttp://localhost:3000/addThis executes the default action (index) and displays
the default page (index.rhtml)● Fill out form and click submit
This executes the sum action (which uses the model) and displays sum.rhtml
Rails 24
● pages that end with a .rhtml extension can have Ruby code embedded within
● .rhtml pages are processed by an Embedded Ruby processor (ERb) which handles the ruby code and generates an HTML
● Ruby code must be contained within– <%= ... %> display result of the embedded ruby– <% ... %> don't display result– <%# %> comment
Embedded Ruby
Rails 25
Embedded Ruby● puts <% puts “in foo function” %>
– can be used to output stuff to the console (where WEBrick is running)
– not for outputting to web page (even within <%= %>)
– useful for debugging● h <%= h(10 < 20) %>
– h method converts sensitive characters into HTML entity equivalents
Rails 26
Rails Shortcuts● text_field_tag(name, value = nil, options = {})
– creates an input tag with:● type = “text”● name = name● default value displayed is value parameter● options is a hash where keys can be “disabled”, “size”,
and “maxlength”● Example:<%= text_field_tag("num1", "", {"size" => 30}) %>
Rails 27
Rails Shortcuts● check_box_tag● select_tag● form_tag (deprecated start_form_tag,
end_form_tag)● submit_tag● radio_button_tagInfo about these and much more found at:http://api.rubyonrails.com/
Rails 28
Invoking action from a form
<form action=”\Look\at” >● Pressing submit will cause
– at method within Look controller to be executed– then (by default) at.rhtml view to be displayed
Rails 29
Reading data from form● data from form accessible via the params hash
(no matter whether get or post used)● access data by passing the symbol :namevalue
to the params hash● Example
– Form:<input type=”text” name=”addr” size=”50”>– Ruby@address = params[:addr]
Rails 30
Selecting a view to render● By default, after at action is executed, at view is
displayed● render function can be used to display a
different view– from within actionrender(:action => :lunch)– this causes the view associated with the lunch
action to be displayed; it doesn't cause the lunch action to be executed
Rails 31
Example● want an application that prompts for two
numbers and an operation (addition or subtraction)
● depending upon what operation is selected, an add or sub view is displayed
● First,rails Compute1ruby script/generate controller compute
Rails 32
Compute controllerclass ComputeController < ApplicationController def index end def compute #form data is in the params hash (no matter whether #GET or POST is used), indexed by #symbol for name value in form @num1 = params[:num1].to_i @num2 = params[:num2].to_i @op = params[:op] if (@op == '+') @result = @num1 + @num2 render(:action => :add) else @result = @num1 - @num2 render(:action => :sub) end end def add end def sub endend
found in: Compute1/app/controllers/compute_controller.rb
Rails 33
index.rhtml displayed in response to index action
<html><head><title>Adding two numbers</title></head><body><% form_tag({:action => "compute"}, {:method => "post"})do %>Please enter first number.<%= text_field_tag("num1", "", {"size" => 30}) %> <br />Please enter second number.<%= text_field_tag("num2", "", {"size" => 30}) %> <br />+<%= radio_button_tag("op", "+", true, {}) %> <br />-<%= radio_button_tag("op", "-", false, {}) %> <br /><%= submit_tag "submit" %> <% end %></body></html>
found in: Compute1/app/views/compute/index.rhtml
Rails 34
add.rhtml and sub.rhtml<html><head> <title>Result of addition</title></head><body><b> <%= @num1 %> plus <%= @num2 %> is <%= @result %></b></body></html>
<html><head> <title>Result of subtraction</title></head><body><b> <%= @num1 %> minus <%= @num2 %> is <%= @result %></b></body></html>
found in: Compute1/app/views/compute/add.rhtml
found in: Compute1/app/views/compute/sub.rhtml
Rails 35
Request of compute performs default index action and displays defaultindex.rhtml view
Rails 36
Notice name of action is compute, not add
Rails 37
redirect_to● render is used to display a view associated with
an action, but without causing the associated action to be executed
● unlike render, redirect_to displays a different view after first executing the associated action
● specifically, redirect_to causes browser to invoke a different URLrender(:action => :add) -- display add.rhtmlredirect_to(:action => :add) – execute add action and
then display add.rhtml
Rails 38
Exampleclass ComputeController < ApplicationController def index end def compute @num1 = params[:num1] @num2 = params[:num2] @op = params[:op] if (@op == '+') #notice parameters to add action redirect_to(:action => :add, :num1 => @num1, :num2 => @num2) else redirect_to(:action => :sub, :num1 => @num1, :num2 => @num2) end end def add @num1 = params[:num1].to_i @num2 = params[:num2].to_i @result = @num1 + @num2 end def sub @num1 = params[:num1].to_i @num2 = params[:num2].to_i @result = @num1 - @num2 endend
Rails 39
Rails 40
Notice action is add, not compute
Rails 41
Rendering any template ● can render any template, not just those
associated with an action● notice last example required add and sub
actions even though they weren't executed when rendering the view
● can render any template by using render with file key – key value is full path to the template
Rails 42
Exampleclass ComputeController < ApplicationController def index end def compute #form data is in the params hash (no matter whether #GET or POST is used), indexed by #symbol for name value in form @num1 = params[:num1].to_i @num2 = params[:num2].to_i @op = params[:op] if (@op == '+') @result = @num1 + @num2 render(:file => 'C:\Users\Public\Downloads\InstantRails-1.7-win\InstantRails\rails_apps\Compute2\app\views\compute\add.rhtml') else @result = @num1 - @num2 render(:file => 'C:\Users\Public\Downloads\InstantRails-1.7-win\InstantRails\rails_apps\Compute2\app\views\compute\sub.rhtml') end endend
Notice there are no add and sub actions
Rails 43
add.rhtml
<html><head> <title>Result of addition</title></head><body><b> <%= @num1 %> plus <%= @num2 %> is <%= @result %></b></body></html>
Exactly the same as in earlier example, but there is no actionassociated with it
Rails 44
Rails 45
Notice that the action is still compute even though a different view was displayed
Rails 46
Linking to another action
● rails link_to method creates a hyperlink● clicking on link will causes the action to be
executed and the associated view to be displayed
<%= link_to “Go to lunch.”, :action => “lunch” %>clicking causes lunch action to occur and (unless
changed by action) lunch.rhtml template to be displayed
Rails 47
Using a layout● Often we want the pages in a website to have a
common look● In rails we can capture the common look by
creating a layout● The layout can then display a specific view by
including the view's template● layouts are controller-specific
– layout for controller Look would be in the file Look/app/views/layouts/look.rhtml
Rails 48
Example using link_to and a layout● Create the application
rails Poetry● Create the controller
ruby script/generate controller Poetry● Create a layout and place in the file:
Poetry/app/views/layouts/poetry.rhtml● Create templates for specific views: index.rhtml,
hope.rhtml, eclipse.rhtml● Controller has index, hope and eclipse actions
Rails 49
My poetry.rhtml layout<html><head><title>Best Poetry</title><%= stylesheet_link_tag 'poetry.css' %></head><body><div id="heading"><%= @heading %></div><%= @content_for_layout %><% if controller.action_name != "index" %><%= link_to "Back To List", :action => "index" %><% end %></body></html>The value of @content_for_layout is a template...which templatedepends upon the action.
Rails 50
Stylesheet poetry.cssbody {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;font-size: 13px;line-height: 18px;background-color: #eee;}#heading {font-family: "Arial Rounded MT Bold";font-size: 20px;}
You can name the stylesheet anything you like, but itmust be in the directory: Poetry/public/stylesheets
Rails 51
index.rhtml
<p><%= link_to "The Eclipse", :action => "eclipse" %><br /><%= link_to "Hope", :action => "hope" %></p>
Clicking on the link displayed will cause the action to be executed and the associated view to be displayed
Rails 52
hope.rhtml<p>Hope is the thing with feathers<br />That perches in the soul,<br />And sings the tune without the words,<br />And never stops at all, <br /></p><p>Hope is the thing with feathers <br />That perches in the soul,<br />And sings the tune without the words,<br />And never stops at all, <br /></p><p>Hope is the thing with feathers<br />That perches in the soul,<br />And sings the tune without the words,<br />And never stops at all, <br /></p>
Rails 53
eclipse.rhtml<p>I stood out in the open cold<br />To see the essence of the eclipse<br />Which was its perfect darkness. <br /></p><p>I stood in the cold on the porch<br />And could not think of anything so perfect<br />As mans hope of light in the face of darkness.<br /></p>
Rails 54
poetry_controller.rb
class PoetryController < ApplicationController def index @heading = "My Favorite Poems" end def eclipse @heading = "The Eclipse, by Richard Eberhart" end def hope @heading = "Hope is the Thing, by Emily Dickinson" endend
Note that the @heading variable is referenced in the layout
Rails 55
Rails 56
Rails 57
Working with multiple controllers● Often we want to break up our website into
separate parts that can be developed in isolation; for example: login utility, slide show builder, slide show displayer
● In Rails, we do this by creating multiple controllers
● We can execute the action of another controller by specifying both controller and actionredirect_to :controller => :categories, :action => :listlink_to 'List', {:controller => :categories, :action => :list}
Rails 58
Sessions● Rails session is a hash that persists across
requests● session can be used to store any object (for
example, a shopping cart)● Rails causes a session id to be stored in a
cookie on the browser; actual session data is stored on the server
● After 15 minutes of inactivity, session data is erased
Rails 59
Flash● flash is another hash that acts as a temporary
scratch pad for value● data can be stored in flash via the processing of
one request and is removed from flash at the end of handling the next request
● flash is very useful for displaying error messages or other comments
Rails 60
Example with two controllers, a session and flash
● one controller handles logging in● second controller would allow the user to do
“stuff”● session used to make sure user doesn't bypass
logging in before doing stuff● flash used to display error message
Rails 61
The steps● Create the Rails app
rails Session● Create the two controllers
ruby script/generate controller Loginruby script/generate controller Dostuff
Rails 62
Login files● Sessions/app/controllers/login_controller.rb● Sessions/app/views/layouts/login.rhtml● Sessions/app/views/login/index.rhtml● Sessions/public/stylesheets/login.css
Rails 63
login_controller.rbclass LoginController < ApplicationController def index @title = 'Login Page' end def login @password = params[:password] @email = params[:email] #Here is where you would verify the email address #and password (better than what I am doing) valid = true valid = false if @password == "" valid = false if @email == "" if (valid == true) session[:email] = @email redirect_to :controller => :dostuff, :action => :index else reset_session flash[:notice] = 'Invalid email address and password' redirect_to :action => :index end endend
Rails 64
login.rhtml – the layout file
<html><head><title><%= @title %></title><%= stylesheet_link_tag 'login' %></head><body><%= @content_for_layout %><% if flash[:notice] %><div id="notice"><%= flash[:notice] %></div><% end %></body></html>
Rails 65
login/index.rhtml
<% form_tag({ :action => "login"}, {:method => "post"})do %>Email Address:<%= text_field_tag("email", "", {"size" => 30}) %> <br />Password:<%= password_field_tag("password", "", {"size" => 30}) %> <br /><%= submit_tag "login" %><% end %>
Rails 66
DoStuff files● Sessions/app/controllers/dostuff_controller.rb● Sessions/app/views/layouts/dostuff.rhtml● Sessions/app/views/dostuff/index.rhtml● Sessions/public/stylesheets/dostuff.css
Rails 67
dostuff_controller.rb
class DostuffController < ApplicationController def index @title = 'Welcome User' if (!session[:email]) #user is not logged on redirect_to :controller=>:login, :action=>:index end endend
Rails 68
dostuff.rhtml – the layout file
<html><head><title><%= @title %></title><%= stylesheet_link_tag 'dostuff' %></head><body><%= @content_for_layout %></body></html>
Rails 69
dostuff/index.rhtml<%# index.rhtml for Dostuff controller %><p>You are logged on. Now you can do important stuff like<br />modify your blog, update your account info, or whatever<br />is appropriate for your application.</p>
Rails 70
If the user tries to skip this page and instead open uphttp://localhost:3000/login, then the lack of a session willcause control to be sent back to this action.
Also, if the clicks on login without entering email or password,then control is sent back to this action.
Rails 71
Rails 72
Rails Scaffold utility● scaffold utility is used to build a framework for
database applications● scaffold generates the code necessary to
access and add to the database (rails automatically generates the mysql)
● scaffold also generated the interface that supports modifying the database or list the contents
Rails 73
Simple store example● Create the application
rails Store● Create the database (table name needs to be
lower case and plural; also needs auto_increment id): CREATE TABLE `items` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` VARCHAR( 80 ) NOT NULL , `description` TEXT NOT NULL , `price` DECIMAL NOT NULL);
Rails 74
Simple store example
modify the /Store/config/database.yml file, if necessary
development: adapter: mysql database: store username: root password: host: localhostIf you use the rake utility, you'll want three dbs: one for
development, one for testing and one for production● Next, we'll need to create a controller and a model, but first
...
Rails 75
Naming the Model● database table name needs to be lowercase
and plural● mode name should be same except singular
and initial letter capped– database table: items– model: Item
● If database table name has underscores, model name should be equivalent camel case– database table: store_items– model: StoreItem
Rails 76
Naming the Controller● can choose name you like● rails will create NameController class which
inherits from ApplicationController for a controller named Name
● scaffold utility will stock this controller with code
Rails 77
Simple store example● Create the controller and the model
ruby script/generate scaffold Item Manage● Start up the server
ruby script/server● Open up browser and see what was created
http://localhost:3000/store
Rails 78
Index action – db initially empty
Rails 79
New action-- from New Itemlink on index
Rails 80
List action (after new action)
Rails 81
Show action
Rails 82
Edit action
Rails 83
Index action again – db not empty
Rails 84
class ManageController < ApplicationController def index list render :action => 'list' end verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list } def list @item_pages, @items = paginate :items, :per_page => 10 end def show @item = Item.find(params[:id]) end
def new @item = Item.new end
Manage Controller (next two slides)
Rails 85
def create @item = Item.new(params[:item]) if @item.save flash[:notice] = 'Item was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end
def edit @item = Item.find(params[:id]) end
def update @item = Item.find(params[:id]) if @item.update_attributes(params[:item]) flash[:notice] = 'Item was successfully updated.' redirect_to :action => 'show', :id => @item else render :action => 'edit' end end
def destroy Item.find(params[:id]).destroy redirect_to :action => 'list' endend
Rails 86
About the controller code● verify method
– used to verify that certain conditions are met before action is attempted
– In this case for actions destroy, update, create, only the post method can be used to send data to the server; if verification fails, list action performed
● paginate method– returns a paginator object and the first page of
items to be displayed@item_pages, @items = paginate :items, :per_page => 10
Rails 87
The layout - manage.rhtml<!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>Manage: <%= controller.action_name %></title> <%= stylesheet_link_tag 'scaffold' %></head><body><p style="color: green"><%= flash[:notice] %></p>
<%= yield %></body></html>
Rails 88
About the layout● <%= yield %> does the same thing as <%=
@content_for_layout %>– causes the display of a particular view
Rails 89
_form.html<%= error_messages_for 'item' %><!--[form:item]--><p><label for="item_name">Name</label><br/><%= text_field 'item', 'name' %></p><p><label for="item_description">Description</label><br/><%= text_area 'item', 'description' %></p><p><label for="item_price">Price</label><br/><%= text_field 'item', 'price' %></p><!--[eoform:item]-->
Rails 90
about _form.rhtml● _form.rhtml is a chunk of a view● not associated with a particular action, they can
be rendered explicitly by another view or controller
● they can be passed parameters so that the results can be different with each rendering
Rails 91
edit.rhtml
<h1>Editing item</h1><% form_tag :action => 'update', :id => @item do %> <%= render :partial => 'form' %> <%= submit_tag 'Edit' %><% end %><%= link_to 'Show', :action => 'show', :id => @item %> |<%= link_to 'Back', :action => 'list' %>
here is where the partial _form.rhtml gets rendered
Rails 92
list.rhtml<h1>Listing items</h1>
<table> <tr> <% for column in Item.content_columns %> <th><%= column.human_name %></th> <% end %> </tr> <% for item in @items %> <tr> <% for column in Item.content_columns %> <td><%=h item.send(column.name) %></td> <% end %> <td><%= link_to 'Show', :action => 'show', :id => item %></td> <td><%= link_to 'Edit', :action => 'edit', :id => item %></td> <td><%= link_to 'Destroy', { :action => 'destroy', :id => item }, :confirm => 'Are you sure?', :method => :post %></td> </tr><% end %></table>
<%= link_to 'Previous page', { :page => @item_pages.current.previous } if @item_pages.current.previous %><%= link_to 'Next page', { :page => @item_pages.current.next } if @item_pages.current.next %>
<br />
<%= link_to 'New item', :action => 'new' %>
Rails 93
About list.rhtml● Notice that @items is the array of items created
by the call to paginate● @item_pages is the paginator object that can
be used to display another page of items
Rails 94
new.rhtml
<h1>New item</h1><% form_tag :action => 'create' do %> <%= render :partial => 'form' %> <%= submit_tag "Create" %><% end %><%= link_to 'Back', :action => 'list' %>
Rails 95
show.rhtml<% for column in Item.content_columns %><p> <b><%= column.human_name %>:</b> <%=h @item.send(column.name) %></p><% end %><%= link_to 'Edit', :action => 'edit', :id => @item %> |<%= link_to 'Back', :action => 'list' %>
Rails 96
About show.rhtml● uses model Item to get each cell of the selected
row● Item.content_columns returns the list of
columns (excluding the id column)● @item is the parameter to show.rhtml (see
show in controller class)● send method used to access the value of a
specific column
Rails 97
Finally the model -- item.rbclass Item < ActiveRecord::Baseend
Where's the code for accessing the items table?It is inherited from the parent class ActiveRecord::Base
Rails 98
Scaffold utility● Besides views, controller and model:
– stylesheet– testing frameworkwere also created
Rails 99
What these slides don't cover● Lots, of course, but especially
– rake ● Ruby make utility● can be used to perform database migrations
– testing● Rails creates tests and test directories (unit tests for
models, functional tests for controllers and integration tests for multiple controls
– Rails and Ajax