UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

35
UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations

Transcript of UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Page 1: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

UC Berkeley

More Rails: ActiveRecord,

ActionController, ActionView, and if time, Associations

Page 2: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Administrivia

• Armando/Will office hours moved to Thursdays 1:30

• Lab will be staffed for up to 30 mins. after most classes

• We’ll try to work more labs into the class time starting next week

Page 3: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Active Record: what is it?

• A class library that provides an object-relational model over a plain old RDBMS

• Deal with objects & attributes rather than rows & columns– SELECT result rows enumerable collection

– (later) object graph join query

Page 4: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

SQL 101 (Structured Query Language)

• Relational model of data organization (Codd, 1969) based on predicate logic & set theory

• Theoretical model implemented by Gray et al. in 1970’s– portable language (structured query language, SQL) to

express relational operations– relational database stores the data and provides

transactional semantics to instantiate the abstract relational model

• Think of a table as an unordered collection of objects that share a schema of simply-typed attributes– eg: Student = <lastname:string, ucb_sid:int,

degree_expected:date>• Think of SELECT as picking some records out

– SELECT lastname,ucb_sid FROM students WHERE degree_expected < 12/31/07

– Generally,SELECT attribs FROM tables WHERE constraints– Joins are more interesting, we’ll do them later

Page 5: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

While we’re on SQL...what’s a primary key

anyway?• Column whose value must be unique for every table

row– Why not just use (e.g.) last name or SID#?

• SQL AUTO_INCREMENT function makes it easy to specify an integer primary key

• If using migrations to create tables (recommended), Rails takes care of creating an autoincrement primary key field called ID

CREATE TABLE students ( id INT NOT NULL AUTO_INCREMENT, last_name VARCHAR(255), first_name VARCHAR(255), ucb_sid INT(11) DEFAULT 9999);

class CreateStudents<ActiveRecord::Migration

def self.up create_table :students do |tbl| tbl.column :last_name, :string tbl.column :first_name, :string tbl.column :ucb_sid, :integer, :null=>false, :default=>9999 end end

def self.down drop_table :students endend

Page 6: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

A Relational Database System is a "SQL

Server"• Maintains tables, accepts SQL queries, returns results

• API varies (embedded library, socket, etc.)

• RDBMS servers maintain ACID properties– Atomicity: all or nothing– Consistency: like a single copy– Isolation: transactions that execute simultaneously & touch same tables don't interfere with each other

– Durability: changes are “sure” once committed

• Very hard to get engineering for this correct with high performance– => Oracle => $$$

Page 7: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

MySQL vs. SQLite

• Command line interface• Various GUIs: MySQLAdmin, PHPMyAdmin, CocoaMySQL (MacOS)...

Localfile

Your app

SQLite library

DB#1

App

Driver

DB#n

Serverprocess

Serverprocess

App

Driver

App

Driver

App

DriverApp

Driver

App

Driver

App

Driver

App

Driver

SQL commands

results

• • •

• • •

SQL commands(socket)

results(socket)

filesystem calls

Page 8: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Review: CRUD

• 4 basic operations on a table row: Create, Read, Update attributes, Destroy

INSERT INTO students (last_name, ucb_sid, degree_expected) VALUES (“Fox”, 99999, “1998-12-15”),        (“Bodik”, 88888, “2009-06-05”)

SELECT * FROM students WHERE (degree_expected < “2000-01-01”)

UPDATE students SET degree_expected=“2008-06-05” WHERE last_name=“Bodik”)

DELETE FROM students WHERE ucb_sid=99999

Page 9: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

More on Student Example

• object attributes are “just” instance methods (a la attr_accessor)– so can already say stu.last_name, stu.ucb_sid, etc.

– what line in what file makes this happen?

• ActiveRecord accessors/mutators– default attr_accessor for each table column

– perform type-casting as needed– can be overridden, virtualized, etc.

Page 10: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Example: a short tourPredicate-like method names often end with

question markself (like Java this) not strictly necessary

here

Interpolation of expressions into strings

Some useful class methods of Date

Page 11: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Constructors

• Method named initialize, but invoked as new

• (at least) 3 ways to call it...

Page 12: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

New != Create

• Call s.save to write the object to the databases.create(args) s.new(args); s.saves.update_attributes(hash) can be used to update attributes in place

s.new_record? is true iff no underlying database row corresponds to s

• save does right thing in SQL (INSERT or UPDATE)

• Convention over configuration:– if id column present, assumes primary key– if updated_at/created_at columns in table, automatically are set to update/creation timestamp

Page 13: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

find() SQL SELECT# To find an arbitrary single record:s = Student.find(:first) # returns a Student instance# To find all records:students = Student.find(:all) # returns enumerable!

# find by 'id' primary key (Note! throws RecordNotFound)book = Book.find(1235)# Find a whole bunch of thingsids_array = get_list_of_ids_from_somewhere()students = Student.find(ids_array)

# To find by column values:armando = Student.find_by_last_name('Fox') # may return nila_local_grad =

Student.find_by_city_and_degree_expected('Berkeley', Date.parse('June 15,2007')

# To find only a few, and sort by an attributemany_localgrads =

Student.find_all_by_city_and_degree_expected('Berkeley', Date.parse('June 15,2007'),:limit=>30,:order=>:last_name)

Page 14: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Find by conditions• Use ? for values from parameters. Rails will sanitize the SQL and prevent any SQL injection

• You will want to learn some minimal SQL syntax

# Using SQL conditionsbooks = Book.find(:all,

:conditions => [‘pub_date between ? and ?’, params[:start_date], params[:end_date]],

:order => ‘pub_date DESC’)

You can also specify ordering and use arbitrary SQL operators:

Page 15: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Find by conditions

• Use ? to substitute in condition values– not mandatory, but a good idea!

• You can include other SQL functionality

• You can roll your owns = Student.find_by_sql("SELECT * FROM students ...")

# Using SQL conditionsbooks = Book.find(:all,

:conditions => [‘pub_date between ? and ?’, params[:start_date], params[:end_date]],

:order => ‘pub_date DESC’)

Page 16: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Advanced Find

books = Book.find(:all, :conditions => [‘pub_date between ? and ?’, params[:start_date], params[:end_date]],

:limit => 10, :offset => params[:page].to_i * 10)

You can also specify limits and offsets, and oh so much more

• :lock - Holds lock on the records (default: share lock)• :select - Specifies columns for SELECT (default *)• :group - (used with select) to group• :readonly - load as read-only (object can’t be saved)• :include - Prefetches joined tables (try :include first; more about this in Section 4)

• Note: use SQL-specific features at your own risk....

Page 17: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Caveat!

• The result of a find-all operation mixes in Enumerable

• Enumerable defines methods find and find_all

• Not to be confused with ActiveRecord::Base#find!

Page 18: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Action View

• A template for rendering views of the model that allows some code embedding– commonly RHTML (.html.erb); also RXML, HAML, RJS– note...too much code breaks MVC separation– convention: views for model foo are in

app/views/foo/

• “Helper methods” for interacting with models– model valuesHTML elements (e.g. menus)– HTML form inputassignment to model objects

• DRY (Don’t Repeat Yourself) support– Layouts capture common page content at application level, model level, etc. (app/views/layouts/)

– Partials capture reusable/parameterizable view patterns

Page 19: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Helper Methods for Input & Output

• Review: we saw a simple view already...– Anatomy: <% code %> <%= output %>

• But these form tags are generic...what about model-specific form tags?

• In the RHTML template:<%= form_for(@student) do |f| %>

– ...etc....

• In HTML delivered to browser:<input id="student_last_name"

name="student[last_name]" size="30" type="text" value="Fox" />

• What happened?

Page 20: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Action Controller• Each incoming request instantiates a new Controller object with its own instance variables– Routing (Sec. 4) determines which method to call– Parameter unmarshaling (from URL or form sub.) into params[] hash...well, not really a hash...but responds to [], []=

• Controller methods set up instance variables– these will be visible to the view– controller has access to model’s class methods; idiomatically, often begins with Model.find(...)

• Let’s see some examples...

Page 21: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Then we render...

• Once logic is done, render the view

– exactly one render permitted from controller method (1 HTTP request 1 response)

• Convention over configuration: implicit render – if no other render specified explicitly in action method

– looks for template matching controller method name and renders with default layouts (model, app)

Page 22: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

What about those model-specific form

elements?• Recall:

<input type="text" id="student_last_name" name="student[last_name]"/>

• Related form elements for student attributes will be named student[attr ]– marshalled into params as params[:student][:last_name], params[:student][:degree_expected], etc.

– i.e, params[:student] is a hash :last_name=>string, :degree_expected=>date, etc.

– and can be assigned directly to model object instance

– helpers for dates and other “complex” types...magic

Page 23: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

What else can happen?

• redirect_to allows falling through to different action without first rendering– fallthrough action will call render instead– works using HTTP 302 Found mechanism, i.e. separate browser roundtrip

• example: update method– fail: render the edit action again– success: redirect to “URL indicated by this @student object”

• alternate (older) syntax for redirects:redirect_to :action => 'show', :id => @student.id

Page 24: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

The Session Hash

• Problem: HTTP is stateless (every request totally independent). How to synthesize a session (sequence of related actions) by one user?

• Rails answer: session[] is a magic persistent hash available to controller

Actually, it’s not really a hash, but it quacks like one

– Managed at dispatch level using cookies– You can keep full-blown objects there, or just id’s (primary keys) of database records

– Deploy-time flag lets sessions be stored in filesystem, DB table, or distributed in-memory hash table

Page 25: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

The Flash

• Problem: I’m about to redirect_to somewhere, but want to display a notice to the user

• yet that will be a different controller instance with all new instance variablesRails answer: flash[]– contents are passed to the

next action, then cleared– to this action:

flash.now[:notice]

– visible to views as well as controller

• Strictly speaking, could use session & clear it out yourself

Page 26: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Intro. to Associations

• Let’s define a new model to represent Courses.– keep it simple: name, CCN, start date (month & year)

• What’s missing: a way to identify who is in the class!

• Rails solution: (similar to database foreign keys)– Add column course_id to Students table– Declare that a Course has_many :students– Both of these are Rails conventions

• Set a given student’s course_id field for the course they are taking– An obvious problem with this approach...but we’ll fix it later

Page 27: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Associations In General

• x has_many y– the y table has an x_id column– y belongs_to x– Note! Table structure unaffected by whether you also define the belongs_to....so why do it?

• x has_one y– actually like has_many: does same SQL query but returns only the first result row

Page 28: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Using Associations

• Going forward (course has_many students):

@c = Course.find(...)@s = @c.students

– What is the “type” of @s?• Going the other way (student belongs_to course):

@s = Student.find(...)@c = @s.course

Page 29: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Modeling professors

• How should we change the schema to support course belongs_to professor?

Page 30: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

What about all the students that a

professor teaches? @p = Professor.find(...)@c = Professor.courses@s = @c.students

• Or....

• Now we can just write: @s = Professor.find(...).students

Page 31: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

What is happening in terms of tables in

this example?• SQL is doing a join• Which you’ll learn about next time....

• The message is:Active Record tries to provide the abstraction of an object graph by using SQL table joins.

• The xxx_id fields are called foreign keys.

Page 32: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Remember....

• has_many, etc. are not part of the language

• nor are they macros• just regular old methods!• How do they work?

Page 33: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Learn more on your own

• These links will be posted on wiki soon

• SQLite: http://souptonuts.sourceforge.net/readme_sqlite_tutorial.html

• General SQL intro: http://www.w3schools.com/sql/sql_intro.asp

• Associations: Agile Rails book Ch. 14

Page 34: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Summary

• ActiveRecord provides (somewhat-)database-independent object model over RDBMS

• ActionView supports display & input of model objects– facilitates reuse of templates via layouts & partials

• ActionController dispatches user actions, manipulates models, sets up variables for views– declarative specifications capture common patterns for checking predicates before executing handlers

Page 35: UC Berkeley More Rails: ActiveRecord, ActionController, ActionView, and if time, Associations.

Virtual attributes example: simple authentication

• Assume we have a table customers with columns salt and hashed_password...Defines the receiver method

for password=

Why do we want to use self here?

Where’s the accessor for password?