Skip to content

Instantly share code, notes, and snippets.

@oojikoo-gist
Created April 15, 2015 16:48
Show Gist options
  • Save oojikoo-gist/85df888d26d9b1018c69 to your computer and use it in GitHub Desktop.
Save oojikoo-gist/85df888d26d9b1018c69 to your computer and use it in GitHub Desktop.
rails: association
# With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method.
# without contuer_cache option
# asking for the value of @customer.orders.size requires making a call to the database to perform a COUNT(*) query
# To avoid this call, you can add a counter cache to the belonging model:
belongs_to :customer, counter_cache: true
# throught association
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
# nested association
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
# many to many
#
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
# has_one
class Supplier < ActiveRecord::Base
has_one :account
end
class Account < ActiveRecord::Base
belongs_to :supplier
end
# polyymorphic
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
# self join
class Employee < ActiveRecord::Base
has_many :subordinates, class_name: "Employee",
foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
end
# inverse_of
class Customer < ActiveRecord::Base
has_many :orders, inverse_of: :customer
end
class Order < ActiveRecord::Base
belongs_to :customer, inverse_of: :orders
end
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
class Order < ActiveRecord::Base
belongs_to :customer
end
# > methods
# customer
# customer=
# build_customer
# create_customer
# create_customer!
@customer = @order.build_customer(customer_number: 123,
customer_name: "John Doe")
@order.customer = @customer
# :dependent
# :destroy, when the object is destroyed, destroy will be called on its associated objects.
# :delete, when the object is destroyed, all its associated objects will be deleted directly from the database without calling their destroy method
# :foreign_key
# By convention, Rails assumes that the column used to hold the foreign key on this model is the name of the association with the suffix _id added. The :foreign_key option lets you set the name of the foreign key directly:
class Order < ActiveRecord::Base
belongs_to :customer, class_name: "Patron",
foreign_key: "patron_id"
end
# :touch
#
class Order < ActiveRecord::Base
belongs_to :customer, touch: true
end
class Customer < ActiveRecord::Base
has_many :orders
end
# In this case, saving or destroying an order will update the timestamp on the associated customer. You can also specify a particular timestamp attribute to update:
class Order < ActiveRecord::Base
belongs_to :customer, touch: :orders_updated_at
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.
# Scopes for belongs_to
# There may be times when you wish to customize the query used by belongs_to. Such customizations can be achieved via a scope block. For example:
class Order < ActiveRecord::Base
belongs_to :customer, -> { where active: true },
dependent: :destroy
end
# You can use any of the standard querying methods inside the scope block. The following ones are discussed below:
# where
# includes
# readonly
# select
# includes
# If you frequently retrieve representatives directly from suppliers (@supplier.account.representative), then you can make your code somewhat more efficient by including representatives in the association from suppliers to accounts:
class Supplier < ActiveRecord::Base
has_one :account, -> { includes :representative }
end
class Account < ActiveRecord::Base
belongs_to :supplier
belongs_to :representative
end
class Representative < ActiveRecord::Base
has_many :accounts
end
# ====================================
# has_many Association Reference
# ====================================
#
# collection(force_reload = false)
# collection<<(object, ...)
# collection.delete(object, ...)
# collection.destroy(object, ...)
# collection=(objects)
# collection_singular_ids
# collection_singular_ids=(ids)
# collection.clear
# collection.empty?
# collection.size
# collection.find(...)
# collection.where(...)
# collection.exists?(...)
# collection.build(attributes = {}, ...)
# collection.create(attributes = {})
# collection.create!(attributes = {})
# The collection<< method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model.
@customer.orders << @order1
# The collection.delete method removes one or more objects from the collection by setting their foreign keys to NULL.
@customer.orders.delete(@order1)
# The collection.destroy method removes one or more objects from the collection by running destroy on each object.
@customer.orders.destroy(@order1)
# The collection_singular_ids method returns an array of the ids of the objects in the collection.
@order_ids = @customer.order_ids
# The collection.clear method removes every object from the collection. This destroys the associated objects if they are associated with dependent: :destroy, deletes them directly from the database if dependent: :delete_all, and otherwise sets their foreign keys to NULL.
########################
# Options for has_many
########################
# >> methods
# :as
# :autosave
# :class_name
# :dependent
# :foreign_key
# :inverse_of
# :primary_key
# :source
# :source_type
# :through
# :validate
# The group method supplies an attribute name to group the result set by, using a GROUP BY clause in the finder SQL.
class Customer < ActiveRecord::Base
has_many :line_items, -> { group 'orders.id' },
through: :orders
end
# The limit method lets you restrict the total number of objects that will be fetched through an association.
#
class Customer < ActiveRecord::Base
has_many :recent_orders,
-> { order('order_date desc').limit(100) },
class_name: "Order"
end
# The offset method lets you specify the starting offset for fetching objects via an association. For example, -> { offset(11) } will skip the first 11 records.
#
# The order method dictates the order in which associated objects will be received (in the syntax used by an SQL ORDER BY clause).
class Customer < ActiveRecord::Base
has_many :orders, -> { order "date_confirmed DESC" }
end
# If you use the readonly method, then the associated objects will be read-only when retrieved via the association.
# The select method lets you override the SQL SELECT clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns.
# ***** If you specify your own select, be sure to include the primary key and foreign key columns of the associated model. If you do not, Rails will throw an error.
# Use the distinct method to keep the collection free of duplicates. This is mostly useful together with the :through option.
class Person < ActiveRecord::Base
has_many :readings
has_many :articles, through: :readings
end
person = Person.create(name: 'John')
article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">]
Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
class Person
has_many :readings
has_many :articles, -> { distinct }, through: :readings
end
person = Person.create(name: 'Honda')
article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 7, name: "a1">]
Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
# If you want to make sure that, upon insertion, all of the records in the persisted association are distinct (so that you can be sure that when you inspect the association that you will never find duplicate records), you should add a unique index on the table itself. For example, if you have a table named person_articles and you want to make sure all the articles are unique, you could add the following in a migration:
add_index :person_articles, :article, unique: true
# Options for has_and_belongs_to_many
# :association_foreign_key
# :autosave
# :class_name
# :foreign_key
# :join_table
# :validate
# :association_foreign_key
# By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix _id added. The :association_foreign_key option lets you set the name of the foreign key directly:
#
class User < ActiveRecord::Base
has_and_belongs_to_many :friends,
class_name: "User",
foreign_key: "this_user_id",
association_foreign_key: "other_user_id"
end
# If the default name of the join table, based on lexical ordering, is not what you want, you can use the :join_table option to override the default.
# If you set the :validate option to false, then associated objects will not be validated whenever you save this object. By default, this is true: associated objects will be validated when this object is saved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment