手动更改路由时未将 ID 参数发送到控制器
ID param not being sent to Controller when manually changing routes
我查看了 Whosebug 上提供的其他答案,其中 none 回答了我的问题。这是我的代码发生的情况。
错误
undefined method `update' for nil:NilClass
问题:
看起来参数 id 没有从表单发送到控制器,因为它们在使用 byebug 的控制台中显示为 nil。
控制台读数:
(byebug) params[:id]
nil
(byebug) @support
nil
(byebug) params[:title]
nil
(byebug) params[:support]
<ActionController::Parameters {"title"=>"Test", "subtitle"=>"testing",
"website"=>"www.test.com", "type_of_support"=>"", "description"=>""}
permitted: false>
(byebug) params[:support][:id]
nil
(byebug) params[:support][:title]
"Test"
我认为问题不在于表单,因为它与用于 new/create 操作的部分表单相同,然后将参数发送到控制器并创建对象(尽管在那如果没有 id,因为它是在创建对象时生成的,而不是从表单传递的)。
你可以在我下面的代码中看到 PATCH
的路由只是 'support' 而没有 :id
参数。如果我尝试将其添加到路由中,则会收到一条错误消息,指出没有路由匹配 'support/'。所以,我必须去掉路由中的 :id
参数才能将信息传递给控制器。
我在这里不知所措。如何将 :id
传递给控制器? rails 是怎么做到的?在我手动更改路线之前,来自 resources :supports
的自动路线包含 PATCH
路线的 :id
参数并且它有效。我做错了什么,它不允许我将其添加到路线中?
代码:
config/routes.rb
get 'support', as: 'supports', to: 'supports#index'
post 'support', to: 'supports#create'
get 'support/new', as: 'new_support', to: 'supports#new'
get 'support/:id/edit', as: 'edit_support', to: 'supports#edit'
get 'support/:title', as: 'support_page', to: 'supports#show'
patch 'support/', to: 'supports#update'
put 'support/:id', to: 'supports#update'
delete 'supports/:id', to: 'supports#destroy'
佣金路线的结果:
supports GET /support(.:format) supports#index
support POST /support(.:format) supports#create
new_support GET /support/new(.:format) supports#new
edit_support GET /support/:id/edit(.:format) supports#edit
support_page GET /support/:title(.:format) supports#show
PATCH /support(.:format) supports#update
PUT /support/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
app/controllers/supports_controllers.rb
class SupportsController < ApplicationController
before_action :set_support_by_title, only: [:show]
before_action :set_support_by_id, only: [:edit, :update, :destroy]
def index
@supports = Support.all
end
def show
end
def new
@support = Support.new
end
def edit
end
def create
@support = Support.new(support_params)
respond_to do |format|
if @support.save
format.html { redirect_to @support,
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
# byebug
respond_to do |format|
if @support.update(support_params)
format.html { redirect_to @support,
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@support.destroy
respond_to do |format|
format.html { redirect_to supports_url,
notice: 'Support was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_support_by_title
@support = Support.find_by(title: params[:title])
# byebug
end
def set_support_by_id
@support = Support.find(params[:id])
# byebug
end
# Never trust parameters from the scary internet,
# only allow the white list through.
def support_params
params.require(:support).permit(:title,
:subtitle,
:website,
:type_of_support,
:description)
end
end
app/views/supports/edit.html.erb
<h1>Editing Support</h1>
<%= render 'form', support: @support %>
<%= link_to 'Show', support_page_path(@support.title) %> |
<%= link_to 'Back', supports_path %>
app/views/supports/_form.html.erb
<%= form_with(model: support, local: true) do |form| %>
<% if support.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(support.errors.count, "error") %>
prohibited this support from being saved:
</h2>
<ul>
<% support.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
Title:
<%= form.text_field :title, id: :support_title %>
</div>
<div class="field">
Subtitle:
<%= form.text_field :subtitle, id: :support_subtitle %>
</div>
<div class="field">
Website:
<%= form.text_field :website, id: :support_website %>
</div>
<div class="field">
Type of Support:
<%= form.text_field :type_of_support, id: :support_type %>
</div>
<div class="field">
Description:
<%= form.text_area :description, id: :support_description %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
在写这道题的时候,我想到了一个东西,试了一下。它奏效了。我没有自己重写所有路由,而是只写了 2 条并使用 resources :supports, except: [:index, :show]
让 rails 生成其他路由。这解决了我的问题。
说明
我知道幕后发生了一些我不明白的事情。在我开始更改路线之前,整个过程运行良好。所以,里面有些东西是不正确的。 (我仍然不知道它是什么以及如何更改它。)
我真正想要更改的唯一两条路线是用户看到的两条路线。我不关心路由在管理后端中的外观。所以,这意味着我只需要更改 index 和 show 的路由,使其对 SEO 友好并且在浏览器中看起来更好。所以,为了做到这一点,我写了这样的路线:
config/routes.rb
resources :supports, except: [:index, :show]
get 'support', as: 'support_index', to: 'supports#index'
get 'support/:title', as: 'support_page', to: 'supports#show'
然后为我创建了所有新的、创建、编辑、更新、销毁路线。这样做之后,这就是我的路线现在的样子:
supports POST /supports(.:format) supports#create
new_support GET /supports/new(.:format) supports#new
edit_support GET /supports/:id/edit(.:format) supports#edit
support PATCH /supports/:id(.:format) supports#update
PUT /supports/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
support_index GET /support(.:format) supports#index
support_page GET /support/:title(.:format) supports#show
如您所见,PATCH
路由现在正在获取参数 :id
以便能够更新记录。
现在,我只需要像这样在创建、更新和销毁后更改控制器中的一些重定向:
def create
@support = Support.new(support_params)
respond_to do |format|
if @support.save
format.html { redirect_to support_page_path(title: @support.title),
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @support.update(support_params)
format.html { redirect_to support_page_path(title: @support.title),
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@support.destroy
respond_to do |format|
format.html { redirect_to support_index_path,
notice: 'Support was successfully deleted.' }
end
end
这些 redirect_to
语句现在匹配我为索引和显示生成的路由。
现在一切正常。
所以,问题解决了,虽然我仍然不知道我之前做错了什么。任何可以发出的光将不胜感激。
我查看了 Whosebug 上提供的其他答案,其中 none 回答了我的问题。这是我的代码发生的情况。
错误
undefined method `update' for nil:NilClass
问题: 看起来参数 id 没有从表单发送到控制器,因为它们在使用 byebug 的控制台中显示为 nil。
控制台读数:
(byebug) params[:id]
nil
(byebug) @support
nil
(byebug) params[:title]
nil
(byebug) params[:support]
<ActionController::Parameters {"title"=>"Test", "subtitle"=>"testing",
"website"=>"www.test.com", "type_of_support"=>"", "description"=>""}
permitted: false>
(byebug) params[:support][:id]
nil
(byebug) params[:support][:title]
"Test"
我认为问题不在于表单,因为它与用于 new/create 操作的部分表单相同,然后将参数发送到控制器并创建对象(尽管在那如果没有 id,因为它是在创建对象时生成的,而不是从表单传递的)。
你可以在我下面的代码中看到 PATCH
的路由只是 'support' 而没有 :id
参数。如果我尝试将其添加到路由中,则会收到一条错误消息,指出没有路由匹配 'support/'。所以,我必须去掉路由中的 :id
参数才能将信息传递给控制器。
我在这里不知所措。如何将 :id
传递给控制器? rails 是怎么做到的?在我手动更改路线之前,来自 resources :supports
的自动路线包含 PATCH
路线的 :id
参数并且它有效。我做错了什么,它不允许我将其添加到路线中?
代码:
config/routes.rb
get 'support', as: 'supports', to: 'supports#index'
post 'support', to: 'supports#create'
get 'support/new', as: 'new_support', to: 'supports#new'
get 'support/:id/edit', as: 'edit_support', to: 'supports#edit'
get 'support/:title', as: 'support_page', to: 'supports#show'
patch 'support/', to: 'supports#update'
put 'support/:id', to: 'supports#update'
delete 'supports/:id', to: 'supports#destroy'
佣金路线的结果:
supports GET /support(.:format) supports#index
support POST /support(.:format) supports#create
new_support GET /support/new(.:format) supports#new
edit_support GET /support/:id/edit(.:format) supports#edit
support_page GET /support/:title(.:format) supports#show
PATCH /support(.:format) supports#update
PUT /support/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
app/controllers/supports_controllers.rb
class SupportsController < ApplicationController
before_action :set_support_by_title, only: [:show]
before_action :set_support_by_id, only: [:edit, :update, :destroy]
def index
@supports = Support.all
end
def show
end
def new
@support = Support.new
end
def edit
end
def create
@support = Support.new(support_params)
respond_to do |format|
if @support.save
format.html { redirect_to @support,
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
# byebug
respond_to do |format|
if @support.update(support_params)
format.html { redirect_to @support,
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@support.destroy
respond_to do |format|
format.html { redirect_to supports_url,
notice: 'Support was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_support_by_title
@support = Support.find_by(title: params[:title])
# byebug
end
def set_support_by_id
@support = Support.find(params[:id])
# byebug
end
# Never trust parameters from the scary internet,
# only allow the white list through.
def support_params
params.require(:support).permit(:title,
:subtitle,
:website,
:type_of_support,
:description)
end
end
app/views/supports/edit.html.erb
<h1>Editing Support</h1>
<%= render 'form', support: @support %>
<%= link_to 'Show', support_page_path(@support.title) %> |
<%= link_to 'Back', supports_path %>
app/views/supports/_form.html.erb
<%= form_with(model: support, local: true) do |form| %>
<% if support.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(support.errors.count, "error") %>
prohibited this support from being saved:
</h2>
<ul>
<% support.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
Title:
<%= form.text_field :title, id: :support_title %>
</div>
<div class="field">
Subtitle:
<%= form.text_field :subtitle, id: :support_subtitle %>
</div>
<div class="field">
Website:
<%= form.text_field :website, id: :support_website %>
</div>
<div class="field">
Type of Support:
<%= form.text_field :type_of_support, id: :support_type %>
</div>
<div class="field">
Description:
<%= form.text_area :description, id: :support_description %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
在写这道题的时候,我想到了一个东西,试了一下。它奏效了。我没有自己重写所有路由,而是只写了 2 条并使用 resources :supports, except: [:index, :show]
让 rails 生成其他路由。这解决了我的问题。
说明
我知道幕后发生了一些我不明白的事情。在我开始更改路线之前,整个过程运行良好。所以,里面有些东西是不正确的。 (我仍然不知道它是什么以及如何更改它。)
我真正想要更改的唯一两条路线是用户看到的两条路线。我不关心路由在管理后端中的外观。所以,这意味着我只需要更改 index 和 show 的路由,使其对 SEO 友好并且在浏览器中看起来更好。所以,为了做到这一点,我写了这样的路线:
config/routes.rb
resources :supports, except: [:index, :show]
get 'support', as: 'support_index', to: 'supports#index'
get 'support/:title', as: 'support_page', to: 'supports#show'
然后为我创建了所有新的、创建、编辑、更新、销毁路线。这样做之后,这就是我的路线现在的样子:
supports POST /supports(.:format) supports#create
new_support GET /supports/new(.:format) supports#new
edit_support GET /supports/:id/edit(.:format) supports#edit
support PATCH /supports/:id(.:format) supports#update
PUT /supports/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
support_index GET /support(.:format) supports#index
support_page GET /support/:title(.:format) supports#show
如您所见,PATCH
路由现在正在获取参数 :id
以便能够更新记录。
现在,我只需要像这样在创建、更新和销毁后更改控制器中的一些重定向:
def create
@support = Support.new(support_params)
respond_to do |format|
if @support.save
format.html { redirect_to support_page_path(title: @support.title),
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @support.update(support_params)
format.html { redirect_to support_page_path(title: @support.title),
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@support.destroy
respond_to do |format|
format.html { redirect_to support_index_path,
notice: 'Support was successfully deleted.' }
end
end
这些 redirect_to
语句现在匹配我为索引和显示生成的路由。
现在一切正常。
所以,问题解决了,虽然我仍然不知道我之前做错了什么。任何可以发出的光将不胜感激。