2010-05-14 14 views
40

El uso de Ruby on Rails nuevo sistema de enrutamiento de 3, es posible cambiar el valor por defecto: parámetro idCambio del parámetro id en los carriles de enrutamiento

resources :users, :key => :username 

salido con las siguientes rutas

/users/new 
/users/:username 
/users/:username/edit 
...etc 

I Estoy preguntando porque, aunque el ejemplo anterior es simple, sería muy útil hacerlo en un proyecto actual en el que estoy trabajando.

¿Es posible cambiar este parámetro y, de no ser así, hay una razón particular de por qué no?

+3

Me gusta esta pregunta desde la perspectiva de "¿Cómo cambio la ID predeterminada utilizada para buscar un usuario/objeto/etc.?" Sin embargo, solo quiero poner un complemento para ocultar esa ID predeterminada, ya que tiende a ser una clave principal directamente de la base de datos y hay todo tipo de razones de seguridad por las que no se debe exponer ese valor (facilitando los ataques de inyección SQL, identificadores imaginables para otros usuarios, ...). En particular, usar el nombre de usuario permite el ataque directo en una cuenta (adivinar pwd). Usar un gran valor aleatorio y único hace que todo esto sea mucho más difícil. Aclamaciones. –

+0

* Asegúrese de leer las respuestas después del aceptado * – blnc

Respuesta

34

Si te entiendo correctamente, lo que quieres es tener el username en lugar de id en tu url, ¿verdad?

Puede hacerlo anulando el método to_param en su modelo. Puede obtener más información here.

+0

Supongo que esta es la única manera de hacerlo por el momento. Parece una especie de rotonda sin embargo. – joeellis

+1

Gracias por este puntero, resolvió completamente mi problema. Vine aquí buscando cómo cambiar este b/c, por política, consideramos que recuperar por ID de clave principal de la web es un problema de seguridad. En su lugar, agregamos un gran valor aleatorio y único al objeto (SecureRandom.urlsafe_base64 (15)) y lo usamos como la ID devuelta desde to_param y cuando las API RESTful encuentran_by_OID. Tal vez, cuando entiendo Ruby/Rails mejor, esto se puede convertir en una gema. –

0

Pase el nombre de usuario como entrada a los ayudantes de ruta.

En el código de la vista:

user_path(u.username) #/users/john 

En su controlador tratan el id recibidos como username:

def show 
    user = User.find_by_username!(params[:id]) 
    ... 
end 
+0

Eso es algo de lo que he estado haciendo, pero creo que sería más sencillo hacer algo como User.find_by_username (params [: username]) en el código. Realmente me pregunto por qué Rails no permite esto en general. ¿Está en contra de algún principio de REST quizás? – joeellis

1

Aunque la respuesta ha sido aceptada por el autor de la pregunta, pero no es un método simple para hacer esto. Escribe este código en tu controlador.

authorize_resource :find_by => :username 

y en su vista, donde desee mostrar el enlace, escriba este código.

<%= link_to "Username", user_path(u.username) %> 

No necesita ningún otro cambio en sus rutas o controlador.

ACTUALIZACIÓN: Esto solo funcionará si está utilizando la gema CanCan.

+0

Ese parece ser un método CanCan. No se menciona en la api rails en absoluto. [apidock.com] (http://apidock.com/rails/search?query=authorize_resource) [api.rubyonrails.org] (http://api.rubyonrails.org/?q=authorize_resource) – Nultyi

+0

Sí, eso es un método CanCan. Olvidé mencionar eso en mi respuesta. He actualizado la respuesta. – KULKING

61

En su recorrido se pueden utilizar

resources :user, param: :username 
+4

esta debería ser la respuesta aceptada, estoy mucho más cómodo agregando un argumento a una ruta que sobreescribir el método 'to_param' – omnikron

+1

@omnikron depende de lo que intente lograr en su aplicación, a veces necesita hacer ambas cosas (por ejemplo, cuando quieres pasar directamente tu recurso a los helpers de enrutamiento 'user_path @ user' para que no tengas que hacer' user_path @ user.nombre de usuario') ... pero sí, tienes razón, esto es elegante cuando solo quieres quiere funcionalidad de enrutamiento – equivalent8

+3

Esto solo funciona en Rails 4+ –

23

para Ruby on Rails 4.1.4 (y posiblemente versiones anteriores) que tiene que hacer lo tantoj.. y Ujjwal sugirió:

1) En config/routes.rb, añadir:

resources :user, param: :username 

2) En app/models/user.rb, añadir:

def to_param 
    username 
end 

En usted solo hace # 1, entonces todas sus rutas serán correctas, como se puede ver en rake routes:

$ rake routes 
    Prefix Verb URI Pattern     Controller#Action 
user_index GET /user(.:format)    user#index 
      POST /user(.:format)    user#create 
    new_user GET /user/new(.:format)   user#new 
edit_user GET /user/:username/edit(.:format) user#edit 
     user GET /user/:username(.:format)  user#show 
      PATCH /user/:username(.:format)  user#update 
      PUT /user/:username(.:format)  user#update 
      DELETE /user/:username(.:format)  user#destroy 

Sin embargo, los métodos de ayuda que crean una URL basada en una instancia User seguirán incluyendo el id en la url, p. /user/1. Para obtener el username en las urls construidas, debe anular to_param como en el n. ° 2.

+4

el 2) se pierde la mayor parte del tiempo cuando aparece esta pregunta; esta debería ser la respuesta aceptada – Ben

+0

** funciona con ** 'rails 5.0.2' ** y **' ruby ​​2.4.1' – blnc

Cuestiones relacionadas