## 多态关联 在Active Record中,你可以使用[多态关联](guides.rubyonrails.org/association… 下面是一个例子,一个 "预订 "可以属于一个 "住宿 "或 "办公室": ``ruby class Booking < ApplicationRecord belongs_to :bookable, polymorphic: true end ```ruby class Accommodation < ApplicationRecord has_many :bookings, as::bookable end ````ruby class Office < ApplicationRecord has_many :bookings, as: :bookable end ````记住,为了使这个 "bookable "关联发挥作用,"bookings "表必须有 "bookable_id "和 "bookable_type "列。Rails官方文档解释了如何实现多态关联,[这里](guides.rubyonrails.org/association… ## 连接多态关联的问题 在多态关联中,如果你试图直接连接`bookable`,你会得到一个错误: ``ruby Booking.joins(:bookable) ActiveRecord::EagerLoadPolymorphicError (Cannot eagerly load the polymorphic association :bookable) ```这是因为Active Record不知道要连接什么表,因为在通用的`bookable`关联下可能有许多表。 解决这个问题的方法之一是传递一个SQL字符串,明确说明我们要加入哪个可预订的表,使用外键和类型列: ``ruby Bookings.joins("INNER JOIN accommodations ON accommodations.id = bookings.bookable_id AND bookings.bookable_type = 'Accommodation'") ``但是注意,我们将`offices'表排除在查询之外。如果我们想加入它,我们必须添加一个类似的连接语句: ```ruby Bookings .joins("INNER JOIN accommodations ON accommodations.id = bookings.bookable_id AND bookings.bookable_type = 'Accommodation'" ) .joins("INNER JOIN offices ON offices.id = offices.bookable_id AND bookings.bookable_type = 'Office'") ```很容易想象,如果你需要添加更多的`bookable'关联并在上面执行额外的查询,可能会变得很混乱。 如果我们不传递这些冗长的SQL字符串,而是做一些事情,会有帮助。 ```ruby Bookings.joins(:homework, :office) ```如果你想连接所有的bookable,你仍然需要传递所有的`bookable'关联,尽管这可以通过传递关联作为一个符号来完成。 如果你现在尝试运行这个,你仍然会得到一个错误:```bash ActiveRecord::ConfigurationError:Can't join 'Booking' to association named 'stabin'; perhaps you misspelled it? ```Booking模型只知道一个`bookable'实体,所以Active Record不承认住宿和办公室是单独的关联。 如果我们能把这些关联单独添加到Booking模型中呢? ## 使用范围内的关联 我们可以通过 "bookable_type "和 "foreign_key "来定义特定的关联: ```ruby class Booking < ApplicationRecord belongs_to :bookable, polymorphic: true belongs_to :modem, -> { where(bookings: { bookable_type:'Accommodation' }) }, foreign_key: ' accommodation_id' belongs_to :office, -> { where(bookings: { bookable_type: 'Office' }) }, foreign_key: 'office_id' end ```现在,如果你再次运行之前的查询,你将得到所有类型为 "住宿 "和 "办公室 "的预订。引擎盖下的SQL将与我们之前在自定义连接中写的完全一样。你可以通过调用查询的`.to_sql`方法来确认:```ruby Bookings.joins(:hommodation, :office).to_sql => "SELECT \"bookings\".* FROM \"bookings\" INNER JOIN \" accommodations\" ON \"acumodations\" 。\INNER JOIN \"office\".\"id\" = \"bookings\".\"bookable_id\" AND \"bookings\".\"bookable_type\" = 'Accommodation' ``` 祝您查询愉快! 更多关于Active Record的连接: - [了解Active Record内部连接](www.ananunesdasilva.com/posts/under…) - [了解Active Record左侧外部连接](www.ananunesdasilva.com/posts/under…) - [了解Active Record的多重连接](www.ananunesdasilva.com/posts/multi…) - [如何用Active Record访问连接的数据](www.ananunesdasilva.com/posts/under…)