Как отобразить форму для подмножества связанных записей, некоторые из которых еще не существуют?
У меня есть задачи и пользователи. Когда пользователь выполняет задачу, я создаю завершение, в котором есть поле для пользователя, чтобы указать, сколько времени он потратил. Мне нужна форма, которая показывает все задачи с их статусом завершения и атрибутом 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 ответа:
Я, наконец, решил эту проблему. Одним из ключей является аргумент коллекции для 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 .