当使用浅层路由时,不同的路由需要不同的form_for参数

我在这里使用简单的表单,但这也是普通的Rails表单的一个问题。 在使用浅层路由时,form_for需要不同的参数,具体取决于它使用的上下文。

例如:为了编辑( http://localhost:3000/notes/2/edit ),_form.html.erb需要有simple_form_for(@note) 。 但是为了创build一个新的注释( http://localhost:3000/customers/2/notes/new )_form.html.erb需要simple_form_for([@customer, @note]) 。 如果要么收到错误的参数,我会得到一个方法找不到错误。

处理这个问题的最好方法是什么?

  • 我可以制作两个单独的表格,但是看起来很乱。
  • 我必须为后面的链接设置@customer,但是我可以在表单中使用一个不同的variables(比如@customer_form),而不是在编辑和更新方法中设置它,但是这不一致并且有些混乱,因为我会必须在新方法中设置@customer_form和@customer。
  • 我可以做这个人做的事情,并将其分成多个文件。 它看起来像迄今为止最好的select,但我不太喜欢它,因为你不能只打开_form.html.erb,看看发生了什么。

这些是我唯一的select吗?

示例如下:

configuration/ routes.rb中

 Billing::Application.routes.draw do resources :customers, :shallow => true do resources :notes end end 

耙路线| grep说明

  customer_notes GET /customers/:customer_id/notes(.:format) notes#index POST /customers/:customer_id/notes(.:format) notes#create new_customer_note GET /customers/:customer_id/notes/new(.:format) notes#new edit_note GET /notes/:id/edit(.:format) notes#edit note GET /notes/:id(.:format) notes#show PUT /notes/:id(.:format) notes#update DELETE /notes/:id(.:format) notes#destroy 

应用程序/视图/笔记/ _form.html.erb

 # v----------------------------- Right here <%= simple_form_for (@note), html: { class: 'form-vertical'} do |f| %> <%= f.input :content %> <%= f.button :submit %> <% end -%> 

应用程序/视图/笔记/ new.html.erb

 <h1>New note</h1> <%= render 'form' %> <%= link_to 'Back', customer_path(@customer) %> 

应用程序/视图/笔记/ edit.html.erb

 <h1>Editing note</h1> <%= render 'form' %> <%= link_to 'Show', @note %> <%= link_to 'Back', customer_path(@customer) %> 

应用程序/控制器/ notes_controller.rb

 class NotesController < ApplicationController def show @note = Note.find(params[:id]) @customer = Customer.find(@note.customer_id) respond_to do |format| format.html format.json {render json: @note } end end # GET /notes/new # GET /notes/new.json def new @note = Note.new @customer = Customer.find(params[:customer_id]) respond_to do |format| format.html # new.html.erb format.json { render json: @note } end end # GET /notes/1/edit def edit @note = Note.find(params[:id]) @customer = Customer.find(@note.customer_id) end # POST /notes # POST /notes.json def create @customer = Customer.find(params[:customer_id]) @note = @customer.notes.build(params[:note]) respond_to do |format| if @note.save format.html { redirect_to @customer, notice: 'Note was successfully created.' } format.json { render json: @note, status: :created, location: @note } else format.html { render action: "new" } format.json { render json: @note.errors, status: :unprocessable_entity } end end end # PUT /notes/1 # PUT /notes/1.json def update @note = Note.find(params[:id]) @customer = Customer.find(@note.customer_id) respond_to do |format| if @note.update_attributes(params[:note]) format.html { redirect_to @customer, notice: 'Note was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @note.errors, status: :unprocessable_entity } end end end # DELETE /notes/1 # DELETE /notes/1.json def destroy @note = Note.find(params[:id]) @note.destroy respond_to do |format| format.html { redirect_to :back } format.json { head :no_content } end end end 

如果数组中的第一个对象是表单构build器,则Rails将仅POST第二个对象。 因为这个原因, 不要 在控制器的编辑操作中 设置你的 @customer 对象 。 如果您需要访问客户对象,请通过@note调用它。

如果您使用相同的部分进行新build和编辑,则需要在控制器的新操作中设置@note.customer@customer时不会设置@customer )。

我想这就是Rails团队打算如何工作的。

我想对James的解决scheme进行一些修改:

 # app/helpers/application_helper.rb def shallow_args(parent, child) child.try(:new_record?) ? [parent, child] : child end 

而不是依靠控制器行动被称为“新” – 虽然它可能会是95%的时间 – 这只是检查,如果孩子是一个新的纪录。

以下是我想到的:

应用程序/佣工/ application_helper.rb

 module ApplicationHelper # Public: Pick the correct arguments for form_for when shallow routes # are used. # # parent - The Resource that has_* child # child - The Resource that belongs_to parent. def shallow_args(parent, child) params[:action] == 'new' ? [parent, child] : child end end 

应用程序/视图/笔记/ _form.html.erb

 <%= simple_form_for shallow_args(@customer, @note), html: { class: 'form-vertical'} do |f| %> <%= f.input :content %> <%= f.button :submit %> <% end -%> 

我不知道这是最好的解决scheme,但它似乎工作正常。