Associations: Mechanics (ESaaS §5.3)

Slides:



Advertisements
Similar presentations
Chapter 10: Designing Databases
Advertisements

When Things Go Wrong: Debugging (Engineering Software as a Service §4.5) © 2013 Armando Fox & David Patterson, all rights reserved 1.
Introduction to Databases CIS 5.2. Where would you find info about yourself stored in a computer? College Physician’s office Library Grocery Store Dentist’s.
Concepts of Database Management Sixth Edition
Associations: Mechanics (ESaaS §5.3) © 2013 Armando Fox & David Patterson, all rights reserved.
DRYing Out MVC (ESaaS §5.1) © 2013 Armando Fox & David Patterson, all rights reserved.
1 Chapter 2 Reviewing Tables and Queries. 2 Chapter Objectives Identify the steps required to develop an Access application Specify the characteristics.
Logical Database Design Nazife Dimililer. II - Logical Database Design Two stages –Building and validating local logical model –Building and validating.
Page 1 ISMT E-120 Introduction to Microsoft Access & Relational Databases The Influence of Software and Hardware Technologies on Business Productivity.
Page 1 ISMT E-120 Desktop Applications for Managers Introduction to Microsoft Access.
Model-View-Controller
Chapter 4 The Relational Model 3: Advanced Topics Concepts of Database Management Seventh Edition.
IE 423 – Design of Decision Support Systems Database development – Relationships and Queries.
Lecture 11 Rails Topics SaaSSaaS Readings: SaaS book Ch February CSCE 740 Software Engineering.
1 Relational Databases and SQL. Learning Objectives Understand techniques to model complex accounting phenomena in an E-R diagram Develop E-R diagrams.
Photo Gallery INFO 2310: Topics in Web Design and Programming.
Chapter 38 Persistence Framework with Patterns 1CS6359 Fall 2011 John Cole.
1 CSE 2337 Introduction to Data Management Access Book – Ch 1.
Routes & REST & URL-helpers & validations & filters
Database Systems Design, Implementation, and Management Coronel | Morris 11e ©2015 Cengage Learning. All Rights Reserved. May not be scanned, copied or.
CMP-MX21: Lecture 4 Selections Steve Hordley. Overview 1. The if-else selection in JAVA 2. More useful JAVA operators 4. Other selection constructs in.
Create, Update and Delete Carol Wolf Computer Science.
Rails and routing INFO 2310: Topics in Web Design and Programming.
CS 160 and CMPE/SE 131 Software Engineering February 9 Class Meeting Department of Computer Science Department of Computer Engineering San José State University.
Introduction to information systems RUBY ON RAILS dr inż. Tomasz Pieciukiewicz.
DAY 14: ACCESS CHAPTER 1 RAHUL KAVI October 8,
Ruby on Rails. Web Framework for Ruby Designed to make it easier to develop, deploy, and maintain web applications Design with Model-View-Controller –almost.
AOIT Database Design Unit 3, Lesson 9 Data Integrity Copyright © 2009–2011 National Academy Foundation. All rights reserved.
COP Introduction to Database Structures
Creating Databases for Web applications
DRYing Out MVC (ESaaS §5.1)
Tables & Relationships
Project Management: Messages
Methodology Logical Database Design for the Relational Model
Working in the Forms Developer Environment
Microsoft Access 2016 Design and Implement Powerful Relational Databases Chapter 6.
© 2013 Armando Fox & David Patterson, all rights reserved
CHAPTER 7 DATABASE ACCESS THROUGH WEB
CSE 103 Day 15: Database Design
Information Systems Today: Managing in the Digital World
Foreign Keys Local and Global Constraints Triggers
Objectives Create an action query to create a table
CIS 155 Table Relationship
Microsoft Office Illustrated Fundamentals
Information Systems Database Management
Design and Implement Powerful Relational Databases Chapter 6
Translation of ER-diagram into Relational Schema
Databases and Information Management
Ruby on Rails by Manik Juneja
Chapter 9 Designing Databases
Introduction to Access 2003
Ruby on Rails by Manik Juneja
Tutorial 3 – Querying a Database
Teaching slides Chapter 8.
Relational Algebra Chapter 4, Sections 4.1 – 4.2
Systems Analysis and Design
Databases and Information Management
Spreadsheets, Modelling & Databases
Rails Philip Ritchey slides generously gifted by Jeff Huang.
Relational Databases.
Peter Seibel Practical Common Lisp Peter Seibel
Chapter 17 Designing Databases
Microsoft Access Validation Rules, Table Relationships And
Review of Previous Lesson
Grauer and Barber Series Microsoft Access Chapter One
SQL – Constraints & Triggers
CPSC-608 Database Systems
Databases and Information Management
Database Systems: Design, Implementation, and Management
Relationships While we are on the subject of Relationships, let’s take a quick look at them.
Presentation transcript:

Associations: Mechanics (ESaaS §5.3) © 2013 Armando Fox & David Patterson, all rights reserved

How Does It Work? Models must have attribute for foreign key of owning object e.g., movie_id in reviews table ActiveRecord manages this field in both database & in-memory AR object Don’t manage it yourself! Harder to read May break if database schema doesn’t follow Rails conventions

Rails Cookery #4 To add a one-to-many association: Add has_many to owning model and belongs_to to owned model Create migration to add foreign key to owned side that references owning side Apply migration rake db:test:prepare to regenerate test database schema

END

We can say movie.reviews, but review.movie won’t work ☐ Suppose we have setup the foreign key movie_id in reviews table. If we then add has_many :reviews to Movie, but forget to put belongs_to :movie in Review, what happens? We can say movie.reviews, but review.movie won’t work ☐ We will get a database error when trying to save a Review ☐ 1. True. The has_many will set up the getter in Movie, but there will be no getter in Review. 2. True. The foreign key won’t be set. 3. True. We won’t have the foreign key, and the movie name is not unique. 4. True We will have no way of determining which movie a given review is associated with ☐ ☐ All of the above

END

Through-Associations (ESaaS §5.4) © 2013 Armando Fox & David Patterson, all rights reserved

Many-to-Many Associations Scenario: Moviegoers rate Movies a moviegoer can have many reviews but a movie can also have many reviews Why can’t we use has_many & belongs_to? Solution: create a new AR model to model the multiple association

Many-to-Many moviegoer: has_many :reviews movie: has_many :reviews id reviews moviegoer_id movie_id number movies id ... moviegoer: has_many :reviews movie: has_many :reviews review: belongs_to :moviegoer belongs_to :movie How to get all movies reviewed by some moviegoer?

has_many :through moviegoers id reviews moviegoer_id movie_id ... movies id ... moviegoer: has_many :reviews has_many :movies, :through => :reviews movie: has_many :reviews has_many :moviegoers, :through => :reviews reviews: belongs_to :moviegoer belongs_to :movie Why is there no review_id field in the movie table?

Through Now you can do: My potato scores for R-rated movies @user.movies # movies rated by user @movie.users # users who rated this movie My potato scores for R-rated movies @user.reviews.select { |r| r.movie.rating == 'R' } Example: show => vouchers

has_many :through moviegoers id reviews moviegoer_id movie_id ... movies id ... @user.movies SELECT * FROM movies JOIN moviegoers ON reviews.moviegoer_id = moviegoers.id JOIN movies ON reviews.movie_id = movies.id Why is there no review_id field in the movie table?

END

Which of these, if any, is NOT a correct way of saving a new association, given m is an existing movie: Review.create!(:movie_id=>m.id, :potatoes=>5) ☐ r = m.reviews.build(:potatoes => 5) r.save! ☐ ☐ m.reviews << Review.new(:potatoes=>5) m.save! 1. Works. But definitely not desirable. 2. Works. The save is needed. 3. Works. Adds new review to list of m’s reviews and saves it. The save is redundant. 4. All work. All will work ☐

END

Shortcut: Has and Belongs to Many (habtm) join tables express a relationship between existing model tables using FKs Join table has no primary key because there’s no object being represented! movie has_and_belongs_to_many :genres genre has_and_belongs_to_many :movies @movie.genres << Genre.find_by_name('scifi') http://pastebin.com/tTVGtNLx movies id name ...etc. genres id description genres_movies genre_id movie_id

Rules of Thumb If you can conceive of things as different real-world objects, they should probably be distinct models linked through an association If you don’t need to represent any other aspect of a M-M relationship, use habtm Otherwise, use has_many :through

HABTM Naming Conventions M-M relationship naming convention: if a Bar has_and_belongs_to_many :foos then a Foo has_and_belongs_to_many :bars and the database table is the plural AR names in alphabetical order bars_foos

END

Faculty has-many appointments, Student has-many appointments ☐ We want to model students having appointments with faculty members. Our model would include which relationships: Faculty has-many appointments, Student has-many appointments ☐ Faculty HABTM Students, Students HABTM Faculty ☐ ☐ Faculty belongs-to appointment, Student belongs-to appointment 1. True. Similar to a movie has-many reviews and a moviegoer has-many reviews. 2. False. We want appointments as a separate object. 3. False. The belongs-to goes the other way. 4. False. Faculty has-many students through appointments. Faculty has-many appointments, through Students ☐

END

RESTful Routes for Associations (ESaaS §5.5) © 2013 Armando Fox & David Patterson, all rights reserved

Creating/Updating Through-Associations When creating a new review, how to keep track of the movie and moviegoer with whom it will be associated? Need this info at creation time But route helpers like new_movie_path (provided by resources :movies in routes file) only “carry around” the ID of the model itself

Nested RESTful Routes in config/routes.rb: resources :movies becomes resources :movies do resources :reviews end Nested Route: access reviews by going ”through” a movie

Nested RESTful Routes available as params[:movie_id] Why do you need movie_id when creating a review? => nested RESTful routes manage it for you by making it part of URL. but don't HAVE to do it this way. available as params[:movie_id] available as params[:id]

ReviewsController#create # POST /movies/1/reviews # POST /movies/1/reviews.xml def create # movie_id because of nested route @movie = Movie.find(params[:movie_id]) # build sets the movie_id foreign key automatically @review = @movie.reviews.build(params[:review]) if @review.save flash[:notice] = 'Review successfully created.' redirect_to(movie_reviews_path(@movie)) else render :action => 'new' end to what action does movie_reviews_path point? why is it OK to render :action => 'new' on failure?

ReviewsController#new # GET /movies/1/reviews/new def new # movie_id because of nested route @movie = Movie.find(params[:movie_id]) # new sets movie_id foreign key automatically @review ||= @movie.reviews.new @review = @review || @movie.reviews.new end Another possibility: do it in a before-filter to what action does movie_reviews_path point? why is it OK to render :action => 'new' on failure? See http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html for a discussion of a ||= b. It is not exactly the same as a = a || b. If a is not nil/false, no action is taken, otherwise a = b. So it acts as a test and set operator – if @review is nil (no review has been created), then one is created (@movies.reviews.new). before_filter :lookup_movie def lookup_movie @movie = Movie.find_by_id(params[:movie_id]) || redirect_to movies_path, :flash => {:alert => "movie_id not in params"} end

Views %h1 Edit = form_tag movie_review_path(@movie,@review), :method => :put do |f| ...Will f create form fields for a Movie or a Review? = f.submit "Update Info" = link_to 'All reviews for this movie', movie_reviews_path(@movie) Remember, these are for convenience. Invariant is: review when created or edited must be associated with a movie.

END

If we also have moviegoer has_many reviews, can we use moviegoer_review_path() as a helper? Yes, it should work as-is because of convention over configuration ☐ Yes, but we must declare reviews as a nested resource of moviegoers in routes.rb ☐ No, because there can be only one RESTful route to any particular resource ☐ 1. False. 2. True. See Figure 5.19. /moviegoers/:moviegoer_id/reviews 3. False. You can have several routes to the same resource. 4. False. This is not a through association, as reviews belong-to moviegoers. No, because having more than one through-association involving Reviews would lead to ambiguity ☐

END

DRYing Out Queries with Reusable Scopes (ESaaS §5.6) © 2013 Armando Fox & David Patterson, all rights reserved

“Customizing” Associations with Declarative Scopes Movies appropriate for kids? Movies with at least N reviews? Movies with at least average review of N? Movies recently reviewed? Combinations of these?

Scopes Can Be “Stacked” Movie.for_kids.with_good_reviews(3) Movie.with_many_fans.recently_reviewed Scopes are evaluated lazily! http://pastebin.com/BW40LAHX

END

Where do database queries happen? 1 # in controller: 2 def good_movies_for_kids 3 @m = Movie.for_kids.with_good_reviews(3) 4 end 5 # in view: 6 - @m.each do |movie| 7 %p= pretty_print(movie) Where do database queries happen? Line 3 only ☐ Lines 6-7 only ☐ The ActiveRecord database queries are lazy. The only time that the access is required is when the value must be known, which is in lines 6 (determine whether there are any such movies and get the next one) and line 7 (print it out). False True True. If no movies are returned, then line 7 is never executed. ☐ Line 3 AND lines 6-7 Depends on return value of for_kids ☐

END

Associations Wrap-Up (ESaaS §5.7-5.9) © 2013 Armando Fox & David Patterson, all rights reserved

Associations Wrap-Up Associations are part of application architecture provides high-level, reusable association constructs that manipulate RDBMS foreign keys Mix-ins allow Associations mechanisms to work with any ActiveRecord subclass Proxy methods provide Enumerable-like behaviors A many-fold association quacks like an Enumerable Proxy methods are an example of a design pattern Nested routes help you maintain associations RESTfully - but they’re optional, and not magic

Elaboration: 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

Referential Integrity What if we delete a movie with reviews? movie_id field of those reviews then refers to nonexistent primary key another reason primary keys are never recycled Various possibilities depending on app... delete those reviews? has_many :reviews, :dependent => :destroy make reviews “orphaned”? (no owner) has_many :reviews, :dependent => :nullify Can also use lifecycle callbacks to do other things (e.g., merging)

Testing Referential Integrity it "should nuke reviews when movie deleted" do @movie = @movie.create!(...) @review = @movie.reviews.create!(...) review_id = @review.id @movie.destroy end lambda { Review.find(review_id) }.should raise_error(ActiveRecord::RecordNotFound)

Advanced Topics Single-Table Inheritance (STI) & Polymorphic Associations Self-referential has_many :through Many declarative options on manipulating associations (like validations) To learn (much) more: http://guides.rubyonrails.org/association_basics.html The Rails 4 Way, Chapter 9

END

to have to write the association methods yourself If using the DataMapper pattern and you want to do one-to-many associations, you can expect: to have to write the association methods yourself ☐ ☐ Better scalability ☐ Worse scalability 1. True. The mapper methods provide the associations. 2. True. You can use noSQL databases. 3. True. If the associations are well-mapped to relational databases, then it might be very fast, especially with custom RDBMS hardware. 4. True. All of the above are possible ☐

END