:has_many,:through =>在表单中更新多个属性的关联表

时间:2012-12-04 20:08:34

标签: ruby-on-rails-3 associations has-many-through

我正在努力让它正确渲染和更新。发生了什么,是我有多对多关联,关联连接包含多个属性的表。一个箱子可以有很多屏幕,一个屏幕很多箱子,并且可以为每个箱子订购一个箱子的屏幕。我当前设置中发生的另一个奇怪的项目是,每次提交表单时,关联表都没有清除旧的关联值。新值将附加到表中。

类:

class Case < ActiveRecord::Base
    attr_accessible :cases_screens_attributes

    has_many :cases_screens
    has_many :screens, :through => :cases_screens

    accepts_nested_attributes_for :cases_screens, 
                                  :allow_destroy => true,
                                  :reject_if => lambda { |p| p[:screen_id].nil? }
end

class Screen < ActiveRecord::Base
    has_many :cases_screens
    has_many :cases, :through => :cases_screens
end

class CasesScreen < ActiveRecord::Base
    attr_accessible :order

    belongs_to :case
    belongs_to :screen
end

控制器:

# GET /cases/1/edit
def edit
    @case = Case.find(params[:id])
    @cases_screens = @case.cases_screens.order("cases_screens.[order] ASC")
    @screens = Screen.where({:active => true})
end

# PUT /cases/1
# PUT /cases/1.json
def update
    @case = Case.find(params[:id])
    @cases_screens = @case.cases_screens.order("cases_screens.[order] ASC")
    @screens = Screen.where({:active => true})

    respond_to do |format|
      if @case.update_attributes(params[:case])
        format.html { redirect_to case_path(@case), :notice => t(:case_successfully_updated) }
        format.json { head :no_content }
      else
        format.html { render :action => "edit" }
        format.json { render :json => @case.errors, :status => :unprocessable_entity }
      end
    end
end

我尝试过多次尝试使用fields_for无济于事。这是我目前在_form.erb.html文件中的内容。最终目标是在案例表格中查看所有屏幕的列表,每个屏幕旁边都有一个复选框。每个复选框还具有“订单”的关联输入。提交后,将正确填充cases_screens表(如果不再选择旧值,则删除旧值)。

<div class="controls">

  <% @screens.each do |s| %>

    <label>
      <%= check_box_tag("case[cases_screens_attributes][#{s.id}][screen_id]", s.id, @case.screen_ids.include?(s.id)) %>
      <%= s.name %>
    </label>
      <%= select_tag("case[cases_screens_attributes][#{s.id}][order]", options_for_select(1..@screens.size, 2)) %>
  <% end %>

</div>

我现在已经在这个墙上撞了几天我的头,我似乎无法做到这一点。任何帮助将非常感谢。

附加说明:

我使用简单的表单,我只是做了以下内容:

<%= f.association :screens %>

并且一切都按预期工作(没有订单属性更新)。关联表已正确清理。当然,这是指向嵌套属性的方向作为罪魁祸首,但我不确定。

周三10:45更新 我现在确信这里发生的问题是没有在表单中出现cases_screens_id。通常在清理期间,rails将使用此ID清除以前的条目,然后填充新的。由于我循环遍历@screens,而不是当前存在的cases_screens(与案例相关联),我无法获取id而不会查询每一行。

我想现在,我的解决方案是将before_save方法编写到cases_screens中,这将清除cases_screens的当前条目,然后允许填充新值。

更新1:15 我至少与其中一个项目进行了一点距离,以便仅在选中复选框时才插入记录。我已将更新的:reject_if添加到上面的Case类中。我仍然没有解决为什么值只附加到表,以及为什么不删除以前的值。

更新4:00 我的最新尝试包括一个隐藏字段,如果仅设置了记录,则该字段包含cases_screens ID。这需要我在循环中创建子查询以获取当前的cases_screen_id。除了:reject_if参数之外,现在正在更新值。但是,无法再删除当前设置的值。

我无法做到这一点,它感觉不像铁轨。这个场景是我应该在控制器中手动处理数据的那个场景吗?

1 个答案:

答案 0 :(得分:0)

此时,我正在将此问题归结为设计问题。

我现在正在使用

  <% @case.cases_screens.each do |cs| %>
    <%= hidden_field_tag("case[cases_screens_attributes][#{cs.id}][id]", cs.id) %>
    <%= hidden_field_tag("case[cases_screens_attributes][#{cs.id}][screen_id]", cs.screen_id) %>
    <%= hidden_field_tag("case[cases_screens_attributes][#{cs.id}][_destroy]", 1) %>
    <label><%= check_box_tag("case[cases_screens_attributes][#{cs.id}][_destroy]", 0, @case.cases_screen_ids.include?(cs.id)) %> <%= cs.screen.name %></label>
    <%= text_field_tag("case[cases_screens_attributes][#{cs.id}][ordinality]", cs.ordinality) %>
  <% end %>

这会导致仅显示当前设置的大小写/屏幕链接。用户需要通过单独的屏幕将特定屏幕添加到案例中。