Как отобразить форму для подмножества связанных записей, некоторые из которых еще не существуют?


У меня есть задачи и пользователи. Когда пользователь выполняет задачу, я создаю завершение, в котором есть поле для пользователя, чтобы указать, сколько времени он потратил. Мне нужна форма, которая показывает все задачи с их статусом завершения и атрибутом time_spent. На представить, дополнения, которые существовали, должны быть обновлены, а новые должны быть созданы. Я хотел бы сделать это в Formtastic, если это возможно, но я буду доволен базовым решением Rails 3.

class Completion < ActiveRecord::Base
  belongs_to :task
  belongs_to :user

  # attribute time_spent
end

class User < ActiveRecord::Base
  has_many :completions
  has_many :tasks, :through => :completions
end    

class Task < ActiveRecord::Base
  belongs_to :milestone
  has_many :completions
  has_many :users, :through => :completions
end

Дополнительный аспект заключается в том, что я хочу показать только определенный набор задач, например, относящихся к вехе. Должен ли я иметь форму на контроллере Milestone, которая отправляет сообщения контроллеру завершений?

class Milestone < ActiveRecord::Base
  has_many :tasks
  has_many :completions, :through => :tasks
end

Обновление Я искал уже несколько дней, и я нашел Много мертв концы . Этот множественный объект в форме Rails близок, но он требует, чтобы все связывающие объекты уже существовали.

Что отличает этот вопрос, так это то, что некоторые из связей еще не существуют, и их нет. одна модель для вложенных ссылок. Например, с помощью вложенных объектных форм Райана Дейгла post) я сделал эту работу в форме для редактирования всех возможных завершений для пользователя, но мне нужно отредактировать подмножество возможных завершений в одной форме. Нужно ли создавать избыточный объект MilestoneCompletions, который has_many Завершает и belongs_to пользователь? Может ли ActiveModel has_many?

2 5

2 ответа:

Я, наконец, решил эту проблему. Одним из ключей является аргумент коллекции для fields_for . Другой способ заключается в создании коллекции из смеси существующих и новых записей.

Итак, в представлении что-то вроде:

<%= form_for @user do |f| %>
  <table>
    <tr><th>Completed</th><th>Time spent</th><th>Task</th></tr>

    <%= f.fields_for :completions, available_completions_for_milestone(@user, @milestone) do |cf| %>
      <tr>
        <td><%= cf.check_box :status, {disabled: cf.object.persisted?}, "done", "unreported" %></td>
        <td><%= cf.text_field :time_spent_text %></td>
        <td><%= cf.object.task.description %></td>
      </tr>
      <%= cf.hidden_field :task_id %>
    <% end -%>

С помощью вспомогательного метода:

def available_completions_for_milestone(user, milestone)
  user_completions = user.completions.in_milestone(milestone)    
  available = []
  milestone.tasks.each do |t|
    c = user_completions.select{|c| c.task_id == t.id}.first
    if !c then # make it
      c = user.completions.build( task: t )
    end
    available << c
  end
  available
end

Обратите внимание в представлении, что завершения уже в БД проверяются и отключаются, поэтому их нельзя отменить. Непроверенное состояние получает значение "unreported" , и пользовательская модель может отфильтровать эти записи, чтобы они не вошли БД:

has_many :completions
accepts_nested_attributes_for :completions, :reject_if => proc { |attrs| attrs['status'] == 'unreported' }

Я также должен был сделать completions_attributes attr_accessible на пользовательской модели. Если вы сделаете task_ids доступным, то update удалит дополнения, которые были оставлены вне PUT.

Я отвечаю на это сам, как на возможное решение для любых других читателей, но оно не удовлетворяет, поэтому я не отмечаю его как приемлемое.

Чтобы обойти это, в форме generation action я просто create любые отсутствующие ассоциации в "неактивном" состоянии. (Путем добавления поля status в модель Completion.) Затем я использую функцию редактирования массива" object [] " форм. RISCfuture имеет несколько полезных советов во 2-м комментарии кформам_for API docs .