命名空间路由将错误(父)控制器操作

Namespaced route going to wrong (parent) controller action

还有一些其他问题 (1 2),但不幸的是它们没有帮助。

我有一个事件资源和一个命名空间 event_participant。路由、操作等看起来不错,但是当我尝试单击 link_to 到我的自定义命名空间操作时,路由被映射到 events#update 控制器。不知道出了什么问题!

config/routes.rb

Rails.application.routes.draw do
  resources :events
  namespace :events do
      put "/:id/add_or_rm_role" => "participants#add_or_rm_role"
  end
end

耙路

          Prefix Verb   URI Pattern                          Controller#Action
          events GET    /events(.:format)                    events#index
                 POST   /events(.:format)                    events#create
       new_event GET    /events/new(.:format)                events#new
      edit_event GET    /events/:id/edit(.:format)           events#edit
           event GET    /events/:id(.:format)                events#show
                 PATCH  /events/:id(.:format)                events#update
                 PUT    /events/:id(.:format)                events#update
                 DELETE /events/:id(.:format)                events#destroy
                 PUT    /events/:id/add_or_rm_role(.:format) events/participants#add_or_rm_role #This one looks good!

participants_controller.rb

class ParticipantsController::EventsController < ApplicationController
  load_and_authorize_resource
  def add_or_rm_role
    event = Event.find(event_participants_params.event_id)
    #add user role to event...
    redirect_to event, notice: 'Changes have been saved!'
  end

  private
    def event_participants_params
      params.permit(:role, :is_add, :event_id, :user_id)
    end
end

events_controller.rb 是自动生成的。

events/show 上的 link_to 是

    <%= link_to "Sign Up For Event", 
        event_path(role: Event::Participant.event_role_types[:participant], is_add: false, id: @event.id),
        action: :add_or_rm_role,
        method: :put, remote: true %>

当我单击 link 时,将发送以下 PUT 请求。您可以看到它正在将错误的 link 处理为错误的格式。 link_to 是一个小按钮,用于将 current_user 添加为给定事件的参与者。

Started PUT "/events/_ceEY?is_add=false&role=3" for 127.0.0.1 at 2017-07-31 20:05:10 -0400
Processing by EventsController#update as JS
  Parameters: {"is_add"=>"false", "role"=>"3", "id"=>"_ceEY"}
#......

知道什么电线在这里交叉吗?

更新

以下答案建议使用嵌套路由而不是命名空间路由,但我想继续尝试让命名空间路由工作以改进控制器中的 organization/file 结构。切换到嵌套将是核心选项,但我想先看看这会把我带到哪里。利用当前的反馈,我做了以下更改:

config/routes.rb

#...
  namespace :events do
      put :add_or_rm_role, to: 'participants#add_or_rm_role'
  end

耙路

              Prefix Verb   URI Pattern                      Controller#Action
   #...
   events_add_or_rm_role PUT    /events/add_or_rm_role(.:format) events/participants#add_or_rm_role

link_to

    <%= link_to "Sign Up For Event", 
        events_add_or_rm_role_path(role: Event::Participant.event_role_types[:participant], is_add: false, event_id: @event.id),
        method: :put, remote: true %>

events/participants_controller.rb

class Events::ParticipantsController < ApplicationController #Renamed
  #...
  def event_participants_params
    params.permit(:role, :is_add, :event_id, :user_id)
  end
end

尽管如此,controller#action 仍然是错误的(因此似乎在 id 参数中添加)

Started PUT "/events/add_or_rm_role?event_id=_ceEY&is_add=false&role=3" for 127.0.0.1 at 2017-07-31 21:37:45 -0400
Processing by EventsController#update as JS
  Parameters: {"event_id"=>"_ceEY", "is_add"=>"false", "role"=>"3", "id"=>"add_or_rm_role"}

我哪里出错了(服务器重启了)?

更新

如果我更改 Rails 路由的顺序(赋予 add_or_rm_role 更高的优先级),则会匹配正确的控制器。这是因为我的事件 ID 是字符串吗?

  namespace :events do
      put :add_or_rm_role, to: 'participants#add_or_rm_role'
  end
  resources :events

现在调用了正确的操作,但在完成之前抛出了一个错误:NameError (uninitialized constant Participant):

更新

NameError (uninitialized constant Participant): 被抛出是因为我试图通过 load_and_authorize_resource 授权(通过 CanCanCan)Events::ParticipantsController 顶部的非资源。由于模型是命名空间的,我需要手动指定资源模型:load_and_authorize_resource class: "Event::Participant"

更新

修复以上所有问题后,我收到错误 NoMethodError (undefined method 'event_id' for #<ActionController::Parameters:0x007f791dcbe240>):,我认为这与强参数有关,但最终是由使用点符号引起的:event_participants_params.event_id is损坏但 event_participants_params[:event_id] 有效。

看看你的路线

PUT    /events/:id/add_or_rm_role(.:format) events/participants#add_or_rm_role #This one looks good!

events/participants#add_or_rm_role 在名为 Events::ParticipantsController 的命名空间控制器上转换为名为 add_or_rm_role 的操作,但该控制器不存在。

您确实有 ParticipantsController::EventsController,但我认为这也不是您的意图。这转化为 EventsController class 嵌套在 ParticipantsController 模块中。我会将其重命名为 ParticipantsController.

您似乎也在尝试向控制器发送 id: @event.id,但控制器需要一个名为 event_id.

的参数

我认为您正在寻找 nest 这条路,而不是 namespace 它。我认为对路由的这种更改将使您走上正确的轨道

Rails.application.routes.draw do
  resources :events do
    put '/add_or_rm_role', as: :add_or_rm_role, to: 'participants#add_or_rm_role'
  end
end

它将生成这条路线

event_add_or_rm_role PUT    /events/:event_id/add_or_rm_role(.:format) participants#add_or_rm_role

您现在将拥有一个路由辅助方法 event_add_or_rm_role,在 URL 中带有一个 event_id 参数,将放置请求发送到 ParticipantsController#add_or_rm_role。希望这有帮助