代码之家  ›  专栏  ›  技术社区  ›  Betjamin Richards

需要通过关系在has_many的联接模型上创建和更新属性

  •  0
  • Betjamin Richards  · 技术社区  · 11 年前

    我有以下型号:

    class Individual < ActiveRecord::Base
      has_many visits
      has_many cities, :through => visits
      accepts_nested_attributes_for :visits, reject_if: proc { |a| a[:city_id].blank? }, allow_destroy: true
    end
    
    class Visit < ActiveRecord::Base
      belongs_to individual
      belongs_to city
    end
    
    class City < ActiveRecord::Base
      has_many visits
      has_many individuals, :through => visits
    end
    

    我正试图为每个人开发一个表格,列出我数据库中的所有城市,并允许他们勾选他们访问过的城市,然后添加有关该城市的一些基本属性。我目前拥有的是:

                 <%= form_for(individual) do |f| %>
                      <% for city in cities.each do %>
                        <tr>
                          <td>
                              <%= check_box_tag "individual[visits_attributes][][city_id]", city_id.id, individual.cities.include?(city) %>
                          </td>
                          <td>
                            <label>How good was your visit here?</label>
                            <%= select_tag "individual[visits_attributes][][sentiment]", options_for_select([ ...... ])) %>
                          </td>
                          <td>
                            <label>What was the weather like?</label>
                            <%= select_tag "individual[visits_attributes][][weather]", options_for_select([ ...... ])) %>
                          </td>
                          <td>
                            <label>Where did you stay?</label>
                            <%= select_tag "individual[visits_attributes][][accomodation]", options_for_select([ ...... ])) %>
                          </td>
                        </tr>
                      <% end %>
                      <%= f.submit "Update", :class => "btn" %>
                  <% end %>
    

    这有点奏效,但感觉不对,就像脱轨一样。此外,它会创建重复的记录,我还没能让它删除记录。

    有人能提出更好的方法吗?或者帮助我重构我已经拥有的东西?

    2 回复  |  直到 11 年前
        1
  •  0
  •   Carlos Drew    11 年前

    我没有时间写完整的答案,但要点是你想使用 fields_for 以针对对象输出关联字段。这在Rails中也被称为“嵌套模型表单”。

    查看这些资源以获得一些帮助:
    Nested Model Form Railscast
    Rails API fields_for

        2
  •  0
  •   Betjamin Richards    11 年前

    这就是我最终解决问题的方法。

    结合@carlos的输入,我使用Ryan Bates的助手动态添加新的nested_attributes字段,但将其更改为在我的城市列表中工作

    <%= form_for(individual) do |f| %>
      <% for city in cities.each do %>
        <% if individual.visits.include?(city) %>
          <% visit = f.object.visits.find_by_city_id(city.id) %>
          <%= f.fields_for(:visits, visit, child_index: visit.id ) do |existing_visit| %>
            <tr>
              <td>
                  <%= check_box_tag "individual[visits_attributes][#{visit.id}][city_id]", city.id, individual.visits.include?(city) %>
                  <%= existing_visit.hidden_field :_destroy %>
              </td>
              <td>
                <label>How good was your visit here?</label>
                <%= existing_visit.select :sentiment, options_for_select([ ...... ])) %>
              </td>
              <td>
                <label>What was the weather like?</label>
                <%= existing_visit.select :weather, options_for_select([ ...... ])) %>
              </td>
              <td>
                <label>Where did you stay?</label>
                <%= existing_visit.select :accomodation, options_for_select([ ...... ])) %>
              </td>
            </tr>
          <% end %>
        <% else %>
          <% visit = f.object.visits.build %>
          <% random_index = city.id.to_s+"_"+Time.now.to_i.to_s %>
          <%= f.fields_for(:visits, visit, child_index: random_index) do |new_visit| %>
            <tr>
              <td>
                  <%= check_box_tag "individual[visits_attributes][#{random_index}][city_id]", city.id, nil %>
              </td>
              <td>
                <label>How good was your visit here?</label>
                <%= new_visit.select :sentiment, options_for_select([ ...... ])) %>
              </td>
              <td>
                <label>What was the weather like?</label>
                <%= new_visit.select :weather, options_for_select([ ...... ])) %>
              </td>
              <td>
                <label>Where did you stay?</label>
                <%= new_visit.select :accomodation, options_for_select([ ...... ])) %>
              </td>
            </tr>
          <% end %>
        <% end %>
        <%= f.submit "Update", :class => "btn" %>
      <% end %>
    <% end %>
    

    关键是使用if语句检查记录是新记录还是现有记录,然后在fields_for helper上正确设置child_index:。

    我还必须使用check_box_tag而不是.check_box帮助程序,这样它就不会产生隐藏的复选框字段。

    当用户取消选中访问所在城市旁边的框时,我使用Javascript触发隐藏字段来删除记录。

    如果您需要更多详细信息,请与我们联系。