active record(1)

Post on 12-Apr-2017

228 Views

Category:

Engineering

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Active records association

BYANANTA RAJ LAMICHHANE

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.

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….

AR associations. Why?

make common operations simpler and easier

Scenarioconsider a simple Rails application that

includes a model for customers and a model for orders.

Each customer can have many orders

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

description:stringrake db:migraterails c

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

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

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

Type of Association

belongs_tohas_onehas_manyhas_many :throughhas_one :throughhas_and_belongs_to_many

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

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

model

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

class Order < ActiveRecord::Base belongs_to :customerend

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

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.

The has_many :through Association

a many-to-many connection

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

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

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

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:

The has_and_belongs_to_many Association

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

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

Various options for relations

class_namedependentpolymorphicvalidatewherethrough

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

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!!

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

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

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

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

Single table inheritance

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/

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.

# 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">]>

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

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

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.

$ 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

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

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">

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"

POlymorphic many to any association

Scopes

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

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

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

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

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

default_scope-is-evil

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

Thank you

top related