【问题标题】:Routes and namespaces on filtered index action过滤索引操作上的路由和命名空间
【发布时间】:2013-04-15 18:52:51
【问题描述】:

我有一个事件模型和一个 events_type 模型。所有事件都被分配了一个来自 event_type 模型的 id。

在我的事件索引操作/视图中,我有一个过滤器,它允许我通过查找在 url 中传递的 id 来过滤和查看所选类型的事件。例如; http:localhost:3000/events?event_type=2

我想做的是使用 event_type 名称来完成这项工作,而不是像这样; http:localhost:3000/events/film 等,我还希望能够为每个 event_type 提供唯一的元标记(这可能意味着迁移以将字段添加到我的 event_type 模型)。

谁能提供一些关于如何批准的帮助?它只是一个路由/命名空间的事情吗?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    您必须从路由中的 resources 方法中分离出来才能添加动态功能。没关系,我实际上更喜欢这样做,如下面我的回答所述。

    基本策略是重写 resources 自己所做的,添加一个额外的路由端点,可以捕获你的 :event_type。在这种情况下,我们有效地将您的 :event_type 路由插入到任何会覆盖它的内容之前。

    # routes.rb
    
    # We want the vanilla index route to come first, then deal with the rest.
    # Notice it receives no params.
    get 'events'           to: 'events#index'
    
    # Using scope or namespace gives us urls nested under that string:
    #  /events/:event_type
    # Using scope instead of namespace prevents the router for looking under a corresponding ruby module
    # AKA if this was `namespace 'event_type' do`, it would look for a
    #   `Events::EventsController#index` instead of using our `EventsController#index`.
    # All of the `as:` statements are to preserve access to the standard
    #   path+url helpers you get out of the box with `resources`.
    # All of the `constraints:` are to prevent urls from overriding each other.
    #   I don't believe they're strictly necessary in this example, but
    #   explicit is better than implicit in your routes.
    scope 'events' do
      get ':event_type/:meta',  to: 'events#index',     as: :event_by_type_and_meta, constraints: { :event_type => /[a-zA-Z]*/, :meta => /[a-zA-Z]*/ }
      get ':event_type',  to: 'events#index',     as: :event_by_type, constraints: { :event_type => /[a-zA-Z]*/ }
      get ':id/edit',     to: 'events#edit',      as: :edit_event,   constraints: { :id => /\d/ }
      get 'new',          to: 'events#new',       as: :new_event
    
      delete ':id',       to: 'events#destroy',   as: :delete_event, constraints: { :id => /\d/ }
      put ':id',          to: 'events#update',    as: :update_event, constraints: { :id => /\d/ }
      get ':id',          to: 'events#show',      as: :event,        constraints: { :id => /\d/ }
    
      post '',            to: 'events#create',     as: :create_event
      get '',             to: 'events#index',     as: :events
    end
    

    有了这些,您只需在您的EventController 中检查:event_type 并进行相应的过滤。如果使用:meta 标签,只需进一步细化过滤器。

    class EventsController < ApplicationController
    
      def index
        if params[:event_type]
          @event_type = EventType.find_by_name(params[:event_type])
          @events = Event.includes(:event_types).where(["id NOT IN (?)", @event_type.events_ids]).all
        else
          @event_type = nil
          @events = Event.filed_under(@event_type).all
        end
      end
    

    如果您不制作 RESTful API,我认为您应该避免使用 resources 句点。您的用户将遇到的应用程序的第一部分是您的 URL 结构。这确实是用户体验中最被忽视的方面。明确说明您的所有路线有助于您通过这种体验进行思考,并断言我在下面使用的更细粒度的控制。

    如果您只使用resource,也很容易留下不应该暴露的路线。明确使用 URL 有助于您了解安全漏洞。

    【讨论】:

    • 这看起来不错,我今天就试试。感谢您提供如此深入的回答!
    • 这很好用,谢谢,但我遇到了一个我最初没有考虑过的问题;如果我要使用 slug 而不是 id,我该如何处理我的活动节目?目前 events/great-band-live 将被上面的路由视为 event_type。
    • 这会使事情复杂化。在我看来,此时最简单的方法是将事件的 event_types url 命名为“events/type/:event_type”之类的名称。
    • 酷,相当明显,但这似乎有效。出于兴趣,您在第一条路线get ':event_type/:meta' 背后的想法是什么,目前没有使用它,必须注释掉才能使 'events/type/:event_type' 工作。最后,对正则表达式做了一个小修改来处理连字符,所以我们现在有了 /[a-zA-Z-]*/
    • 您最初的问题提到您“还希望能够为每个 event_type 提供唯一的元标记”,我只是在扔东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 2018-01-07
    • 2022-08-16
    • 2015-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多