如何显示相关记录子集的表单,其中一些还不存在?

Tur*_*adg 5 activerecord ruby-on-rails nested-sets nested-forms

我有任务和用户.当用户完成任务时,我创建一个完成,其中有一个字段供用户指示他们花了多长时间.我需要一个表单,显示所有具有完成状态和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
Run Code Online (Sandbox Code Playgroud)

另一个方面是我想要显示一组特定任务,例如那些属于里程碑的任务.我应该在里程碑控制器上有一个表格发布到完成控制器吗?

class Milestone < ActiveRecord::Base
  has_many :tasks
  has_many :completions, :through => :tasks
end
Run Code Online (Sandbox Code Playgroud)

更新 我现在已经找了几天,我发现了很多 死路 一条.Rails表单中的这个Multiple对象很接近,但它要求所有链接对象都已存在.

让这个问题与众不同的是,有些链接尚不存在,并且没有单一的模型可以嵌套链接.例如,使用Ryan Daigle的嵌套对象形式帖子)我已经将这个工作以一种形式进行编辑所有可能的用户完成,但我需要在一个表单中编辑可能的完成的子集.我是否需要制作一个冗余对象MilestoneCompletions即has_manyCompletions和belongs_toUser?可以使用ActiveModel has_many吗?

Tur*_*adg 5

我终于解决了这个问题 一个关键是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 -%>
Run Code Online (Sandbox Code Playgroud)

使用辅助方法:

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
Run Code Online (Sandbox Code Playgroud)

请注意,在视图中已经检查并禁用了DB中已有的完成,因此无法取消选中它们.未选中状态获取值"未报告",用户模型可以过滤掉这些记录,以便它们不会进入数据库:

has_many :completions
accepts_nested_attributes_for :completions, :reject_if => proc { |attrs| attrs['status'] == 'unreported' }
Run Code Online (Sandbox Code Playgroud)

我还必须completions_attributes在User模型上创建attr_accessible.如果你可以task_ids访问,那么update将删除遗漏的完成PUT.