这是多态关联的略微独特的版本。它是其中一个"现实世界"我努力解决的问题并没有得到很多好的答案,所以我自己做了。
Transaction
条记录有多个Tasks
,每个Task
都有Assignee
,可以来自多个表。
# Models
class Transaction < ApplicationRecord
has_many :tasks
has_many :borrowers
has_many :partners
# Combine into a single array to display on the collection_select
def assignees
borrowers + partners
end
end
class Task < ApplicationRecord
# has attribute :assignee_type_and_id (string)
belongs_to :transaction
# Reverse engineer single attribute into type/id parts
def assignee
if assignee_type_and_id
parts = assignee_type_and_id.split(".")
type = parts.first
id = parts.last
if type.to_s.downcase == "borrower"
Borrower.find(id)
elsif type.to_s.downcase == "partner"
Partner.find(id)
end
end
end
end
class Borrower < ApplicationRecord
# has attribute :name
belongs_to :transaction
def type_and_id
"borrower.#{id}"
end
end
class Partner < ApplicationRecord
# has attribute :name
belongs_to :transaction
def type_and_id
"partner.#{id}"
end
end
在Task
表单页面上,我想要一个结合select
和Borrowers
的单个HTML Partners
。
经典多态性说要添加assignee_type
列,但现在我正在使用2个字段而不是1个字段。
我的解决方案是将这两个组合成一个选择,使得最终值的格式为assignee_type.assignee_id
。
# form.html.erb
<%= form_for @task do |f| %>
<%= f.label :assignee_type_and_id, "Assignee" %>
<%= f.collection_select :assignee_type_and_id, @transaction.assignees, :name, :type_and_id %>
<% end %>
提交表单后,它会以borrower.123
,partner.57
等格式发布值,该值将存储在数据库列中。
当我想要检索实际任务Assignee
时,我必须在Task#assignee
方法中进行一些逆向工程。
问题
有更合适的方法吗?我自己想出了这个,这让我感到害怕,因为我知道这样的问题一定是由比我聪明的人解决的......
有没有办法让这项工作与#34;正常&#34;多态而不是强制我自己的混合版本?
更新
我遇到了Rails 4.2+ GlobalID,它似乎做了这件事。除非有理由不使用它,否则我可能会使用该实现而不是我自己的&#34; bastardized&#34;版。对于像这样的情况有没有更好的解决方案?
答案 0 :(得分:0)
对于表单跨越多个模型/复杂关联的这些类型的问题,我使用表单支持对象。它保持一切清洁和模块化。这是一篇很好的文章:https://content.pivotal.io/blog/form-backing-objects-for-fun-and-profit