What you want to do (perhaps in vain, but more on that later) is really done by a polymorphic association . A table is made in which the "foreign key" (not real, but which one is) is represented by two fields: штука_type and штука_id , and Rails uses them when specified in the model:
belongs_to :штука, polymorphic: true
And the opposite has_many or has_one is set, respectively, with as: :штука (since everything fits the polymorph, guess what name to select, not what, you need to specify the name explicitly).
But in general, polymorphs are rather dirty. Control of data consistency for them at the database level will be very difficult to organize (if at all possible - I haven’t yet seen RDBMSs that allow making a foreign key not on the whole table, but only on a small subsample), and you can’t even make complex queries involving this association try.
Why not STI?
If you match one and only one owner class for each type value, you will get a crutch in the form of a polymorph, where instead of штука_type will be just type , and there will be not directly the type of owner, but something from which you can recognize it.
Very similar to the device on polymorph and all its shortcomings, too.
Perhaps it is better to throw out UserAvatar as an unnecessary entity?
If at any moment in time for each User record you expect one and only one UserAvatar record, then these two entities should be made into parts of one. Why not make the user's avatar a field right inside the model?
And a slightly more general rule: if two entities are in a 1-to-1 relationship, think about whether they should not really be one entity?
If you don’t have PostgreSQL, you can stop reading :)
If you really, really want to be able to climb behind the pictures of all the models at once, you can make a knight's move and use the inheritance not of ActiveRecord, but right at the database. PostgreSQL has it, here is an example of migration and models:
class CreateImages < ActiveRecord::Migration[5.0] def change # Базовая таблица с общими полями # vvvvvvvvv ВАЖНО create_table :images, id: false do |t| t.string :url end # Просто модели create_table :apples do |t| t.timestamps end create_table :oranges do |t| t.timestamps end # А вот тут самое интересное! create_table :apple_images, options: "INHERITS (images)" do |t| t.references :apple, foreign_key: true end create_table :orange_images, options: "INHERITS (images)" do |t| t.references :orange, foreign_key: true end end end
It is worth noting that:
schema is exported to losses in schema.rb , inheritance is successfully lost, you need to add export directly to SQL in config/application.rb
config.active_record.schema_format = :sql`
class Image < ApplicationRecord end class Apple < ApplicationRecord has_many :apple_images end class AppleImage < ApplicationRecord belongs_to :apple end class Orange < ApplicationRecord has_many :orange_images end class OrangeImage < ApplicationRecord belongs_to :orange end
- The table under
Image no primary key. And, unfortunately, it cannot be, because PostgreSQL does not support the creation of a unique key (and the primary key is unique, by definition) on the base table. And as a result, there is no way to update individual lines of the table in the usual ActiveRecord way, and there will also be no support for callbacks in which files can be deleted.
But you can make requests in general for all the pictures, if desired. And adding fields to images will add them to all tables inherited.
See if this solution can help you. At a minimum, it maintains control of consistency with foreign keys. As a workout, you can even add a foreign key column to the base table, and create foreign keys themselves in successor tables.