ruby-on-rails - anidados - rails formularios
Confundido sobre los recursos anidados y la autenticación en Rails (2)
Comencemos por las rutas, puedes hacer tus rutas así:
resources :users do
resources :plans, only: [:index]
end
resources :plans, except: [:index]
Usé resources :plans
dentro de resources :users
tienen una ruta como esta /users/:user_id/plans
, mientras que los resources :plans
externos son para el resto de las acciones (editar, destruir, ...) que no requieren una user_id
, es decir, un plan se identifica con una identificación única, por lo que no necesita un user_id
para buscarlo desde la base de datos para editarlo o destruirlo.
Ahora para el controlador, podemos hacerlo así:
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
Veamos si puedo explicarme lo suficiente sobre las dudas que tengo.
Tengo un modelo de usuario administrado por Devise. Entonces en mis rutas tengo:
devise_for :users
En el modelo de Usuario , tengo una asociación con el modelo de Plan . La asociación es:
User has_many Plans
Plan belongs_to User
En este punto, también tengo un recurso para el modelo del Plan, por lo que puedo buscar todos los Planes, mostrar un plan particular, etc. Pero quiero ir más allá.
Quiero poder ver los planes de un Usuario en particular y permitir que un Usuario en particular vea sus propios planes y los edite.
Entonces, por ejemplo, cada vez que voy a:
/ users /: id / planes
Quiero poder ver los planes para ese particular: usuario de id. Y si el usuario que está visitando esa url es el que está conectado, quiero que él pueda editar esos planes.
¿Cómo puedo gestionar todo este comportamiento? ¿Hay alguna joya que ayuda con eso? O necesito hacer condicionales en las vistas diciendo si current_user ...
Esto no es diferente a usar cualquier otro recurso anidado. La llamada a devise_for
en el archivo routes.rb
no proporciona enrutamiento RESTful al modelo de usuario. Piénselo sin el recurso anidado durante un minuto, con solo una instalación estándar de Devise. Si tuviera que rake routes
, obtendría algo similar a lo siguiente:
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
Esto no proporciona nada para indexar o mostrar usuarios, por lo que aún necesitaría agregar rutas para eso:
resources :users, only: [:index, :show]
Ahora obtienes:
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
Bien, ahora estamos llegando a algún lado, entonces simplemente está agregando el recurso anidado, todo el tiempo a Devise no le importa.
resources :users, only: [:index, :show] do
resources :plans
end
Lo que te da el enrutamiento ingenioso que deseas
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
Y eso es todo lo que hay que hacer. Devise se mantiene fuera de tu camino en este caso.