Rails has_many 通过表单与连接模型中的复选框和额外字段 [英] Rails has_many through form with checkboxes and extra field in the join model

查看:20
本文介绍了Rails has_many 通过表单与连接模型中的复选框和额外字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解决一个非常常见(如我所想)的任务.

共有三种模型:

class Product :分类accepts_nested_attributes_for :categorizations结尾类别分类ActiveRecord::Base归属地:产品归属地:类别验证:描述,存在:真实 # 注意这里的附加字段结尾类别类别

我的问题始于新产品/编辑表单.

创建产品时,我需要检查它所属的类别(通过复选框).我知道这可以通过创建名称类似于product[category_ids][]"的复选框来完成.但我还需要为每个检查的关系输入描述,这些关系将存储在连接模型(分类)中.

我在复杂的表单、habtm 复选框等上看到了那些漂亮的 Railscast.我几乎没有搜索过 StackOverflow.但我没有成功.

我发现了一篇帖子,其中描述了与我几乎完全相同的问题.最后一个答案对我来说很有意义(看起来这是正确的方法).但实际上效果不佳(即如果验证失败).我希望类别始终以相同的顺序显示(在新的/编辑表单中;验证前/验证后),如果验证失败等,复选框保持原位.

任何想法表示赞赏.我是 Rails 的新手(从 CakePHP 切换)所以请耐心等待并尽可能详细地写.请指点我正确的方法!

谢谢.:)

解决方案

看来我想通了!这是我得到的:

我的模型:

class Product 

形式:

<%= form_for(@product) do |f|%>...<div class="field"><%= f.label :name %><br/><%= f.text_field :name %>

<%= f.fields_for :categorizations, @product.initialized_categorizations 做 |builder|%><% 类别 = builder.object.category %><%= builder.hidden_​​field :category_id %><div class="field"><%= builder.label :enable, category.name %><%= builder.check_box :enable %>

<div class="field"><%= builder.label :description %><br/><%= builder.text_field :description %>

<%结束%><div class="actions"><%= f.submit %>

<%结束%>

和控制器:

class ProductsController <应用控制器# 如果您使用的是 rails 5+ 及更高版本,请使用 `before_action` 而不是 `before_filter`,因为 `before_filter` 在这些版本的 rails 中已被弃用/删除.before_filter :process_categorizations_attrs, 只有: [:create, :update]def process_categorizations_attrsparams[:product][:categorizations_attributes].values.each 做 |cat_attr|cat_attr[:_destroy] = true 如果 cat_attr[:enable] != '1'结尾结尾...# 剩下的都是标准的脚手架代码结尾

乍一看,它工作得很好.我希望它不会以某种方式破裂.. :)

谢谢大家.特别感谢 Sandip Ransing 参与讨论.希望对我这样的人有用.

I'm trying to solve a pretty common (as I thought) task.

There're three models:

class Product < ActiveRecord::Base  
  validates :name, presence: true

  has_many :categorizations
  has_many :categories, :through => :categorizations

  accepts_nested_attributes_for :categorizations
end

class Categorization < ActiveRecord::Base
  belongs_to :product
  belongs_to :category

  validates :description, presence: true # note the additional field here
end

class Category < ActiveRecord::Base
  validates :name, presence: true
end

My problems begin when it comes to Product new/edit form.

When creating a product I need to check categories (via checkboxes) which it belongs to. I know it can be done by creating checkboxes with name like 'product[category_ids][]'. But I also need to enter a description for each of checked relations which will be stored in the join model (Categorization).

I saw those beautiful Railscasts on complex forms, habtm checkboxes, etc. I've been searching StackOverflow hardly. But I haven't succeeded.

I found one post which describes almost exactly the same problem as mine. And the last answer makes some sense to me (looks like it is the right way to go). But it's not actually working well (i.e. if validation fails). I want categories to be displayed always in the same order (in new/edit forms; before/after validation) and checkboxes to stay where they were if validation fails, etc.

Any thougts appreciated. I'm new to Rails (switching from CakePHP) so please be patient and write as detailed as possible. Please point me in the right way!

Thank you. : )

解决方案

Looks like I figured it out! Here's what I got:

My models:

class Product < ActiveRecord::Base
  has_many :categorizations, dependent: :destroy
  has_many :categories, through: :categorizations

  accepts_nested_attributes_for :categorizations, allow_destroy: true

  validates :name, presence: true

  def initialized_categorizations # this is the key method
    [].tap do |o|
      Category.all.each do |category|
        if c = categorizations.find { |c| c.category_id == category.id }
          o << c.tap { |c| c.enable ||= true }
        else
          o << Categorization.new(category: category)
        end
      end
    end
  end

end

class Category < ActiveRecord::Base
  has_many :categorizations, dependent: :destroy
  has_many :products, through: :categorizations

  validates :name, presence: true
end

class Categorization < ActiveRecord::Base
  belongs_to :product
  belongs_to :category

  validates :description, presence: true

  attr_accessor :enable # nice little thingy here
end

The form:

<%= form_for(@product) do |f| %>
  ...
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :categorizations, @product.initialized_categorizations do |builder| %>
    <% category = builder.object.category %>
    <%= builder.hidden_field :category_id %>

    <div class="field">
      <%= builder.label :enable, category.name %>
      <%= builder.check_box :enable %>
    </div>

    <div class="field">
      <%= builder.label :description %><br />
      <%= builder.text_field :description %>
    </div>
  <% end %>

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

And the controller:

class ProductsController < ApplicationController
  # use `before_action` instead of `before_filter` if you are using rails 5+ and above, because `before_filter` has been deprecated/removed in those versions of rails.
  before_filter :process_categorizations_attrs, only: [:create, :update]

  def process_categorizations_attrs
    params[:product][:categorizations_attributes].values.each do |cat_attr|
      cat_attr[:_destroy] = true if cat_attr[:enable] != '1'
    end
  end

  ...

  # all the rest is a standard scaffolded code

end

From the first glance it works just fine. I hope it won't break somehow.. :)

Thanks all. Special thanks to Sandip Ransing for participating in the discussion. I hope it will be useful for somebody like me.

这篇关于Rails has_many 通过表单与连接模型中的复选框和额外字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆