为多态模型的非多态方面路由表单

时间:2016-03-20 16:08:08

标签: ruby-on-rails ruby ruby-on-rails-4

我在Event,Meeting和TaskList之间建立了一个多态关联,以便:

  • 一个事件可以有许多TaskLists,一个TaskList可以属于一个事件。
  • 会议可以有许多任务列表,任务列表可以属于一个会议。

这可行,我可以从这些模型的视图中创建task_lists。但是我的问题是我希望能够将TaskItem添加到每个TaskList中,以便:

  • TaskList可以有许多TaskItem,TaskItem可以属于一个TaskList。

我无法路由表单来创建任务项。我为此创建了一个“_form.html.erb”,并从task_item的视图中呈现它。我正在使用下面的表格,目前从事件视图,它显示表单正常,但抛出路由错误“没有路由匹配[POST]”/events/3/task_lists/new.3 < / strong>“点击提交时。

_form.html.erb

<%= form_for TaskItem.new, url: new_polymorphic_path([@listable, @task_list, @task_item]) do |f| %>
  <div class="field">
    <%= f.label :content %><br />
    <%= f.text_field :content %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

我也试过像下面这样设置它甚至不显示抛出错误的表单“表格中的第一个参数不能包含nil或为空

<%= form_for @task_item do %>
  <div class="field">
    <%= f.label :content %><br />
    <%= f.text_field :content %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

模型

class TaskList 
    belongs_to :listable, polymorphic: true
    has_many :task_items
end

class TaskItem 
    belongs_to :task_list
end

class Event
    has_many :task_lists, as: :listable
end

class Meeting
    has_many :task_lists, as: :listable
end

路由(添加:show to task_lists,only :,因为我的链接不起作用。)

  concern :has_task_lists do
    resources :task_lists, only: [:new, :index, :create, :show]
  end

  resources :events, :meetings, concerns: [:has_task_lists]

  resources :task_lists, except: [:new, :index, :create] do
    resources :task_items
  end

task_items_controller(希望它重定向到从中创建的页面项,这是task_list的show view)

def create
  @task_item = @task_list.task_items.new(task_item_params)
  if @task_item.save
    redirect_to @task_list, notice: "Task Item Created"
  else
    render :new
  end

task_lists_controller

before_action :load_listable

def show
    @task_list = @listable.task_lists.find(params[:id])
end

def load_listable
    klass = [Event, Meeting].detect { |c| params["#{c.name.underscore}_id"]}
    @listable = klass.find(params["#{klass.name.underscore}_id"])
end

1 个答案:

答案 0 :(得分:0)

这里的一个关键问题是task_items嵌套的级别太深。

  

经验法则:资源不应嵌套超过1级   深。集合可能需要由其父级确定范围,但需要具体   成员总是可以通过id直接访问,而不应该需要   作用域。
   - Jamis Buck

所以为了解决这个问题,我们会声明这样的路线:

concern :has_task_lists do
  resources :task_lists, only: [:new, :index, :create]
end

resources :events, :meetings, concerns: [:has_task_lists]

resources :task_lists, except: [:new, :index, :create] do
  resources :task_items
end

routing concern让我们重新使用嵌套路线。

因为我们已经摆脱了额外的&#34;父母&#34;我们可以简化表格:

form_for([ @task_list, @task_item || @task_list.task_items.new ])
如果您将表单嵌入另一个控制器/操作中,

@task_item || @task_list.task_items.new将阻止错误。

您实际上必须创建作用于父级的资源。只做form_for([@a, @b])不会自动关联记录 - 它只是生成url并设置表单方法(POST或PATCH)。

class TaskItemsController < ApplicationController

  before_action :set_task_list

  def new
    @task_item = @task_list.task_items.new
  end


  def create
    @task_item = @task_list.task_items.new(task_item_params)

    if @task_item.save
      redirect_to task_list_path(@task_list), notice: "Task Item Created"
    else
      render :new
    end
  end

  private

    def set_task_list
       @task_list = TaskList.find(params[:task_list_id])
    end

    # ...

end

当您致电@task_list.task_items.new时,您正在调用集合上的.new方法 - 因此新的TaskItem将设置task_list_id列。

请注意,您也可以编写redirect_to @task_list并且rails会将剩下的内容写出来。如果您需要重定向到嵌套资源,例如新创建的项目,您将执行以下操作:

redirect_to [@task_list, @task_item]