ppt - CS Course Webpages

DRYing Out MVC
(ESaaS §5.1)
© 2013 Armando Fox & David Patterson, all rights reserved
Don’t Repeat Yourself – But How?
• Goal: enforce that movie names must be
less than 40 characters
– Call a “check” function from every place in app
where a Movie might get created or edited?
That’s not DRY!
• How do we DRY out cross-cutting concerns:
Logically centralized, but may appear
multiple places in implementation?
Background & History:
GO TO & COME FROM
• CACM, 1968 Letter to Editor
Aspect-Oriented Programming
• Advice is a specific piece of code that
implements a cross-cutting concern
• Pointcuts are the places you want to “inject”
advice at runtime
• Advice+Pointcut = Aspect
• Goal: DRY out your code
Rails Example: Validations
• Specify declaratively in model class
http://pastebin.com/2GtWshSb
• Validation is advice in AOP sense
– Many places in app where a model could be
modified/updated
– Including indirectly via associations!
– Don’t want model validation code in all these
places
• So where are the pointcuts?
Model Lifecycle Callbacks
Allows Pre and Post Operations
movie.create
movie.update_attributes
movie.save (new record)
movie.save (existing record)
before_validation
before_validation
before_validation_on_create
before_validation_on_update
Run validations
Run validations
movie.
rb
after_validation
after_validation
after_validation_on_create
after_validation_on_update
before_save
before_save
before_create
before_update
INSERT INTO
movies...
Validation
automatically
happens here
UPDATE
movies...
after_create
after_update
after_save
after_save
• or when you call
valid?
• if fail, save will fail
model.errors is an
ActiveRecord::Errors
object with cool
behaviors of its own
• See Screencast 7.1.1
Example: Controller Filters
• Filters declared in a controller also apply to
http://pastebin.com/ybP6Ece1
its subclasses
– Corollary: filters in ApplicationController
apply to all controllers
• A filter can change the flow of execution
– by calling redirect_to or render
– You should add something to the flash to
explain to the user what happened, otherwise it
will manifest as a “silent failure”
Validations vs. Filters
Validation
Filter
Advice (DRYness)
Check invariants on
model
Check conditions for
allowing controller
action to run
Pointcut
AR model lifecycle hooks
Before and/or after any
public controller
method
Can change
execution flow?
No
Yes
Can define advice in Yes; shortcuts provided
arbitrary function?
for common cases
Yes, must provide
function
Info about errors?
Capture in flash[],
session[], or instance
variable
Each model object has
associated errors object
Con: Can make code harder to debug
10
Single Sign-On and
Third-Party Authentication
(ESaaS §5.2)
© 2013 Armando Fox & David Patterson, all rights reserved
Third-Party Authentication
• Goal: What are my Facebook friends
reading on the NY Times site?
• NY Times needs to be able to
access your Facebook info
• …but you don’t want to reveal your
Facebook password to NY Times!
• How can we do this?
=> Third-party authentication
Logos shown for educational purposes only and are the intellectual property of their owners.
How Does It Work? (Concepts)
• Building block: tamper-evident secure token
• Using cryptography, I create a string that:
– Only I can decrypt (decode)
– I can detect if it’s been tampered with
– No one else could have created it without
knowing my secret key
• Usually, string just contains a “handle” to
valuable info that I store myself
– Receive string => I know I can “trust” the
handle
Third-Party Authentication with
Twitter & RottenPotatoes
1. “Login with
Twitter”
2. Redirect to
Twitter login
page
3. “OK to
authorize this
app?”
Logos shown for educational purposes only and are the intellectual property of their owners.
Third-Party Authentication with
Twitter & RottenPotatoes
4. Yes, please
give away my
personal info
7. “Welcome,
Armando”
5. Redirect to RP
callback page with
access token
6. Here’s a token that
proves I’m allowed to
know this user’s name
Logos shown for educational purposes only and are the intellectual property of their owners.
How Does It Work? (MVC)
• Model session as its own entity
– session controller creates and deletes session,
handles interaction with authentication provider
• Once user is authenticated, we need a local
users model to represent him/her
– session[] remembers primary key (ID) of
“currently authenticated user”
• OmniAuth gem helps a lot by providing
uniform API to different “strategies”
21
Associations & Foreign Keys
(ESaaS §5.3)
© 2013 Armando Fox & David Patterson, all rights reserved
Reviews for RottenPotatoes
• Simple model: “I give it 4 potatoes out of 5”
• Goal: easily represent the concept that
movie has many reviews
• The code we’d like to write…but how?
http://pastebin.com/gU1hqm77
Cartesian Product
table 'artists'
id
name
10
11
12
Justin
Shakira
Britney
table 'reviews'
id
desc
30
31
32
"Terrible"
"Passable"
"Please"
artist_id
12
11
10
Cartesian product: artists JOIN reviews
artists.id
10
10
10
artists.name
Justin
Justin
Justin
reviews.id
30
31
32
reviews.desc reviews.artist_id
"Terrible"
12
"Passable"
11
"Please"
10
11
11
11
12
Shakira
Shakira
Shakira
Britney
30
31
32
30
"Terrible"
"Passable"
"Please"
"Terrible"
12
11
10
12
12
12
Britney
Britney
31
32
"Passable"
"Please"
11
10
Filtered Cartesian product: artists JOIN reviews ON artists.id = reviews.artist_id
artists.id
10
11
12
artists.name
Justin
Shakira
Britney
reviews.id
32
31
30
reviews.desc reviews.artist_id
"Please"
10
"Passable"
11
"Terrible"
12
Expressing “Has Many” in Terms
of Relational DB Model
• foreign key (FK) in one table refers to the primary
key (PK) of another table
reviews
movies
id*
id
movie_id
title
potatoes
rating
release_date
Databases 101
• joins are queries that combine records
from 2 or more tables using PKs and FKs
reviews
movies
id
id
movie_id
...
...
Cartesian
SELECT *
product
FROM movies, reviews
WHERE movies.id = reviews.movie_id
29
ActiveRecord Association
Support
(ESaaS §5.3)
© 2013 Armando Fox & David Patterson, all rights reserved
ActiveRecord Associations
• Allows manipulating DB-managed
associations more Rubyistically
• After setting things up correctly, you don't
have to worry (much) about keys and joins
class Movie < ActiveRecord::Base
has_many :reviews
end
class Review < ActiveRecord::Base
belongs_to :movie
“The foreign key
belongs33to me”
end
Basic Idea…
• reviews table gets a foreign key (FK) field
that has PK of Movie the review is about
• Dereference movie.reviews == perform
database join (lazily) to find reviews where
movie_id == movie.id
• Dereference review.movie == look up one
movie whose PK id == review.movie_id
• Note! Must add FK fields using a migration!
http://pastebin.com/hfvramxQ
Association Proxy Methods
• Now you can say:
@movie.reviews # Enumerable of reviews
• And also go the other way:
@review.movie
# what movie is reviewed?
• You can add new reviews for a movie:
@movie = Movie.where("title='Fargo'")
@movie.reviews.build(:potatoes => 5)
@movie.reviews.create(:newspaper=>'Chronicle', ...)
# how are these different from just new() &
create()?
@movie.reviews << @new_review
# instantly updates @new_review's FK in database!
@movie.reviews.find(:first,:conditions => '...')
36
Administrivia
• Hold team meetings next week
– Meet with your team in ETB 2005 during Tue
and Thu class time
• TAs will circulate to get project status
update from you, provide advice
• Highlight any issues you have so far!