TL; DR:
Я не думаю, что вы могли бы определить has_many
с динамическим «именем таблицы» (a.k.a. динамическая модель), главным образом потому, что нет динамической эквивалентной строки SQL для представления, скажем что-то вроде ниже:
# Let's pretend that you have a `Post` model `belongs_to :user` and has an attribute `is_enabled:boolean`
# and that `User` `has_one :post`...
User.joins(:post).where(posts: { is_enabled: true })
# would generate an SQL
# User Load (0.6ms) SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" WHERE "posts"."is_enabled" = true LIMIT 1
# ^ This works fine because `has_one :posts` always is mapped to the `posts` table
# but since you are asking for a dynamic one, then see an equivalent below
User.joins(:profile).where(":managers or :writers": { is_enabled: true })
# User Load (0.6ms) SELECT "users".* FROM "users" INNER JOIN "what_table" on "what_table"."user_id" = "users"."id" WHERE "what_table"."is_enabled" = true LIMIT 1
# ^ which as you could see does not have an exact SQL equivalent because it is
# "trying to" INNER JOIN on a "dynamic" table. You can do this per `User` record,
# because you know what to INNER JOIN with, but for a collection of `User` records,
# there is no such SQL "dynamic-table-name-matching" equivalent.
Альтернативное решение:
class User < ActiveRecord::Base
enum role: { manager: 1, writer: 2 }
has_one :manager
has_one :writer
def profile
case role
when 'manager' then manager
when 'writer' then writer
else raise NotImplementedError
end
end
# or if you prefer a dynamic-matching one:
# def profile
# send(role.to_sym)
# end
end
Пример использования
# rails console
user = User.first
puts user.profile
# => returns either <Manager...>, <Writer...>, or nil
Предостережение, хотя альтернативное решение выше определяет profile
как метод , а не ассоциацию , поэтому вы потеряете способность делать INNER JOIN
s (что вы, вероятно, не смогли бы сделать в любом случае; см. мой TL; DR выше, чтобы узнать почему)