1

我有一个事件模型和一个 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 模型的迁移)。

任何人都可以就如何批准这个提供一些帮助吗?它只是一个路由/命名空间的东西吗?

4

1 回答 1

1

You'll have to diverge from the resources method in your routes to add dynamic functionality. That's okay, I actually prefer doing so, as stated below my answer.

The basic strategy is to rewrite what resources does ourselves, adding in an extra route endpoint that can catch your :event_type. In this case, we effectively insert your :event_type routes before anything that would override it.

# 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

With that in place, you can just check for :event_type in your EventController and filter accordingly. If using the :meta tag, just refine the filter further.

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

If you're not making a RESTful API, in my opinion you should avoid using resources period. The very first part of your app your users will encounter is your URL structure. It's really the most overlooked facet of the user experience. Stating all your routes explicitly helps your think through that experience, as well as assert the finer grained control I'm using below.

It's also easy to leave routes in that really shouldn't be exposed if you just use resource. Being explicit with your URLs helps you be aware of security vulnerabilities.

于 2013-04-15T19:29:33.693 回答