2

简单地说,一个联系人可以有各种关联的时间窗口,这些时间窗口可能会或可能不会作为计划活动。以机智:

楷模

class Contact < ActiveRecord::Base
  has_many :schedules
  has_many :time_windows, :through => :schedules
  accepts_nested_attributes_for :schedules, :allow_destroy => true
end

class TimeWindow < ActiveRecord::Base
  has_many :schedules
  has_many :contacts, :through => :schedules
end

class Schedule < ActiveRecord::Base
  belongs_to :contact
  belongs_to :time_window
end

看法

  <% TimeWindow.all.each do |tw| %>
    <% schedule = Schedule.find_by_contact_id_and_time_window_id(@contact.id, tw.id)
       schedule ||= Schedule.new %>
    <p>
      <%= f.label tw.description %>
      <%= hidden_field_tag "contact[schedules_attributes][][id]", schedule.id %>
      <%= check_box_tag "contact[schedules_attributes][][time_window_id]",
 tw.id, @contact.time_windows.include?(tw) %>
      <%= check_box_tag "contact[schedules_attributes][][active]", nil,
 schedule.active %>
    </p>
  <% end %>

这会提交如下内容:

Parameters: { "commit" => "Update", "contact" => {
  "group_ids" => ["2"], "enabled" => "1",
  "schedules_attributes" => [ { "time_window_id"=>"1", "id"=>"46"},
   { "time_window_id" => "2", "id" => "42", "active" => "on" },
   { "time_window_id" => "3", "id" => "43"},
   { "time_window_id" => "4", "id" => "44", "active" => "on"}],
  "last_name" => ... 

控制器中的更新操作基本上是库存,除了处理另一个相关模型的另一个实例,我使用 Advanced Rails 食谱书中的“处理多个模型”示例进行编码。

根据this API doc,我认为上面应该可以工作。但是,有关时间表的任何内容都没有更新。这显示在服务器日志中:

  [4;35;1mSchedule Update (0.2ms)[0m   [0mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 42[0m
  [4;36;1mSchedule Update (0.1ms)[0m   [0;1mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 44[0m

(NetBeans 在输出中给了我那些愚蠢的“[0m”。我不知道那里出了什么问题。)

SQL 显示“活动”布尔字段在选中时设置为 0。如何让它正确设置活动位?

作为后续行动,我将如何组织它以完全摆脱 Schedule“连接”?我想我需要从表单中提交一个带有时间表的 :_delete,但是当涉及一个复选框时,我将如何有条件地执行此操作?

感谢您的任何帮助,您可以提供。事实证明,Rails 对我来说是一个广阔的主题,我想“正确地”做它。我真的很接近这里,但必须有一种方法可以做到这一点——不仅仅是正确的——而且是优雅的。视图代码感觉太麻烦了,不能成为正确的 Rails。;-)

4

1 回答 1

0

我一直在尝试不同的方法来解决这个问题,并且我想出了这个,它有效。大多。唯一的问题是它不处理没有每个“时间窗口”的“时间表”。表单将呈现,我将获得一个禁用的复选框(以防止我尝试删除不存在的内容),但我没有办法将其添加回来,并且在没有它的情况下提交会抛出参数哈希(并导致 Rails 给我一个“预期哈希(得到数组)”错误)

<% TimeWindow.all.each do |tw| %>
  <% schedule = Schedule.find_by_contact_id_and_time_window_id(@contact.id, tw.id)
     schedule ||= Schedule.new %>

<% f.fields_for "schedules_attributes[]", schedule do |sf| %>
  <p>
    <%= sf.label tw.description %>
    <%= sf.hidden_field :id %>
    <%= sf.check_box :_destroy, :disabled => schedule.new_record? %>
    <%= sf.check_box :active %>
  </p>
<% end %>

<% end %>

请注意,“schedules_attributes[]”数组会自动在您的 HTML 中的大括号内为您提供一个现有 ID(这很好),但 _attributes 散列需要一个“id”以及其他属性,以便理解子-哈希。

我在这里学到的一个重要教训是“check_box_tag”方法并没有(似乎)给我一个配对的隐藏字段供 Rails 在未检查的情况下解析。我会预料到这一点。手动添加一个会弄得一团糟,这导致我最终放弃了“fields_for”方法,并尝试了许多化身,然后才找到合适的语法来得到我想要的东西。

我已经意识到我的模型在这个设置中不太合适,所以我要改变它,但我离这个答案太近了,我想至少能看到结尾在我继续之前。

于 2010-10-01T18:07:51.527 回答