一、Rails支持六种类型的关联:
belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many
二、详细的参考
以下各节详细介绍了每种类型的关联,包括它们添加的方法以及在声明关联时可以使用的选项。
1、belongs_to参考
belongs_to关联会与另一个模型进行一对一匹配。用数据库术语,该关联表示该类包含外键。如果另一个类包含外键,则应has_one改为使用外键。
1.1、声明belongs_to关联时,声明类自动获得与该关联相关的6种方法:
association
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
reload_association
在所有这些方法中,association都被替换为作为第一个参数传递给的符号belongs_to。例如,给定声明:
class Book < ApplicationRecord
belongs_to :author
end
该Book模型的每个实例将具有以下方法:
author
author=
build_author
create_author
create_author!
reload_author
在初始化新的has_one或belongs_to关联时,必须使用build_前缀来建立关联,而不是association.build用于has_many或has_and_belongs_to_many关联的方法。要创建一个,请使用create_前缀。
1.1.1、association方法返回关联的对象(如果有)。如果未找到关联的对象,则返回nil.
@author = @book.author
1.1.2、如果已经从数据库中检索到该对象的关联对象,则将返回缓存的版本。要覆盖此行为(并强制读取数据库),请调用#reload_association父对象。
@author = @book.reload_author
1.1.3、association=方法将关联对象分配给该对象。在幕后,这意味着从关联的对象中提取主键,并将该对象的外键设置为相同的值。
@book.author = @author
1.1.4、build_association方法返回关联类型的新对象。这个对象将从通过属性来实例化,并通过这个对象的外键的链接将被设置,但相关的对象将不尚未被保存。
@author = @book.build_author(author_number: 123,author_name: "John Doe")
1.1.5、create_association方法返回关联类型的新对象。该对象将从传递的属性中实例化,通过该对象的外键的链接将被设置,并且一旦它通过了在关联模型上指定的所有验证,关联对象将被保存。
@author = @book.create_author(author_number: 123,author_name: "John Doe")
1.1.6、执行与create_association上述相同的操作,但是ActiveRecord::RecordInvalid如果记录无效,则会引发。
尽管Rails使用的智能默认值在大多数情况下都可以正常工作,但是有时您可能希望自定义belongs_to关联引用的行为。创建关联时,可以通过传递选项和作用域块来轻松实现此类自定义。例如,此关联使用两个这样的选项:
class Book < ApplicationRecord
belongs_to :author, touch: :books_updated_at,
counter_cache: true
end
2、has_one参考
2.1、声明has_one关联时,声明类自动获得与该关联相关的6种方法:
association
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
reload_association
使用方法请参考第一小节
3、has_many参考
has_many协会创建了另一个模型一到一对多的关系。用数据库术语来说,该关联表示另一个类将具有一个引用该类实例的外键。
声明has_many关联时,声明类自动获得与该关联相关的17个方法:
collection
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 = {})
collection.reload
在所有这些方法中,collection将替换为作为第一个参数传递给的符号has_many,并collection_singular替换为该符号的单数形式。例如,给定声明:
class Author < ApplicationRecord
has_many :books
end
3.1 collection
该collection方法返回所有关联对象的Relation。如果没有关联的对象,则返回一个空的Relation。
@books = @author.books
3.2 collection<<(object, …)
该collection<<方法通过将一个或多个对象的外键设置为调用模型的主键来将其添加到集合中。
@author.books << @book1
3.3 collection.delete(object, …)
通过collection.delete将对象的外键设置为,该方法从集合中删除一个或多个对象NULL。
@author.books.delete(@book1)
此外,如果对象与关联,则将被销毁;如果与关联dependent: :destroy,则将其删除dependent: :delete_all。
3.4 collection.destroy(object, …)
该collection.destroy方法通过destroy在每个对象上运行从集合中删除一个或多个对象。
@author.books.destroy(@book1)
将始终从数据库中删除对象,而忽略该:dependent选项。
3.5 collection=(objects)
collection=通过适当地添加和删除,该方法使集合仅包含提供的对象。所做的更改将保存到数据库中。
3.6 collection_singular_ids
该collection_singular_ids方法返回集合中对象ID的数组。
@book_ids = @author.book_ids
3.7 collection_singular_ids=(ids)
该collection_singular_ids=方法通过适当地添加和删除,使集合仅包含由提供的主键值标识的对象。所做的更改将保存到数据库中。
3.8 collection.clear
该collection.clear方法根据dependent选项指定的策略从集合中删除所有对象。如果未提供任何选项,它将遵循默认策略。has_many :through关联的默认策略是delete_all,而has_many关联的默认策略是将外键设置为NULL。
@author.books.clear
如果对象与关联,则将被删除dependent: :destroy,就像dependent: :delete_all。
3.9 collection.empty?
如果该集合不包含任何关联的对象,则该collection.empty?方法返回true。
<% if @author.books.empty? %>
No Books Found
<% end %>
3.10 collection.size
该collection.size方法返回集合中的对象数。
@book_count = @author.books.size
3.11 collection.find(…)
该collection.find方法在集合中查找对象。它使用与相同的语法和选项 ActiveRecord::Base.find。
@available_book = @author.books.find(1)
3.12 collection.where(…)
该collection.where方法基于提供的条件在集合内查找对象,但是对象被延迟加载,这意味着仅当访问对象时才查询数据库。
@available_books = @author.books.where(available: true) # No query yet
@available_book = @available_books.first # Now the database will be queried
3.13 collection.exists?(…)
该collection.exists?方法检查集合中是否存在满足提供条件的对象。它使用与相同的语法和选项 ActiveRecord::Base.exists?。
3.14 collection.build(attributes = {}, …)
该collection.build方法返回单个或一组关联类型的新对象。对象(S)将根据传入的属性被实例化,并通过他们的外键的链接将被创建,但相关的对象将不尚未被保存。
@book = @author.books.build(published_at: Time.now,book_number: "A12345")
@books = @author.books.build([
{ published_at: Time.now, book_number: "A12346" },
{ published_at: Time.now, book_number: "A12347" }
])
3.15 collection.create(attributes = {})
该collection.create方法返回单个或一组关联类型的新对象。将通过传递的属性实例化对象,将创建通过其外键的链接,并且一旦它通过了在关联模型上指定的所有验证,则将保存关联的对象。
@book = @author.books.create(published_at: Time.now,book_number: "A12345")
@books = @author.books.create([
{ published_at: Time.now, book_number: "A12346" },
{ published_at: Time.now, book_number: "A12347" }
])
3.16 collection.create!(attributes = {})
执行与collection.create上述相同的操作,但是ActiveRecord::RecordInvalid如果记录无效,则会引发。
3.17 collection.reload
该collection.reload方法返回所有关联对象的Relation,强制读取数据库。如果没有关联的对象,则返回一个空的Relation。
@books = @author.books.reload
4、has_and_belongs_to_many参考
该has_and_belongs_to_many关联与另一个模型建立了多对多关系。用数据库术语来说,这通过一个中间联接表将两个类相关联,该中间联接表包括引用每个类的外键。
声明has_and_belongs_to_many关联时,声明类自动获得与该关联相关的17个方法:
collection
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 = {})
collection.reload
使用方法参考上节has_many