与多态关联有很多关系

时间:2018-08-27 11:32:54

标签: ruby-on-rails activerecord rails-activerecord

class Sample
  has_many :pictures
end

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
  belongs_to :sample
end


class Employee < ApplicationRecord
  has_many :pictures, as: :imageable
end

class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end

要获取给定样本的所有产品或员工,应该是什么协会? Sample.first.pictures.map(&:imageable)。我想将其作为activerecord关联。

1 个答案:

答案 0 :(得分:2)

解决方法:

class Sample
  has_many :pictures
  has_many :imageable_employees, through: :pictures, source: :imageable, source_type: 'Employee'
  has_many :imageable_products, through: :pictures, source: :imageable, source_type: 'Product'
end

用法:

sample = Sample.first
employees = sample.imageable_employees
products = sample.imageable_products

...请参见docs

说明:

  

Sample.first.pictures.map(&:imageable)。我想将其作为activerecord关联。

...是我认为这是不可能的,但是您仍然可以将它们全部作为Array获得。原因是没有对应于imageable关联的表(模型),而是对应于ANY模型,这使SQL查询变得复杂,因此我认为这是不可能的。

作为示例,请考虑以下查询:

imageables_created_until_yesterday = Sample.first.something_that_returns_all_imageables.where('created_at < ?', Time.zone.now.beginning_of_day)

# what SQL from above should this generate? (without prior knowledge of what tables that the polymorphic association corresponds to)
# =>  SELECT "WHAT_TABLE".* FROM "WHAT_TABLE" WHERE (sample_id = 1 AND created_at < '2018-08-27 00:00:00.000000')

# furthermore, you'll notice that the SQL above only assumes one table, what if the polymorphic association can be at least two models / tables?

替代解决方案:

根据应用程序的需求和尝试执行的“查询”,您可能会考虑也可能不会考虑以下实现abstract_imageable(真实表)模型的功能,以使您能够执行查询。您还可以在此abstract_imageable模型中在此处添加所有您认为在所有“可成像”记录中“共享”的属性。

随时可以重命名abstract_imageable

class Sample
  has_many :pictures
  has_many :abstract_imageables, through: :pictures
end

class Picture
  belongs_to :sample
  has_many :abstract_imageables
end

# rails generate model abstract_imageable picture:belongs_to imageable:references{polymorphic}
class AbstractImageable
  belongs_to :picture
  belongs_to :imageable, polymorphic: true
end

class Employee < ApplicationRecord
  has_many :abstract_imageables, as: :imageable
  has_many :pictures, through: :abstract_imageables
end

class Product < ApplicationRecord
  has_many :abstract_imageables, as: :imageable
  has_many :pictures, through: :abstract_imageables
end

用法:

sample = Sample.first
abstract_imageables = sample.abstract_imageables

puts abstract_imageables.first.class
# => AbstractImageable

puts abstract_imageables.first.imageable.class
# => can be either nil, or Employee, or Product, or whatever model

puts abstract_imageables.second.imageable.class
# => can be either nil, or Employee, or Product, or whatever model

# your query here, which I assumed you were trying to do because you said you wanted an `ActiveRecord::Relation` object
abstract_imageables.where(...)