简体   繁体   English

Rails在表单中的多态关联

[英]Rails polymorphic association in a form

This is a slightly unique version of a polymorphic association. 这是多态关联的略微独特的版本。 It's one of those "real world" problems that I'm struggling to solve and haven't come across many good answers so I made my own. 这是我正在努力解决的那些“现实世界”问题之一,并没有遇到很多好的答案,所以我自己做了。

A Transaction record has many Tasks and each Task has an Assignee , which can be from multiple tables. 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

On the Task form pages, I want a single HTML select that combines BOTH the Borrowers and Partners . Task表单页面,我想一个HTML select是结合了BorrowersPartners

Classic polymorphism says to add an assignee_type column, but now I'm working with 2 fields instead of one. 经典多态性说要添加一个assignee_type列,但现在我正在使用2个字段而不是一个字段。

My solution is to combine these 2 into a single select such that the final value is of the format assignee_type.assignee_id . 我的解决方案是将这两个组合成一个选择,使得最终值的格式为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 %>

When the form is submitted, it POSTs values in the format borrower.123 , partner.57 , etc, and that value gets stored in the DB column. 提交表单时,它以borrower.123partner.57等格式POST值,该值存储在DB列中。

When I want to retrieve the actual task's Assignee , I have to do a little reverse engineering as noted above in the Task#assignee method. 当我想要检索实际任务的Assignee ,我必须在Task#assignee方法中进行一些逆向工程。

Question

Is there a more appropriate way to do this? 有没有更合适的方法来做到这一点? I came up with this myself, which scares me because I know problems like this must have been solved by people much smarter than me... 我自己想出了这个,这让我感到害怕,因为我知道这样的问题一定是由比我聪明的人解决的......

Is there a way to make this work with "normal" polymorphism instead of forcing my own hybrid version? 有没有办法让这个工作与“正常”多态,而不是强制我自己的混合版本?

Update 更新

I happened upon Rails 4.2+ GlobalID, which seems to do this very thing. 我遇到了Rails 4.2+ GlobalID,它似乎做了这件事。 Unless there's a reason not to use that, I may use that implementation instead of my own "bastardized" version. 除非有理由不使用它,否则我可能会使用该实现而不是我自己的“bastardized”版本。 Is there any better solution to a situation like this? 这样的情况有没有更好的解决方案?

For these type of problems where a form spans multiple models/complex associations I use a form backing object. 对于表单跨越多个模型/复杂关联的这些类型的问题,我使用表单支持对象。 It keeps everything clean and modular. 它保持一切清洁和模块化。 Here is a good write up: https://content.pivotal.io/blog/form-backing-objects-for-fun-and-profit 这是一篇很好的文章: https//content.pivotal.io/blog/form-b​​acking-objects-for-fun-and-profit

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

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