active record(1)

58
Active records association BY ANANTA RAJ LAMICHHANE

Upload: ananta-lamichhane

Post on 12-Apr-2017

228 views

Category:

Engineering


3 download

TRANSCRIPT

Page 1: Active record(1)

Active records association

BYANANTA RAJ LAMICHHANE

Page 2: Active record(1)

Active record?

facilitates the creation and use of business objects whose data requires persistent storage to a database.

is a description of an Object Relational Mapping system.ORM, is a technique that connects the rich objects of an application to tables

in a relational database management system.

Page 3: Active record(1)

Convention over Configuration

Naming conventionDatabase Table - Plural with underscores separating words (e.g.,

book_clubs).Model Class - Singular with the first letter of each word capitalized (e.g.,

BookClub).Schema convention Foreign keys - These fields should be named following the pattern

singularized_table_name_id.Primary keys - By default, Active Record will use an integer column named

id as the table's primary keyoptional column names like created_at, updated_at, type etcs….

Page 4: Active record(1)

AR associations. Why?

Page 5: Active record(1)

make common operations simpler and easier

Page 6: Active record(1)

Scenarioconsider a simple Rails application that

includes a model for customers and a model for orders.

Each customer can have many orders

Page 7: Active record(1)

rails g model customer name:stringrails g model order customer_id:integer

description:stringrake db:migraterails c

Page 8: Active record(1)

Without associationclass Customer < ActiveRecord::Baseendclass Order < ActiveRecord::Baseend

Page 9: Active record(1)

2.1.1 :001 > c=Customer.create(name:'cust1') => #<Customer id: 1, name: "cust1", created_at: "2015-01-03 07:58:03", updated_at: "2015-01-03 07:58:03">To Add new Order2.1.1 :002 > o=Order.new2.1.1 :003 > o.customer_id=c.id2.1.1 :003 > o.description="this is a test description"2.1.1 :006 > o.save

To deleting a customer, and ensuring that all of its orders get deleted as well2.1.1 :009 > orders= Order.where(customer_id: c.id)2.1.1 :010 > orders.each do |order|2.1.1 :011 > order.destroy2.1.1 :012?> end2.1.1 :013 > c.destroy

Page 10: Active record(1)

With Associationclass Customer < ActiveRecord::Base has_many :orders, dependent: :destroyend

class Order < ActiveRecord::Base belongs_to :customerend

2.1.1 :001 > c=Customer.create(name:'cust1') => #<Customer id: 1, name: "cust1", created_at: "2015-01-03 07:58:03", updated_at: "2015-01-03 07:58:03">To Add new Order2.1.1 :002 > o=c.orders.create(description:”this is first order”)To deleting a customer, and ensuring that all of its orders get deleted as well2.1.1 :003 > c.destroy

Page 11: Active record(1)

Type of Association

Page 12: Active record(1)

belongs_tohas_onehas_manyhas_many :throughhas_one :throughhas_and_belongs_to_many

Page 13: Active record(1)

The belongs_to Association

a one-to-one connection, such that each instance of the declaring model "belongs to" one instance of the other model.

must use the singular term

Page 14: Active record(1)
Page 15: Active record(1)

The has_one Associationhas_one association also sets up a one-to-one connection with another

model

Page 16: Active record(1)
Page 17: Active record(1)

class Customer < ActiveRecord::Base has_one :order, dependent: :destroyend

class Order < ActiveRecord::Base belongs_to :customerend

c.create_order(description:"ccc")c.order

Page 18: Active record(1)

The has_many Association

a one-to-many connection.the "other side" of a belongs_to association.The name of the other model is pluralized

when declaring a has_many association.

Page 19: Active record(1)
Page 20: Active record(1)

The has_many :through Association

a many-to-many connection

Page 21: Active record(1)
Page 22: Active record(1)

rails g model physician name:stringrails g model patient name:stringrails g model appointment physician_id:integer patient_id:integer

description:string

rake db:migraterails c

Page 23: Active record(1)

class Physician < ActiveRecord::Base has_many :appointments has_many :patients, :through => :appointmentsend

class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, :through => :appointmentsend

class Appointment < ActiveRecord::Base belongs_to :physician belongs_to :patientend

Page 24: Active record(1)

2.1.1 :010 > p=Physician.find(1) => #<Physician id: 1, name: "physicain", created_at: "2015-01-04 12:19:37", updated_at: "2015-01-04 12:19:37">2.1.1 :012 > p.patients.create(name: "p2") => #<Patient id: 2, name: "p2", created_at: "2015-01-04 12:43:22", updated_at: "2015-01-04 12:43:22">2.1.1 :024 > p.appointments.where(patient_id: 2)[0].update_attributes(description:'test')

Alternatively,p.appointments.create(patient_id: 2, description: ‘this is a test description’)

2.1.1 :030 > ph=Physician.find(1) => #<Physician id: 1, name: "physicain", created_at: "2015-01-04 12:19:37", updated_at: "2015-01-04 12:19:37">2.1.1 :031 > ph.patients << Patient.all

Page 25: Active record(1)

The has_one :through Association

a one-to-one connection with another model.declaring model can be matched with one instance of

another model by proceeding through a third model. if each supplier has one account, and each account is

associated with one account history, then the supplier model could look like this:

Page 26: Active record(1)
Page 27: Active record(1)

The has_and_belongs_to_many Association

creates a direct many-to-many connection with another model, with no intervening model.

Page 28: Active record(1)
Page 29: Active record(1)

Classwork 1: Create two tables husband and wife with one on one relationship and test things.

Create a rails app which should have a database named 'blog_db' in MySQL. Then do the following1. Create models Articles (title, content), Comments (comments, article_id), Tags (name)2. Article should have many comments and each comment should be associated to one article3. Each article can have many tags and each tag may be assigned to many articles.4. Create the relation such that if we delete an article then all the comments associated with that

article is also deleted5. Create a scope to query all the articles of yesterday sorted descending according to created

date

Page 30: Active record(1)

Various options for relations

Page 31: Active record(1)

class_namedependentpolymorphicvalidatewherethrough

Page 32: Active record(1)

class_name: Controlling association scopeBy default, associations look for objects only within the current module's scope. For example:module MyApplication module Business class Supplier < ActiveRecord::Base has_one :account end class Account < ActiveRecord::Base belongs_to :supplier end endend

Page 33: Active record(1)

Supplier and Account are defined in different scopes:module MyApplication module Business class Supplier < ActiveRecord::Base has_one :account end end module Billing class Account < ActiveRecord::Base belongs_to :supplier end endend

will not work!!

Page 34: Active record(1)

module MyApplication module Business class Supplier < ActiveRecord::Base has_one :account, class_name: "MyApplication::Billing::Account" end end module Billing class Account < ActiveRecord::Base belongs_to :supplier, class_name: "MyApplication::Business::Supplier" end endend

Page 35: Active record(1)

orif an order belongs to a customer, but the

actual name of the model containing customers is Patron, you'd set things up this way:

class Order < ActiveRecord::Base belongs_to :customer, class_name:

"Patron"end

Page 36: Active record(1)

:validate

If you set the :validate option to true, then associated objects will be validated whenever you save this object. By default, this is false: associated objects will not be validated when this object is saved.

class User belongs_to :account validates :account, :presence => trueend.

Page 37: Active record(1)

class Order < ActiveRecord::Base belongs_to :customer, -> { where active: true }, dependent: :destroyend

Page 38: Active record(1)

Single table inheritance

Page 39: Active record(1)

allows inheritance by storing the name of the class in a column that is named “type” by default.

a way to add inheritance to your models. STI lets you save different models inheriting from the

same model inside a single tableRef: http://samurails.com/tutorial/single-table-inheritance-

with-rails-4-part-1/

Page 40: Active record(1)

rails new sti --no-test-frameworkrails g model animal name:string age:integer

race:stringrake db:migrate

# app/models/animal.rbclass Animal < ActiveRecord::Base belongs_to :tribe self.inheritance_column = :race

# We will need a way to know which animals # will subclass the Animal model def self.races %w(Lion WildBoar Meerkat) end

endNote that self.inheritance_column = :race is used to

specify the column for STI and is not necessary if you are using the default column type.

If you want to disable Single Table Inheritance or use the type column for something else, you can use self.inheritance_column = :fake_column.

Page 41: Active record(1)

# app/models/wild_boar.rbclass WildBoar < Animalend# app/models/meerkat.rbclass Meerkat < Animalend# app/models/lion.rbclass Lion < Animalend

Lion.create(name:"himba", age:11)Meerkat.create(name:"meerkat")WildBoar.create(name:"wildboar")2.1.1 :016 > Animal.all=> # [#<Lion id: 1, name: "himba", age: "11",race:

"Lion", created_at: "2015-01-03 05:22:49", updated_at: "2015-01-03 05:22:49">,

#<Animal id: 2, name: "ananta", age: nil, race: nil, created_at: "2015-01-03 05:24:02", updated_at: "2015-01-03 05:24:02">,

#<Meerkat id: 3, name: "wildboar", age: nil, race: "Meerkat", created_at: "2015-01-03 05:25:03", updated_at: "2015-01-03 05:25:03">,

#<WildBoar id: 4, name: "wildboar", age: nil, race: "WildBoar", created_at: "2015-01-03 05:25:50", updated_at: "2015-01-03 05:25:50">]>

Page 42: Active record(1)

Add scopes to the parent models for each child model

class Animal < ActiveRecord::Base scope :lions, -> { where(race: 'Lion') } scope :meerkats, -> { where(race: 'Meerkat') } scope :wild_boars, -> { where(race: 'WildBoar') }

---end

2.1.1 :001 > Animal.lions Animal Load (0.2ms) SELECT "animals".* FROM "animals" WHERE "animals"."race" = 'Lion' => #<ActiveRecord::Relation [#<Lion id: 1, name: "himba", age: "11", race: "Lion", created_at: "2015-01-03 05:22:49", updated_at: "2015-01-03 05:22:49">]>2.1.1 :002 > Animal.meerkats

Page 43: Active record(1)

Polymorphic associationref: http://www.millwoodonline.co.uk/blog/polymorphic-associations-ruby-on-rails

Page 44: Active record(1)

Scenario:Imagine a school or college system where both students

and teachers can add posts. The post has an author->author could be a student or

a teacher. The students and teachers can ->add many posts.

Therefore we need an association between the Student, Teacher and Post models.

Page 45: Active record(1)

$ rails generate model student name:string email:string$ rails generate model teacher name:string email:string office:integer$ rails generate model post author:references{polymorphic}:index title:string

body:textNote: created the post model with the author reference set as polymorphic

and an index

Page 46: Active record(1)

simplified by using the t.references formauthor:references{polymorphic}:index class CreatePosts < ActiveRecord::Migration def change

create_table :posts do |t| t.references :author, polymorphic: true,

index: true t.string :title t.text :body t.timestamps

end endend

class CreatePosts < ActiveRecord::Migration def change create_table :posts do |t| t.string :title t.text :body t.integer :author_id t.string :author_type t.timestamps end add_index :posts, :author_id endend

Page 47: Active record(1)

The Post model will already be setup correctly# app/models/post.rbclass Post < ActiveRecord::Base belongs_to :author, polymorphic: trueend # app/models/student.rbclass Student < ActiveRecord::Base has_many :posts, as: :authorend

# app/models/teacher.rbclass Teacher < ActiveRecord::Base has_many :posts, as: :authorend

2.1.1 :019 > s=Student.create(name: ‘Ananta’)2.1.1 :019 > s=Student.find(1)2.1.1 :011 > p=Post.new => #<Post id: nil, author_id: nil, author_type: nil, title: nil, body: nil, created_at: nil, updated_at: nil>2.1.1 :012 > p.author= s => #<Student id: 1, name: "ananta", email: nil, created_at: "2015-01-03 07:06:51", updated_at: "2015-01-03 07:06:51">2.1.1 :013 > p.title="test title" => "test title"2.1.1 :014 > p.save2.1.1 :015 > Post.all [#<Post id: 1, author_id: 1, author_type: "Student", title: "test title", body: nil, created_at: "2015-01-03 07:08:02", updated_at: "2015-01-03 07:08:02">

Page 48: Active record(1)

2.1.1 :019 > t=Teacher.create(name:"dddd") => #<Teacher id: 1, name: "dddd", email: nil, office: nil, created_at: "2015-01-03 07:15:02", updated_at: "2015-01-

03 07:15:02">2.1.1 :020 > p=Post.create(author:t, title: "this is title", body:"this is body") => #<Post id: 2, author_id: 1, author_type: "Teacher", title: "this is title", body: "this is body", created_at: "2015-01-

03 07:16:31", updated_at: "2015-01-03 07:16:31">2.1.1 :023 > Post.all => #<ActiveRecord::Relation [#<Post id: 1, author_id: 1, author_type: "Student", title: "test title", body: nil, created_at: "2015-01-03 07:08:02",

updated_at: "2015-01-03 07:08:02">, #<Post id: 2, author_id: 2, author_type: "Teacher", title: "this is title", body: "this is body", created_at: "2015-01-

03 07:16:31", updated_at: "2015-01-03 07:16:31">]>2.1.1 :024 > p= Post.find(1) => #<Post id: 1, author_id: 1, author_type: "Student", title: "test title", body: nil, created_at: "2015-01-03 07:08:02",

updated_at: "2015-01-03 07:08:02">2.1.1 :025 > p.author.name => "ananta"

Page 49: Active record(1)

POlymorphic many to any association

Page 50: Active record(1)

Scopes

Page 51: Active record(1)

What is Scope?A scope is a subset of a collection.

Page 52: Active record(1)

ScenarioYou have Users. Now, some of those Users are subscribed to your newsletter. You marked those who receive a newsletter by adding a field to the Users

Database (user.subscribed_to_newsletter = true). Naturally, you sometimes want to get those Users who are subscribed to

your newsletter.ref:

http://stackoverflow.com/questions/4869994/what-is-scope-named-scope-in-rails

Page 53: Active record(1)
Page 54: Active record(1)

of course, we always do this:User.where(subscribed_to_newsletter: true)

Instead of always writing this you could, however, do something like this.#File: users.rb

class User < ActiveRecord::Base scope :newsletter, where(subscribed_to_newsletter: true)end

This allows you to access your subscribers by simply doing this:User.newsletter

Page 55: Active record(1)

Class methods on your model are automatically available on scopes. Assuming the following setup:class Article < ActiveRecord::Base scope :published, -> { where(published: true) } scope :featured, -> { where(featured: true) }

def self.latest_article order('published_at desc').first end

def self.titles pluck(:title) endend

We are able to call the methods like this:Article.published.featured.latest_articleArticle.featured.titles

Page 56: Active record(1)

default_scopehttp://rails-bestpractices.com/posts/806-

default_scope-is-evil

Page 57: Active record(1)

class Post default_scope where(published: true).order("created_at desc")end

> Post.limit(10) Post Load (3.3ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`published` = 1 ORDER BY created_at desc LIMIT 10

> Post.unscoped.order("updated_at desc").limit(10) Post Load (1.9ms) SELECT `posts`.* FROM `posts` ORDER BY updated_at desc LIMIT 10

Page 58: Active record(1)

Thank you