在Rails 4中填充自联接表

时间:2013-07-26 16:20:55

标签: ruby-on-rails ruby-on-rails-4

我有一个产品表和相关的产品表,相关的工作方式是:

Product(id: int, name: string)
RelatedProduct(id: int, product1: int, product2: int)

使用以下型号:

class Product < ActiveRecord::Base
  validates :name, :uniqueness => true, :presence => true
  has_many :relations, :class_name => "RelatedProducts", :foreign_key => :product1, inverse_of: :source
  has_many :related_products, through: :relations, :source => :destination
end

class RelatedProducts < ActiveRecord::Base
  belongs_to :source, :class_name => "Product", inverse_of: :relations
  belongs_to :destination, :foreign_key => :product2, :class_name => "Product"
end

如果我预先填充了RelatedProducts表,则显示视图将正确显示所有相关产品。我无法弄清楚如何从html中填充RelatedProducts?

<%= form_for(@product) do |f| %>

  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <div class="related-products field">
    <h3>Related Products</h3>
    <%= f.collection_check_boxes :related_products, Product.where.not(id: @product.id), :self, :name %>
  </div>

  <div class="actions">
    <%= f.submit 'Update Products' %>
  </div>
<% end %>

强参数定义为:

params.require(:product).permit(:name, related_products: [:id, :name])

1 个答案:

答案 0 :(得分:0)

我的解决方案是让视图使用ID然后提交

<div class="related-products field">
  <h3>Related Products</h3>
  <%= f.collection_check_boxes :related_products, Product.where.not(id: @product.id), :id, :name %>
</div>

然后我将它与模型中的函数相结合,将id列表转换为产品列表

def related_products_list=(ids)
  self.related_products = ids.reject(&:empty?).collect { |id| Product.find(id) }
end

这适用于提交,但复选框不会在编辑时进行预先检查。这是因为该模型讨论了产品,但视图中有一个id列表,因此不会发现匹配。我使用的解决方案是手动遍历集合以创建复选框,而不是使用collection_check_boxes。

<% Product.where.not(id: @product.id).each do |p| %>
  <%= check_box_tag 'product[related_products][]', p.id, @product.is_related_to?(p), id: "product_related_products_" + p.id.to_s %>
  <%= label_tag "product_related_products_" + p.id.to_s, p.name %>
<% end %>