如何在Rails中基于列值创建动态关系

时间:2019-04-11 14:28:09

标签: ruby-on-rails activerecord

我有一个简单的案例,但是无法理解如何使用my-project-1.0-test.jar来实现它。因此,我有一个类用户,它可以有一个ActiveRecord,也有一个列profile,这是一个枚举。看起来像这样

role

类似地,我有class User < ActiveRecord::Base enum role: { manager: 1, writer: 2 } has_one :profile end 个用户WriterManager

belongs_to

我正在努力指出用户的class Manager < ActiveRecord::Base belongs_to :user end class Writer < ActiveRecord::Base belongs_to :user end 属性以根据角色枚举来更正编写者或管理者的个人资料。我不能使用多态关系,因为用户是父表,而配置文件表(编写者和管理者)依赖于它。

任何帮助都会得到帮助

1 个答案:

答案 0 :(得分:1)

TL; DR:

我认为您无法用动态“表名”(也称为动态模型)定义has_many,主要是因为没有动态等效的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)