Active
Record Associations
=================
Based on guides.rubyonrails.org
Active Record Associations
Types of Associations
belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many
belongs_to
Set a one-to-one
conection with another model. Each
instance of this class belongs_to one instance of other instance
ex:
class Order
< ActiveRecord::Base
belongs_to :customer
end
http://guides.rubyonrails.org/images/belongs_to.png
Corresponding migration
class
CreateOrders < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
t.timestamps
end
create_table :orders do |t|
t.belongs_to :customer
t.datetime :order_date
t.timestamps
end
end
end
has_one
set a one-to-one
connection with another model. But this
association denotes possession of another instance
ex:
class
Supplier < ActiveRecord::Base
has_one :account
end
http://guides.rubyonrails.org/images/has_one.png
Corresponding migration
class
CreateSuppliers < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier
t.string :account_number
t.timestamps
end
end
end
has_many
A instance of a class
has many instances of another class
ex:
class
Customer < ActiveRecord::Base
has_many :orders
end
http://guides.rubyonrails.org/images/has_many.png
Corresponding migration
class
CreateCustomers < ActiveRecord::Migration
def change
create_table :customers do |t|
t.string :name
t.timestamps
end
create_table :orders do |t|
t.belongs_to :customer
t.datetime :order_date
t.timestamps
end
end
end
The has_many :through
Association
To set many-to-many
association. It creates a third model to
represent the many-to-many association
ex:
class
Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
class
Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class
Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
end
http://guides.rubyonrails.org/images/has_many_through.png
Corresponding migration
class
CreateAppointments < ActiveRecord::Migration
def change
create_table :physicians do |t|
t.string :name
t.timestamps
end
create_table :patients do |t|
t.string :name
t.timestamps
end
create_table :appointments do |t|
t.belongs_to :physician
t.belongs_to :patient
t.datetime :appointment_date
t.timestamps
end
end
end
It is possible to get
values using the reference attribute
physician.patients
= patients
It is possible to go
through the nest tree of dependencies using :through
EX:
class
Document < ActiveRecord::Base
has_many :sections
has_many :paragraphs, through: :sections
end
class
Section < ActiveRecord::Base
belongs_to :document
has_many :paragraphs
end
class
Paragraph < ActiveRecord::Base
belongs_to :section
end
@document.paragraphs
has-one :though
Set one-to-one relation
. The :though has a similar purpose of
above. Access another model through a second.
ex:
class
Supplier < ActiveRecord::Base
has_one :account
has_one :account_history, through: :account
end
class
Account < ActiveRecord::Base
belongs_to :supplier
has_one :account_history
end
class
AccountHistory < ActiveRecord::Base
belongs_to :account
end
Corresponding Migration
class
CreateAccountHistories < ActiveRecord::Migration
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier
t.string :account_number
t.timestamps
end
create_table :account_histories do |t|
t.belongs_to :account
t.integer :credit_rating
t.timestamps
end
end
end
has_and_belongs_to_many
Creates a direct
many-to-many association between two models
ex:
class
Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part
< ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
http://guides.rubyonrails.org/images/habtm.png
Corresponding migration
class
CreateAssembliesAndParts < ActiveRecord::Migration
def change
create_table :assemblies do |t|
t.string :name
t.timestamps
end
create_table :parts do |t|
t.string :part_number
t.timestamps
end
create_table :assemblies_parts do |t|
t.belongs_to :assembly
t.belongs_to :part
end
end
end
has_many :through OR
has_and_belongs_to_many?
has_many :through ->
If you need the models to be independent entities
If you need
validations, callbacks, or extra attributes on the join model.
has_and_belongs_to_many
-> if there is a dependency between entities
Polymorphic Associations
a model can belong to more than one other
model, on a single association.
Ex: A Picture that belongs to Employee and
Product
class
Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
class
Employee < ActiveRecord::Base
has_many :pictures, as: :imageable
end
class
Product < ActiveRecord::Base
has_many :pictures, as: :imageable
end
Then:
@employee.pictures.
AND
@product.pictures.
Corresponding migration
class
CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
t.references :imageable, polymorphic:
true
t.timestamps
end
end
end
http://guides.rubyonrails.org/images/polymorphic.png
Self-joins
Ex:
class
Employee < ActiveRecord::Base
has_many :subordinates, class_name:
"Employee",
foreign_key:
"manager_id"
belongs_to :manager, class_name:
"Employee"
end
Issues
Updating the schema
belongs_to
associations you need to create foreign
ex:
class
Order < ActiveRecord::Base
belongs_to :customer
end
class
CreateOrders < ActiveRecord::Migration
def change
create_table :orders do |t|
t.datetime :order_date
t.string
:order_number
t.integer
:customer_id
end
end
end
has_and_belongs_to_many
associations you need to create the appropriate join table.
Controlling association
scope
To make
associations of classes that are in different modules uses "class_name"
and tell all the path
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
end
end
Bi-directional
associations
To
guarantee that the relation is bi-directional use : "inverse_of:"
class
Customer < ActiveRecord::Base
has_many :orders, inverse_of: :customer
end
class Order
< ActiveRecord::Base
belongs_to :customer, inverse_of: :orders
end
ex:
c
= Customer.first
o
= c.orders.first
c.first_name
== o.customer.first_name # => true
c.first_name
= 'Manny'
c.first_name
== o.customer.first_name # => true
Limitations:
Do
not work with :through, :polymorphic and :as associations
For
belongs_to associations, has_many inverse associations are ignored.
belongs_to Association
Reference
association(force_reload
= false)
association=(associate)
build_association(attributes
= {})
create_association(attributes
= {})
Ex:
class Order
< ActiveRecord::Base
belongs_to :customer
end
association(force_reload
= false)
@customer
= @order.customer
association=(associate)
@order.customer
= @customer
build_customer
The
associated object is NOT saved
@customer
= @order.build_customer(customer_number: 123,
customer_name: "John Doe")
create_customer
The
associated object IS SAVED
@customer
= @order.create_customer(customer_number: 123,
customer_name: "John Doe")
Obtions to belongs_to
To customize the behavior of belongs_to
:autosave
If true, Rails will save or destroy any member as
soon as the parent is saved
:class_name
Used
when the name of class in belongs_to can't be derived from association name.
Or
to change the name of the accessed object in belongs_to
ex:
class
Order < ActiveRecord::Base
belongs_to :customer, class_name:
"Patron"
end
:counter_cache
Make
the SIZE more efficient including a counter and the Db not uses
"count(*)"
ex:
class
Order < ActiveRecord::Base
belongs_to :customer, counter_cache: true
#OR
belongs_to :customer, counter_cache:
:count_of_orders
end
class
Customer < ActiveRecord::Base
has_many :orders
end
:dependent
:destroy
-> Call the destroy of the dependant object when the parent is destroyed
belongs_to
:customer, dependent: :destroy
:delete
-> remove the associated object, but don't call destroy.
belongs_to
:customer, dependent: :delete
:restrict
-> A ActiveRecord::DeleteRestrictionError is thrown if try to delete the
associated object
belongs_to
:customer, dependent: :restrict
:foreign_key
Set a name for foreign key
class
Order < ActiveRecord::Base
belongs_to :customer, class_name:
"Patron",
foreign_key:
"patron_id"
end
:inverse_of
Specify
the inverse of association
Ex:
class
Customer < ActiveRecord::Base
has_many :orders, inverse_of: :customer
end
class
Order < ActiveRecord::Base
belongs_to :customer, inverse_of: :orders
end
:polymorphic
Indicates
that an association is polymorphic
:touch
If
the object is saved or destroyed the updated_at stamp is set
belongs_to :customer, touch: true
#OR specify the attribute
belongs_to :customer, touch:
:orders_updated_at
:validate
Whenever
you save the object, the associated will be validated as well
belongs_to :customer, validate: true
Scopes for belongs_to
To
customize the query used by belongs_to
where
belongs_to
:customer, -> { where active: true }
includes
To
specify a second-order association that could eager-loaded. Increase the efficiency
For
first-order, the eager is automatic
class
LineItem < ActiveRecord::Base
belongs_to :order, -> { includes :customer
}
end
class
Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
end
class
Customer < ActiveRecord::Base
has_many :orders
end
readonly
If
readonly, the associated object will be readonly when retrived via a
association.
select
lets
override the "SQL SELECT" clause
has_many Association Reference
Methods
collection(force_reload
= false)
@orders
= @customer.orders
collection<<(object,
...)
@customer.orders
<< @order1
collection.delete(object,
...)
-
Remove from list, seting foreign key to nil.
If associeated with :destroy it will be destroyed.
@customer.orders.delete(@order1)
collection.destroy(object,
...)
-
It will ignore the :depend option
@customer.orders.destroy(@order1)
collection=objects
@order_ids
= @customer.order_ids (ARRAY)
collection.clear
Remove
every object from the collection.
Destroy if "depend :destroy", delete if "depend
:delete_all" or set foreign key to nil
collection.empty?
<%
if @customer.orders.empty? %>
No Orders Found
<%
end %>
collection.size
@order_count
= @customer.orders.size
collection.find(...)
@open_orders
= @customer.orders.find(1)
collection.where(...)
@open_orders
= @customer.orders.where(open: true) # No query yet
collection.exists?(...)
collection.build(attributes
= {}, ...)
Created
but NOT saved
@order
= @customer.orders.build(order_date: Time.now,
order_number: "A12345")
collection.create(attributes
= {})
Created
and SAVED
@order
= @customer.orders.create(order_date: Time.now,
order_number: "A12345")
options for has_may
:as
Polymorphic association
:autosave
Automatically
saved the association based on any modification of the object
:class_name
Change
the class
has_many :orders, class_name:
"Transaction"
:dependent
:foreign_key
has_many
:orders, foreign_key: "cust_id"
:inverse_of
:primary_key
:source
:source_type
:through
:validate
If
validate option to false the associated object will not be validated when the
object is saved. Default = true.
Scope for has_many
where
Confition
to the associated object to be met
class
Customer < ActiveRecord::Base
has_many :confirmed_orders, -> { where
"confirmed = 1" },
class_name: "Order"
end
extending
group
Define
a group by
has_many
:line_items, -> { group 'orders.id' },
through:
:orders
includes
To
define a second-order association to eager-load
has_many :orders, -> { includes :line_items
}
limit
limit
the number of objects that will be fetched
has_many
:recent_orders, -> { order('order_date desc').limit(100) }, class_name: "Order",
offset
Define
the offset of a fetch
->
{ offset(11) }
order
Define
the order by
has_many
:orders, -> { order "date_confirmed DESC" }
readonly
If
true the associated objects retrieved are readonly
select
To
define your own SQL SELEC
distinct
Used
to keep the collection free from duplication.
Mostly used with :through option
class
Person
has_many :readings
has_many :posts, -> { distinct }, through:
:readings
end
has_and_belongs_to_many
Association Reference
Methods
Basicaly
the same as has_many association plus:
:join_table
Override
the name of the join_table
Scope for
has_and_belongs_to_many
Basicaly
the same as has_many association plus:
uniq
To
remove duplicates from colection
Association Callbacks
Callbacks work in some
place in the life cicle of a Active Record object. The are triggered by events in the life cicle
of the object.
before_add
after_add
before_remove
after_remove
ex:
class Customer <
ActiveRecord::Base
has_many :orders, before_add:
:check_credit_limit
def check_credit_limit(order)
...
end
end
If an exception is
thrown, the operation is not performed.
Nenhum comentário:
Postar um comentário