Rails — вложенный ресурс с двумя родителями

Скажем, у меня есть дочерняя модель с двумя родительскими моделями:

Event has_many tickets

Person has_many tickets

Ticket belongs_to Event
Ticket belongs_to Person

Маршруты сопоставляются, поэтому Ticket всегда вкладывается в Event или Person:

resource :people do
  resources :tickets
end

resources :events do
  resources :tickets
end

Как ограничить действия CRUD ticket_Controller родительским ресурсом?

Сейчас я тестирую параметры и использую условные операторы:

class TicketController

  before_filter :get_person
  before_filter :get_event

  def index
    if @person do
      ...
    elsif @event do
      ...
    end
    respond_to
      ...
    end
  end

Это кажется немного утомительным делать для каждого действия. Есть ли более рельсовый СУХОЙ способ сделать это?


person Ed Haywood    schedule 06.09.2010    source источник
comment
Кстати, вы собираетесь показывать одну и ту же страницу по разным адресам? Если да, то это плохо для вашего SEO.   -  person Nikita Hismatov    schedule 14.02.2013


Ответы (2)


Самым СУХИМ было бы использовать inherited_resources:

class TicketsController < InheritedResources::Base
  belongs_to :event, :person, :polymorphic => true
end

Бум... готово. Однако, если вы не можете использовать inherited_resources по какой-либо причине, а не get_person или get_event, вы можете настроить фильтр на get_parent следующим образом:

class TicketsController < ActionController::Base
  before_filter :get_parent

  def get_parent
    if params[:person_id]
      @parent = Person.find(params[:person_id])
      @template_prefix = 'people/tickets/'
    elsif params[:event_id]
      @parent = Event.find(params[:event_id])
      @template_prefix = 'events/tickets/'
    else
      # handle this case however is appropriate to your application...
    end
  end

  # Then you can set up your index to be more generic
  def index
    @tickets = @parent.tickets
    render :template => @template_prefix + 'index'
  end
end

Изменить: я добавил @template_prefix выше, чтобы решить проблему с шаблоном, которую вы упомянули в своем комментарии.

person Dave Pirotte    schedule 06.09.2010
comment
По второму способу, скажем, мои шаблоны существенно различаются для двух типов родителей. Какой-нибудь умный способ сделать это или просто поместить операторы ответа на два шаблона внутри условного выражения? - person Ed Haywood; 06.09.2010
comment
Спасибо, теперь я понял. Я также мог бы избавиться от оператора if, используя в get_parent что-то вроде этого: @prefix = @parent.class. - person Ed Haywood; 10.09.2010
comment
И последний вопрос: я не понимаю префиксы шаблонов в вашем коде, особенно наличие «людей/» и «событий/». Шаблон индекса находится в папке '/views/ticket/'. Интерпретирует ли Rails вложенные пути к ресурсам таким образом, чтобы по-прежнему находить «тикет/индекс», когда «люди/» или «события/» добавляются в команду рендеринга? - person Ed Haywood; 10.09.2010
comment
Чтобы уточнить, мой вопрос не о путях к вложенному ресурсу, как я понимаю, а об имени файла для шаблона представления. Будут ли «events/tickets/index» и «people/tickets/index» отображать шаблон «tickets/index»? - person Ed Haywood; 10.09.2010
comment
Нет, они не будут отображать один и тот же шаблон. Я вставил это, потому что вы сказали, что ваши шаблоны значительно различаются в зависимости от того, рендерите ли вы билеты для события или билеты для человека. Если вам удобно использовать один и тот же шаблон в любом случае, то да, вы можете просто использовать «tickets/index». Но если вам нужны yourapp/events/1/tickets и yourapp/people/1/tickets для использования разных шаблонов, вам нужно контролировать это с помощью переменной (т.е. отображать 'events/tickets/index '). Имеет ли это смысл? - person Dave Pirotte; 10.09.2010
comment
Да, это так, спасибо. Я использовал два шаблона, event_index и person_index, оба в папке views/tickets. Мог ли я сделать это умнее? Если бы я использовал event/tickets/index и person/tickets/index для шаблонов, в какой папке они были бы расположены? - person Ed Haywood; 27.09.2010
comment
Они будут расположены в app/views/event/tickets/index и app/views/person/tickets/index соответственно. Если вы передаете относительный путь к render, он использует приложение/представление в качестве базы. См. документацию здесь: guides.rubyonrails.org/layouts_and_rendering.html#using-render - person Dave Pirotte; 27.09.2010
comment
Спасибо! Я извиняюсь за то, что не покопался в документации, прежде чем спросить. Должен был подумать об этом. - person Ed Haywood; 28.09.2010

Вы можете сделать это:

class TicketController

  before_filter :get_object

  def index

  end

  private

  def get_object
    type = params['event_id'] ? 'event' : 'person'
    value = type.classify.constantize.find(params[:"#{type}_id"])
    name = '@' + type
    instance_variable_set(name , value)
  end

end

Есть много способов улучшить приведенный выше код.

Вы также можете написать маршруты следующим образом:

resources :people, :has_many => :tickets

resources :events, :has_many => :tickets
person vise    schedule 06.09.2010