Rails fields_for 10个嵌套的可选模型,在编辑时显示一些填充和一些空白

时间:2017-04-17 21:08:17

标签: ruby-on-rails

我有一个模型A,它可以在一对多关系中拥有多达10个关联模型B.这些嵌套模型只有一个表示单词的字符串属性。

我想显示一个表单来创建/编辑父模型和所有嵌套子项,显示10个可能模型的字段。然后,如果我只填写其中两个,将创建两个模型。

最后,在编辑模型A时,我需要显示10个字段,其中两个填充了与A数据关联的模型B,其余的空白准备填充。

使用数组尝试fields_for,但它只显示已存在的模型B实例的字段。

查看:

= form_for @a, remote: true do |f|
  = f.text_field :title, placeholder: true
  = f.fields_for :bs, @a.bs do |ff|
    / Here, for the edit action, N text fields appear, being N equals to @soup.soup_words.size
    / and I need to display 10 fields everytime, because a Soup can have up to 10 SoupWord
    / For the new action, it should display 10 empty text fields.

    / Finally, if you fill three of the 10 fields, 
    / model A should have only 3 instances of model B associated. i.e if there were 4 filled and 
    / I set one of them blank, the model B instance should be destroyed.
    = ff.text_field :word, placeholder: true
= f.submit

控制器:

class Bs < ApplicationController
  def edit
    respond_to :js
    @soup = Soup.find params[:id]
  end

  def update
    respond_to :js
    puts params
  end
end

更新

现在可以创建和编辑操作,只需在模型A中添加reject_if参数,

accepts_nested_attributes_for :bs, reject_if: proc { |attrs| attrs[:word].blank? }

并在控制器上设置build

def new
  respond_to :js
  @a = A.new
  10.times { @a.bs.build }
end

def edit
  respond_to :js
  @a = Soup.find params[:id]
  @a.bs.size.upto(9) do |sw|
    @a.bs.build
  end
end

现在我需要销毁模型B的实例,如果我在编辑操作中将它们设置为空白。

1 个答案:

答案 0 :(得分:1)

通常,您可以使用allow_destroy: true选项并传递_destroy参数来删除嵌套记录:

class Soup
  accepts_nested_attributes_for :soup_words, 
    reject_if: proc { |attrs| attrs[:word].blank? },
    allow_destroy: true
end

要获得您想要的行为,您可以使用带有隐藏输入的javascript:

= form_for @soup, remote: true do |f|
  = f.text_field :title, placeholder: true
  = f.fields_for :soup_words, @soup.soup_words do |ff|
    = ff.text_field :word, class: 'soup_word', placeholder: true
    = ff.hidden_input :_destroy
  = f.submit
$(document).on('change', '.soup_word', function(){
  var $obj = $(this);
  if (!this.value || !this.value.length) {
    // set soup_word to be destroyed
    $obj.siblings('input[name~=_destroy]').val('1');
  }
  $obj.fadeOut(50);
});

确保您已将_destroyid参数列入白名单。

def update_params
  params.require(:soup).permit(:soup_words_attributes: [:word, :id, :_destroy])
end