Rails挂载引擎编辑记录时触发NoMethodError问题求助
问题原因
- 使用
form_with model: @country时,Rails会自动尝试调用country_path这个RESTful路由助手,但当前宿主应用和引擎都未定义该路由:- 宿主应用没有为Country模型配置RESTful路由(比如
resources :countries) - 引擎内仅定义了自定义的
edit和post /:id/update路由,且引擎挂载时设置了as: 'country_table'前缀,所有引擎路由助手都需要带上该前缀,form_with无法自动推断。
- 宿主应用没有为Country模型配置RESTful路由(比如
- 另外引擎内的update路由使用
post方法,不符合Rails更新操作使用patch/put的惯例,也会导致表单请求方法不匹配。
解决方案
提供两种可行方案,按需选择:
方案1:手动指定表单提交路径和方法
直接修改引擎的edit.html.erb视图,明确指定表单要提交的引擎路由:
<%= form_with model: @country, url: country_table_update_path(id: @country.id), method: :post do |form| %> <%= form.text_field :name %> <%= form.submit %> <% end %>
说明:
- 在宿主应用根目录运行
rails routes,可以看到引擎内的post '/:id/update'路由会生成country_table_update_path这个助手(因挂载时设置了as: 'country_table') - 手动指定
method: :post来匹配引擎路由的请求方法。
方案2:改为RESTful风格路由(推荐)
如果想遵循Rails最佳实践,调整引擎路由和代码:
- 修改引擎的
config/routes.rb:
MyEngine::Engine.routes.draw do scope module: 'table' do post '/', action: 'index' resources :countries, only: [:edit, :update] end end
- 给引擎的
TableController补充update方法(原代码仅包含edit,需添加更新逻辑):
module MyEngine class TableController < ApplicationController def edit @country = Country.find(params[:id]) end def update @country = Country.find(params[:id]) if @country.update(country_params) redirect_to country_table_countries_path, notice: 'Country updated successfully' else render :edit end end private def country_params params.require(:country).permit(:name) end end end
- 修改
edit.html.erb视图,让form_with正确识别引擎命名空间:
<%= form_with model: [country_table, @country] do |form| %> <%= form.text_field :name %> <%= form.submit %> <% end %>
说明:
[country_table, @country]用于告知Rails使用引擎命名空间前缀生成路由,对应的助手为country_table_country_path,匹配RESTful更新路由- RESTful路由默认使用
patch方法,符合Rails惯例。
验证方式
在宿主应用根目录执行rails routes,可查看所有可用路由助手,确认路径和方法是否正确。
内容的提问来源于stack exchange,提问作者Maxime
相关产品推荐
相关产品推荐

