【问题标题】:Match multiple paths to single controller action将多个路径匹配到单个控制器操作
【发布时间】:2017-04-24 14:05:18
【问题描述】:

在我的应用中,硬币可能属于也可能不属于网络。因此,我的routes.rb 中有以下内容:

resources :coins

resources :networks do
    resources :coins
end

您可以通过硬币#follow 关注coins 并通过硬币#unfollow 取消关注

这对于通过以下方式属于网络的硬币非常有效:

match 'networks/:network_id/coins/:id/follow', to: 'coins#follow', via: 'get', :as => :follow_coin

match 'networks/:network_id/coins/:id/unfollow', to: 'coins#unfollow', via: 'get', :as => :unfollow_coin

我也想这样做:

match 'coins/:id/follow', to: 'coins#follow', via: 'get', :as => :follow_coin

match '/coins/:id/unfollow', to: 'coins#unfollow', via: 'get', :as => :unfollow_coin

但是我在访问coins/coinname时遇到这个错误,例如:

Invalid route name, already in use: 'follow_coin' You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming.

我不清楚正确的解决方案是什么。我想将networks/:network_id/coins/:id/followcoins/:id/follow 都映射到coins#follow 操作,该操作已经准备好处理属于网络的代币和不属于网络的代币。

我怀疑即使有:

match 'networks/:network_id/coins/:id/follow', to: 'coins#follow', via: 'get', :as => :follow_coin

使用networks 资源我可以做得更好

【问题讨论】:

    标签: ruby-on-rails routing ruby-on-rails-5


    【解决方案1】:

    除了 seaify 所说的(好建议!),您还可以这样做:

    resource :coins do
      member do
        put :follow
        put :unfollow
      end
    end
    

    然后,当您想使用 network_id 时,请执行以下操作(假设您定义了 @coin 变量):

    follow_coin_path(network_id: network_id)
    

    这会给你类似的东西:

    /coins/2/follow?network_id=1
    

    您的参数将类似于:

    {..., id: 2, network_id: 1, ...}
    

    因为听起来您已经有了判断network_id 参数是否存在的逻辑。

    如果您尝试使用 coinname 作为识别变量(而不是 id),请执行以下操作:

    resources :coins, param: :coinname do 
      member do 
        put :follow
        put :unfollow
      end
    end
    

    当您执行rake routes 时,您应该会看到如下内容:

       follow_coin PUT    /coins/:coinname/follow(.:format)        coins#follow
     unfollow_coin PUT    /coins/:coinname/unfollow(.:format)      coins#unfollow
             coins GET    /coins(.:format)                         coins#index
                   POST   /coins(.:format)                         coins#create
          new_coin GET    /coins/new(.:format)                     coins#new
         edit_coin GET    /coins/:coinname/edit(.:format)          coins#edit
              coin GET    /coins/:coinname(.:format)               coins#show
                   PATCH  /coins/:coinname(.:format)               coins#update
                   PUT    /coins/:coinname(.:format)               coins#update
                   DELETE /coins/:coinname(.:format)               coins#destroy
    

    您的参数将包含以下内容:

    {..., coinname: 'bitcoin', ...}
    

    另外,当您使用link_to 时,请记住:

    link_to("Follow #{@coin.name}", follow_coin_path(@coin), method: :put)
    

    如果您不使用method: :put,则link_to 会生成get。你最终会得到No route matches [GET] "/coins/coinname/follow" 错误。

    【讨论】:

    • 谢谢!我认为这是正确的轨道。我已经按照你说的做了,但是当我在没有网络 ID 的情况下执行 follow_coin 路径时(对于不属于网络的硬币),我收到了这个路由错误:No route matches [GET] "/coins/coinname/follow"
    • 我不确定coinname 的来源。你试过follow_coin_path(@coin)(假设你定义了@coin)?
    • "coinname" 只是变量。 coins#show 实际上类似于 coins/bitcoin。当我插入<%= link_to("Follow #{@coin.name}", follow_coin_path(@coin) %> it links to coins/bitcoin/follow`并且我得到上面的路由错误
    • 感谢@jvillian 的编辑,但即使使用resources :coins do member do put :follow put :unfollow end end,我仍然收到ActionController::RoutingError (No route matches [GET] "/coins/bitcoin/follow")
    • 是的,我刚刚通过stackoverflow.com/questions/39640825/no-route-matches-get 找到了相同的答案。非常感谢!
    【解决方案2】:

    可以为不同的url设置相同的controller#action

    但是它们应该有不同的route helper,所以在rails视图或控制器中,我们可以为它们生成对应的url。

    把代码改成这个

    match 'networks/:network_id/coins/:id/follow', to: 'coins#follow', via: 'get', :as => :network_follow_coin
    match 'coins/:id/follow', to: 'coins#follow', via: 'get', :as => :follow_coin
    

    所以当使用network_follow_coin(network_id, coin_id)时,它会生成url/networks/1/coins/2/follow

    使用follow_coin_path(coin_id)时,会生成url/coins/2/follow

    为了简化代码,您应该使用resource 更好地包装和理解,减少使用match(实际上我认为永远不会)。改成这样

    resource :networks do
       resource :coins do
         member do
           put :follow
           put :unfollow
         end
       end
    end
    

    另外一点是,如果您更改数据库中的某些内容,则不应将http method 设置为get。如果是get 方法,它假设只是获取数据,没有修改。这也很危险,因为一些蜘蛛会不断访问您网站中的每个链接,它可能会激活一些不好的东西。

    【讨论】:

      猜你喜欢
      • 2016-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      相关资源
      最近更新 更多