我想要一个表images(其中包含一个字段file:string),以及类似这个模型结构的东西
class BookCover
mount_uploader :file, BookCoverUploader
end
class Book
has_many :covers, class: 'BookCover'
end
class UserAvatar
mount_uploader :file, UserAvatarUploader
end
class User
has_one :avatar, class: 'UserAvatar'
end
如何实现这一目标,使用什么?单表继承还是多态关联?我想轻松地抓住images某些user或book(例如,删除而不用imageable_id)。你会如何组织表格?
更新
从理论上讲,这应该可行,对吧?
# прием отсюда https://maulanaruby.wordpress.com/2007/02/17/sti-vs-polymorphic-association/
class CreateImages < ActiveRecord::Migration[5.0]
def change
create_table :images do |t|
t.string :file, null: false
t.string :type, null: false
t.integer :source_id, null: false
t.timestamps
end
end
end
class Image < ActiveRecord::Base
end
class Cover < Image
mount_uploader :file, CoverUploader
belongs_to :book, foreign_key: 'source_id'
end
class Avatar < Image
mount_uploader :file, AvatarUploader
belongs_to :user, foreign_key: 'source_id'
end
class Book < ActiveRecord::Base
has_many :covers
end
class User < ActiveRecord::Base
has_one :avatar
end
你想做的事情(可能是徒劳的,但稍后会详细介绍)实际上是由多态关联完成的。创建一个表,其中“外键”(不是真实的,但它是什么)由两个字段表示:
штука_type和штука_id,Rails 在模型中指定时使用它们:并且,分别设置相反的
has_manyorhas_one,withas: :штука(因为一切都符合多态,所以没有什么可以猜测选择哪个名称,没有什么可做的,您需要明确指定名称)。但总的来说,多态是一个相当肮脏的把戏。在数据库级别为它们组织数据一致性控制将非常困难(如果可能的话 - 我还没有看到一个 RDBMS 允许你为整个表而不是为一小部分创建外键) ,您甚至可以进行涉及此关联尝试的复杂查询。
为什么不是性传播感染?
如果你为每个值匹配一个且只有一个所有者类
type,那么你将得到一个多态形式的拐杖,而штука_type它只是type,并且不会直接有所有者类型,但是你可以从中学习的东西它。它在结构上与多晶型非常相似,也有它的所有缺点。
也许最好把它
UserAvatar作为一个不必要的实体一起扔掉?如果在任何给定时间对于每个条目
User您期望一个且只有一个条目UserAvatar,那么最好将这两个实体作为一个实体的一部分。为什么不让用户的头像成为模型内部的一个字段?还有一个稍微更一般的规则:如果两个实体是一对一的关系,考虑它们是否真的应该是同一个实体?
可怕实验的领域:PostgreSQL 及其继承
如果您没有 PostgreSQL,那么您无法继续阅读 :)
如果您真的非常希望能够一次爬取所有模型的图片,您可以采取骑士行动并使用继承,而不是从 ActiveRecord 继承,而是直接从数据库继承。PostgreSQL 有它,这里是一个迁移和模型的例子:
值得一提的是:
the schema is exported with losses,继承成功丢失,需要在sql选项中直接
schema.rb添加到export中config/application.rbImage没有主键。而且,不幸的是,它不能,因为 PostgreSQL 不支持在基表上创建唯一键(根据定义,主键是唯一的)。因此,将无法以通常的 ActiveRecord 方式更新表的各个行,并且不支持可以删除文件的回调。但如果您愿意,您可以对所有图片提出一般要求。并将字段添加到
images也会将它们添加到所有后代表中。看看这个解决方案是否可以帮助您。至少,它保留了对外键的一致性控制。作为一种实践,您甚至可以向基表添加外键列,并在后代表中自行创建外键。