active record关联(ruby on rails guides)

来源:互联网 发布:nginx搭建wss环境 编辑:程序博客网 时间:2024/05/29 19:12

Rails 支持六种关联:

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

class Author < ActiveRecord::Base  attr_accessible :name  has_many :booksendclass Book < ActiveRecord::Base  attr_accessible :name, :author_id  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'end

has_many :through 关联

has_many :through 关联经常用于建立两个模型之间的多对多关联。这种关联表示一个模型的实例可以借由第三个模型,拥有零个和多个另一模型的实例。例如,在医疗锻炼中,病人要和医生约定练习时间。这中间的关联声明如下:

class Physician < ApplicationRecord  has_many :appointments  has_many :patients, through: :appointmentsend class Appointment < ApplicationRecord  belongs_to :physician  belongs_to :patientend class Patient < ApplicationRecord  has_many :appointments  has_many :physicians, through: :appointmentsend


has_many :through 还能简化嵌套的 has_many 关联。例如,一个文档分为多个部分,每一部分又有多个段落,如果想使用简单的方式获取文档中的所有段落,可以这么做:

class Document < ApplicationRecord  has_many :sections  has_many :paragraphs, through: :sectionsend class Section < ApplicationRecord  belongs_to :document  has_many :paragraphsend class Paragraph < ApplicationRecord  belongs_to :sectionend


加上 through: :sections 后,Rails 就能理解这段代码:

@document.paragraphs

多态关联

关联还有一种高级形式——多态关联(polymorphic association)。在多态关联中,在同一个关联中,一个模型可以属于多个模型。例如,图片模型可以属于雇员模型或者产品模型,模型的定义如下:

class Picture < ApplicationRecord  belongs_to :imageable, polymorphic: trueend class Employee < ApplicationRecord  has_many :pictures, as: :imageableend class Product < ApplicationRecord  has_many :pictures, as: :imageableend


belongs_to 中指定使用多态,可以理解成创建了一个接口,可供任何一个模型使用。在 Employee 模型实例上,可以使用@employee.pictures 获取图片集合。

类似地,可使用 @product.pictures 获取产品的图片。

Picture 模型的实例上,可以使用 @picture.imageable 获取父对象。不过事先要在声明多态接口的模型中创建外键字段和类型字段:

class CreatePictures < ActiveRecord::Migration[5.0]  def change    create_table :pictures do |t|      t.string  :name      t.integer :imageable_id      t.string  :imageable_type      t.timestamps    end     add_index :pictures, [:imageable_type, :imageable_id]  endend


控制缓存

关联添加的方法都会使用缓存,记录最近一次查询的结果,以备后用。缓存还会在方法之间共享。例如:

author.books          # 从数据库中检索图书
author.books.size     # 使用缓存的图书副本
author.books.empty?   # 使用缓存的图书副本

应用的其他部分可能会修改数据,那么应该怎么重载缓存呢?在关联上调用 reload 即可:

author.books                # 从数据库中检索图书
author.books.size           # 使用缓存的图书副本
author.books.reload.empty?  # 丢掉缓存的图书副本
                             # 重新从数据库中检索


Active Record 提供了 :inverse_of 选项,可以通过它明确声明双向关联:

class Author < ApplicationRecord
  has_many:books, inverse_of:'writer'
end
 
class Book < ApplicationRecord
  belongs_to:writer, class_name:'Author', foreign_key:'author_id'
end

inverse_of 有些限制:

  • 不支持 :through 关联;
  • 不支持 :polymorphic 关联;
  • 不支持 :as 选项;

class_name

如果另一个模型无法从关联的名称获取,可以使用 :class_name 选项指定模型名。例如,如果一本书属于一位作者,但是表示作者的模型是Patron,就可以这样声明关联:

class Book < ApplicationRecord
  belongs_to:author, class_name:"Patron"
end

foreign_key

按照约定,用来存储外键的字段名是关联名后加 _id:foreign_key 选项可以设置要使用的外键名:

class Book < ApplicationRecord
  belongs_to:author, class_name:"Patron",
                      foreign_key:"patron_id"
end

primary_key

按照约定,Rails 假定使用表中的 id 列保存主键。使用 :primary_key 选项可以指定使用其他列。

假如有个 users 表使用 guid 列存储主键,todos 想在 guid 列中存储用户的 ID,那么可以使用 primary_key 选项设置:

class User < ApplicationRecord
  self.primary_key ='guid' # 主键是 guid,不是 id
end
 
class Todo < ApplicationRecord
  belongs_to:user, primary_key:'guid'
end

执行 @user.todos.create 时,@todo 记录的用户 ID 是 @userguid 值。

touch

如果把 :touch 选项设为 true,保存或销毁对象时,关联对象的 updated_atupdated_on 字段会自动设为当前时间。

class Book < ApplicationRecord
  belongs_to:author, touch: true
end
 
class Author < ApplicationRecord
  has_many:books
end


includes

如果经常要直接从商品上获取作者对象(@line_item.book.author),就可以在关联中把作者从商品引入图书中:

class LineItem < ApplicationRecord
  belongs_to:book, -> { includes:author }
end
 
class Book < ApplicationRecord
  belongs_to:author
  has_many:line_items
end
 
class Author < ApplicationRecord
  has_many:books
end

每个  模型实例 都获得了这些方法:

assemblies
assemblies<<(object, ...)
assemblies.delete(object, ...)
assemblies.destroy(object, ...)
assemblies=(objects)
assembly_ids
assembly_ids=(ids)
assemblies.clear
assemblies.empty?
assemblies.size
assemblies.find(...)
assemblies.where(...)
assemblies.exists?(...)
assemblies.build(attributes = {}, ...)
assemblies.create(attributes = {})
assemblies.create!(attributes = {})

阅读全文
0 0