Запутался во вложенных ресурсах и аутентификации в Rails

Посмотрим, смогу ли я достаточно хорошо объяснить свои сомнения.

У меня есть модель пользователя, которой управляет Devise. Итак, в моих маршрутах у меня есть:

devise_for :users

В модели Пользователь у меня есть связь с моделью План. Ассоциация это:

User has_many Plans
Plan belongs_to User

На данный момент у меня также есть ресурс для модели плана, поэтому я могу получить все планы, показать конкретный план и так далее. Но я хочу пойти дальше.

Я хочу иметь возможность видеть планы конкретного пользователя и позволить конкретному пользователю видеть свои собственные планы и редактировать их.

Так, например, всякий раз, когда я иду в:

/пользователи/:идентификатор/планы

Я хочу иметь возможность видеть планы для этого конкретного пользователя :id. И если пользователь, который посещает этот URL-адрес, является тем, кто вошел в систему, я хочу, чтобы он мог редактировать эти планы.

Как я могу управлять всем этим поведением? Есть ли какой-нибудь драгоценный камень, который помогает с этим? Или мне нужно сделать условные выражения в представлениях, говорящих, что если current_user...


person Hommer Smith    schedule 30.12.2012    source источник


Ответы (2)


Давайте начнем с маршрутов, вы можете сделать свои маршруты следующим образом:

resources :users do
  resources :plans, only: [:index]
end

resources :plans, except: [:index]

Я использовал resources :plans внутри resources :users, чтобы иметь такой маршрут, как этот /users/:user_id/plans, а resources :plans снаружи - для остальных действий (редактирование, уничтожение, ...), которые не требуют user_id, т. е. план идентифицируется уникальным идентификатором поэтому вам не нужен user_id, чтобы получить его из базы данных для редактирования или уничтожения.

Теперь для контроллера мы можем сделать это так:

class PlansController < ApplicationController
  before_filter :is_plan_owner?, only: [:edit, :update]

  def index
    @plans = Plan.where(:user_id => params[:user_id])
  end

  def edit
    @plan = Plan.find(params[:id])
  end

  private

  def is_plan_owner?
    if current_user != Plan.find(params[:id]).user
      # Scream, shout, call 911 and/or redirect else where
    end
  end
end
person Ahmad Sherif    schedule 30.12.2012

Это ничем не отличается от использования любого другого вложенного ресурса. Вызов devise_for в файле routes.rb не обеспечивает маршрутизацию RESTful к пользовательской модели. Подумайте об этом на минутку без вложенного ресурса, со стандартной установкой Devise. Если бы вы использовали rake routes, вы бы получили что-то похожее на следующее:

  new_user_session GET  /users/sign_in(.:format)       devise/sessions#new
      user_session POST /users/sign_in(.:format)       devise/sessions#create
     user_password POST /users/password(.:format)      devise/passwords#create
 new_user_password GET  /users/password/new(.:format)  devise/passwords#new
edit_user_password GET  /users/password/edit(.:format) devise/passwords#edit
           sign_in GET  /sign_in(.:format)             devise/sessions#new

Это ничего не дает для индексации или отображения пользователей, поэтому вам все равно нужно будет добавить маршруты для этого:

resources :users, only: [:index, :show]

Теперь вы получаете:

users GET /users(.:format)     users#index
 user GET /users/:id(.:format) users#show

Хорошо, теперь мы к чему-то пришли, тогда это просто добавление вложенного ресурса, в то время как Devise не обращает на это внимания.

resources :users, only: [:index, :show] do
  resources :plans
end

Что дает вам находчивую маршрутизацию, которую вы желаете

    user_plans GET /users/:user_id/plans(.:format)          plans#index
              POST /users/:user_id/plans(.:format)          plans#create
 new_user_plan GET /users/:user_id/plans/new(.:format)      plans#new
edit_user_plan GET /users/:user_id/plans/:id/edit(.:format) plans#edit
     user_plan GET /users/:user_id/plans/:id(.:format)      plans#show
               PUT /users/:user_id/plans/:id(.:format)      plans#update
            DELETE /users/:user_id/plans/:id(.:format)      plans#destroy

И это действительно все, что нужно. Devise остается в стороне от вас на этом.

person janders223    schedule 30.12.2012