active record关联(ruby on rails guides)

本文深入解析了Rails中的六种模型关联方式,包括belongs_to、has_one、has_many等,并详细介绍了多态关联、缓存控制及高级配置选项如inverse_of、class_name等。

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

end

class 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: :appointments
end
 
class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end
 
class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end


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

class Document < ApplicationRecord
  has_many :sections
  has_many :paragraphs, through: :sections
end
 
class Section < ApplicationRecord
  belongs_to :document
  has_many :paragraphs
end
 
class Paragraph < ApplicationRecord
  belongs_to :section
end


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

@document.paragraphs

多态关联

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

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end
 
class Employee < ApplicationRecord
  has_many :pictures, as: :imageable
end
 
class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end


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]
  end
end


控制缓存

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

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 = {})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值