Ch04 Rails
Ch04 Rails
1
Today’s Concept Outline
• Quick whirlwind tour of Rails
• ActiveRecord for persisting app data
• ActiveRecord models as resources, and
resource-oriented routes to manipulate them
• Rails tour revisited, putting concepts into
context
• Comparison of concepts & mechanisms in
Rails vs. Sinatra
2
Hello Rails :
from Zero to CRUD
(Engineering Software as a Service §4.1)
Armando Fox
Client: Firefox
A trip through a Rails app
1. Routes (in routes.rb) map incoming URL’s to controller
actions and extract any optional parameters
– Route’s “wildcard” parameters (eg :id), plus any stuff after “?” in URL,
are put into params[] hash accessible in controller actions
2. Controller actions set instance variables, visible to views
– Subdirs and filenames of views/ match controllers & action names
3. Controller action eventually renders a view
app/controllers/movies_controller.rb app/views/movies/show.html.haml
10
11
In-Memory vs. In-Storage
objects
#<Movie:0x1295580>
m.name, m.rating, ... marshal/serialize
#<Movie:0x32ffe416> unmarshal/deserialize ?
m.name, m.rating, ...
• How to represent persisted object in storage
– Example: Movie with name & rating attributes
• Basic operations on object: CRUD (Create,
Read, Update, Delete)
• ActiveRecord: every model knows how to
CRUD itself, using common mechanisms
12
Rails Models Store Data in
Relational Databases (RDBMS)
• Each type of model gets its own database table
– All rows in table have identical structure
– one row in table == one instance of model’s class
– Each column stores value of an attribute of the model
– Each row has unique value for primary key (by
convention, in Rails this is an integer and is called id)
id rating title release_date
2 G Gone With the Wind 1939-12-15
11 PG Casablanca 1942-11-26
... ... ... ...
35 PG Star Wars 1977-05-25
☐ def silly_fortune_1
@fortune_text + 'in bed'
end
def silly_fortune_2
☐ self.fortune_text + 'in bed'
end
def silly_fortune_3
☐ fortune_text + 'in bed'
end
☐ They will all return a silly fortune
17
Alternative: DataMapper
• Data Mapper associates separate mapper with
each model
– Idea: keep mapping independent of particular data store
used => works with more types of databases
– Used by Google AppEngine
– Con: can’t exploit
RDBMS features to
simplify complex
queries & relationships
• We’ll revisit when
talking about
associations
18
cut
19
RESTful Resource Routes
in Rails
23
CRUD on a RESTful resource:
resources :movies
get '/movies' => 'movies#index', :as => 'movies'
get '/movies/:id/new'=>'movies#new', :as=>'new_movie'
post '/movies' => 'movies#create', :as => 'movie'
get '/movies/:id' => 'movies#show', :as => 'movie'
get '/movies/:id/edit' => 'movies#edit', :as => 'edit_movie'
put '/movies/:id'=>'movies#update', :as=>'movie'
delete '/movies/:id' => 'movies#destroy', :as=>'movie'
form_for movie_path(5)
<form action="/movies/5" method="post">
form_for movie_path(5), :method => :put
<form action="/movies/5" method="post">
<input type="hidden" name="_method" value="put"> ...
link_to 'Edit', edit_movie_path(5)
<a href="/movies/5/edit">Edit</a>
link_to 'List All', movies_path
<a href="/movies">List All</a> 24
Demo: rake routes
25
Which statement is NOT true regarding
Rails RESTful routes and the
resources to which they refer:
Armando Fox
29
Multiple environments,
multiple databases
• Rails solution: development, production and
test environments each have own DB
– Different DB types appropriate for each!
• How to make changes to DB, since will have
to repeat changes on production DB?
• Rails solution: migration—script describing
changes, portable across DB types
Migration Advantages
• Can identify each migration, and know
which one(s) applied and when
– Many migrations can be created to be reversible
• Can manage with version control
• Automated == reliably repeatable
34
Based on what you’ve seen of Rails, what kind of
object is likely being yielded in the migration code:
def up
create_table 'movies' do |t|
t.datetime 'release_date' ...
end
end
35
cut
36
Models: Finding, Updating,
Deleting
(Engineering Software as a Service §4.3)
Armando Fox
old_kids_films =
kiddie.where("release_date < ?",30.years.ago)
Update: 2 ways
• Let m=Movie.where(title: 'The Help')
• Modify attributes, then save object
m.release_date='2011-Aug-10'
m.save!
• Update attributes on existing object
m.update_attributes(
release_date: '2011-Aug-10')
42
cut
43
Controllers & Views
(Engineering Software as a Service §4.4)
Armando Fox
link_to movie_path(3)
def show
index. @movie =
html.
<a href="/movies/3">...</a> Movie.find(params[:id])
haml
end
GET /movies/:id
{:action=>"show", :controller=>"movies"}
params[:id]ç3
What else can we do?
• How about letting user return to movie list?
• RESTful URI helper to the rescue again:
• movies_path with no arguments links to Index
action
=link_to 'Back to List', movies_path
49
cut
50
When things go wrong:
Debugging
(Engineering Software as a Service §4.5)
Armando Fox
Armando Fox
☐ = form_tag movies_path do
... end
☐ %form{:action => movies_path,
:method => :post}
☐ %form{:action => '/movies',
:method => 'post'}
☐ All of the above
65
cut
66
Microquiz
goo.gl/NqkrBW
bit.ly/CS169-quiz4
cut
68
Redirection, the Flash and the
Session
(Engineering Software as a Service §4.7)
Armando Fox
74
cut
75
Finishing CRUD
(Engineering Software as a Service §4.8)
Armando Fox
def destroy
@movie = Movie.find(params[:id])
@movie.destroy
flash[:notice] =
"Movie '#{@movie.title}' deleted."
redirect_to movies_path
end
If you set an instance variable in a
controller method, its value will be
retained for how long?
79
cut
80
Summary & Reflections:
SaaS Architecture,
Rails, From Sinatra to Rails
(Engineering Software as a Service
§2.9-2.10, 4.11)
Armando Fox
config /routes.rb
/database.yml
db /development.sqlite3
/test.sqlite3
/migrate/
log /development.log, test.log
Pitfall: Fat controllers &
code in your views
• Really easy to fall into “fat controllers” trap
– Controller is first place touched in your code
– Temptation: start coding in controller method
• Fat views
– “All I need is this for-loop.”
– “....and this extra code to sort the list of movies
differently.”
– “...and this conditional, in case user is not
logged in.”
• No! That’s for model, controller, helpers
Code Clinic part 2
Where, for the love of God,
should you not put code?
☐ Controllers
☐ Controllers
☐ Controllers
☐ Controllers
85
SIMPLIFY YOUR CONTROLLERS
90
Which steps are ALWAYS required when adding a
new action 'foo' to the Movie model of a Rails app:
(a) Ensure there is a template to render in app/
views/movies/foo.html.haml (or .html.erb, etc)
(b) Ensure a route exists in config/routes.rb
(c) Implement helper method to generate
necessary route-helper URIs
☐ Only (b)
91
cut
92