Rails fields_for,可选字段和验证

时间:2014-04-27 01:06:25

标签: ruby-on-rails validation fields-for

我有一个has many :bands, through: :event_bands的事件模型。 band模型validates :name, presence: true, uniqueness: true

在创建事件时,用户从多选中选择乐队,如下所示:

<p>
    <%= f.label t(:band_playing) %>
    <%= f.collection_select :band_ids, Band.order(:name), :id, :name, {}, {multiple: true} %>
</p>

但是,如果用户没有找到合适的乐队,我希望他们能够在我的活动模型中使用accepts_nested_attributes_for :bands在同一表单上创建乐队。

所以,我把它添加到我的表单中,我用一些jQuery隐藏/显示:

    <div id="new_bands">
        <p>
            <%= f.fields_for :bands do |ff| %>
                <%= ff.label "New Band Name" %>
              <%= ff.text_field :name, class: "form-control half" %>
            <% end %>
      </p>
    </div>

但是,要使fields_for正常工作,我需要像这样构建关联我的事件控制器:

def new
  @event = current_user.events.build
  1.times {@event.bands.build}
end

如果用户需要在表单中添加新频段,则效果很好,但是,如果用户没有添加新频段,则表示提交表单。它会中断,因为控制器1.times {@event.bands.build}中的行会构建一个新的Band,但提交的表单没有名称来传递Band验证。

这似乎是为了工作,我需要一种方法来切换1.times {@event.bands.build}我的表单的fields_for部分切换,但我不认为这甚至是可能。

我尝试在事件模型中使用reject_ifaccepts_nested_attributes_for :bands, reject_if: proc { |attributes| attributes['name'].blank? },但它不起作用。我的搜索让我觉得这是失败的,因为reject_if在模型保存之后才会运行,但Band.name上的验证会在保存之前运行吗?

现在,我将所有测试都放在我的控制器中:

def create
    @event = current_user.events.build(event_params)
    @event.bands.each do |band|
        if band.name.blank?
            band.destroy
        end
    end
    if @event.save
    blablabla

但这似乎与整个瘦小的控制器,胖模型方法相悖。

1 个答案:

答案 0 :(得分:1)

一个简单的解决方法:

对强力参数使用两种不同的定义。一个包括和一个不包括乐队的参数。

def event_params
    params.require(:event).permit(:name, :field1, ..., :fieldn)
end

def event_params_with_band
    params.require(:event).permit(:name, :field1, ..., :fieldn, band_attributes: [:name, ..])
end

@event = current_user.events.build(event_params)之前应用一些逻辑来合并或不合并波段参数。例如:

def create
    if params[:event][:new_band]=="true" # let's assume this comes from a 'tick' in your form
        myparams=event_params_with_band
    else
        myparams=event_params
    end
    @event = current_user.events.build(myparams)
    if @event.save
        # your responses etc
    end
end

我想你仍然需要建立event_bands的关系,但我想你知道如何做到这一点。