使用Rails 5.1的form_with处理嵌套资源

30

根据这个拉取请求,我可以看到需要将一个数组传递给 form_with 的model参数。然而,当我提供以下内容时:

<%= form_with(model: [@trip, @activity], local: true) do |f| %>
  ...
<% end %>
ActionView::Template::Error (undefined method activity_path' for #<#<Class:0x007f80231e3070>:0x007f8023010dd8>): Rails将返回此错误信息。
我的路由文件如下:
  resources :trips do
    resources :activities
  end

rake routes的输出如下:

     trip_activities GET    /trips/:trip_id/activities(.:format)          activities#index
                     POST   /trips/:trip_id/activities(.:format)          activities#create
   new_trip_activity GET    /trips/:trip_id/activities/new(.:format)      activities#new
  edit_trip_activity GET    /trips/:trip_id/activities/:id/edit(.:format) activities#edit
       trip_activity GET    /trips/:trip_id/activities/:id(.:format)      activities#show
                     PATCH  /trips/:trip_id/activities/:id(.:format)      activities#update
                     PUT    /trips/:trip_id/activities/:id(.:format)      activities#update
                     DELETE /trips/:trip_id/activities/:id(.:format)      activities#destroy
               trips GET    /trips(.:format)                              trips#index
                     POST   /trips(.:format)                              trips#create
            new_trip GET    /trips/new(.:format)                          trips#new
           edit_trip GET    /trips/:id/edit(.:format)                     trips#edit
                trip GET    /trips/:id(.:format)                          trips#show
                     PATCH  /trips/:id(.:format)                          trips#update
                     PUT    /trips/:id(.:format)                          trips#update
                     DELETE /trips/:id(.:format)                          trips#destroy

我的 activities_controller.rb 文件 -

  before_action :set_activity, only: %i[show update edit destroy]

  def edit; end

  def update
    dates = calculate_datetimes(params[:date_range])
    @activity.assign_attributes(name: params[:name],
                                summary: params[:summary],
                                start_datetime: dates[0],
                                end_datetime: dates[1])
    if @activity.save
      flash[:success] = 'Activity successfully updated'
      redirect_to(@trip)
    else
      set_humanized_daterange
      render :edit
    end
  end

  private 

  def set_activity
    @activity = Activity.find(params[:id])
  end

简而言之 - 我应该如何为嵌套资源设置我的form_with,为什么这个表单认为我想要使用activity_path?理想情况下,我想将此表单移动到一个局部文件中,并在我的#new和#edit操作中都使用相同的表单。

4个回答

43
尝试将模型和URL分别指定:

尝试将模型和URL分别指定:

form_with(model: @activity, url: [@trip, @activity])
根据文档,url 的值类似于传递给 url_for 或 link_to 的值,因此使用数组应该可以工作。由于数组被压缩,所以这也适用于浅嵌套。

8

您只需将要指向表单的URL添加到路由中,例如:url: trip_activity_path或者您需要访问的路径。


7

除了max answer的回答之外,如果您想支持浅层嵌套,您还可以使用:

form_with(model: [@trip, @activity])

并将您的edit.html.erb中的渲染更改为向trip传递nil,例如:

<%= render 'form', trip: nil, activity: @activity %>

同时在您的new.html.erb中一直传递trip模型。


1
更改 URL 是可以的,但您也可以更改模型,使构建器能够推断出 URL 和任何作用域等内容。
<%= form_with(model: child.new_record? ? [@parent, child] : child, local: true) do |form| %>

新建/编辑视图:<%= render 'form', child: @child %>

控制器需要从URL参数中设置@parent,这是嵌套资源的惯例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接