简体   繁体   English

如何使用多个外键制作 Rails 模型 belongs_to

[英]How can i make rails models belongs_to using multiple foreign key

recently I have a migration that adds a user_id column to the watch_events tables.最近我有一个迁移,将user_id列添加到 watch_events 表中。 and thus I want to change the watch_event models to handle belongs_to but with multiple approach因此我想改变 watch_event 模型来处理 belongs_to 但有多种方法

  create_table 'users', force: :cascade do |t|
    t.integer 'id'
    t.integer 'customer_id'
  end

  create_table 'watch_events', force: :cascade do |t|
    t.integer 'customer_id'
    t.integer 'user_id'
  end

previously之前

class WatchEvent < ApplicationRecord
  belongs_to :user, foreign_key: :customer_id, primary_key: :customer_id
end

what I want:我想要的是:

  • if watch_event.customer_id is present, i want to use belongs_to:user, foreign_key: :customer_id, primary_key: :customer_id如果watch_event.customer_id存在,我想使用belongs_to:user, foreign_key: :customer_id, primary_key: :customer_id
  • if watch_event.customer_id is not present, i want to use normal belongs_to:user如果watch_event.customer_id不存在,我想使用普通的belongs_to:user

how can I achieve this on the watch_event model?如何在 watch_event model 上实现这一点?

If I understand your question correctly, then what you are looking for is a Polymorphic association .如果我正确理解您的问题,那么您正在寻找的是一个多态关联

If you see the code below, what it basically does is create two columns in the watch_events table, watcher_type and watcher_id .如果您看到下面的代码,它的基本作用是在watch_events表中创建两列watcher_typewatcher_id And the belongs_to:watcher then uses the watcher_type column to identify which model it should associate to,然后, belongs_to:watcher使用watcher_type列来识别它应该关联到哪个 model,

create_table 'watch_events', force: :cascade do |t|
  t.references 'watcher', polymorphic: true, null: false
end

class WatchEvent < ApplicationRecord
  belongs_to :watcher, polymorphic: true
end

I do not think that Rails supports 'fallback foreign keys' on associations.我不认为 Rails 支持关联的“后备外键”。 However, you can write a simple wrapper for your problem.但是,您可以为您的问题编写一个简单的包装器。 First, relate your WatchEvent class twice to the user model, using your two keys and two 'internal' association names ( :user_1 and :user_2 ).首先,使用您的两个键和两个“内部”关联名称( :user_1:user_2 )将您的WatchEvent class 与用户 model 关联两次。 Then, add a 'virtual association reader' ( user ) and a 'virtual association setter' ( user=(new_user) ):然后,添加一个“虚拟关联阅读器”( user )和一个“虚拟关联设置器”( user=(new_user) ):

class WatchEvent < ApplicationRecord
  
  belongs_to :user_1,
             class_name: 'User',
             foreign_key: :customer_id

  belongs_to :user_2,
             class_name: 'User',
             foreign_key: :user_id
  
  def user
    user_1 || user_2
  end

  def user=(new_user)
    self.user_1 = new_user
  end

end

With this solution, the requirements "use customer_id to find user" and "use user_id as fallback foreign key if customer_id is nil or doesn't yield a result" is satisfied.使用此解决方案,满足“使用customer_id查找用户”和“如果customer_idnil或不产生结果,则使用user_id作为备用外键”的要求。 It happens in the association reader method user .它发生在关联阅读器方法user中。 When there is a reader method, you'll need a setter method, which is user=() .当有 reader 方法时,您将需要一个 setter 方法,即user=() Feel free to design the setter's internals as required, mine is just a suggestion.随意根据需要设计二传手的内部结构,我的只是一个建议。

BTW: You may need to re-add the declaration of the foreign primary_key .顺便说一句:您可能需要重新添加外部primary_key的声明。 I omitted that for clarity.为了清楚起见,我省略了这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM