Controllo degli URL nel routes.rb

Salve ragazzi Vi prego aiutatemi,

avrei bisogno di capire come evitare che l’applicazione generi le pagine
se l’url richiesto è “sbagliato”.

Mi spiego meglio nel mio rotes.rb ho il seguente codice:

map.software ‘:id/software/:keyword/:title.html’,
:controller=>‘view’,
:action=>‘programma’

dato che la :keyword e il :title vengono generate automaticamente con il
seguente codice:

software_url(:id=>guide.id,:keyword=>guide.subcategory.name,:title=>guide.title.split.join(“-”).downcase)

se nell’url metto una qualsiasi altra parola nella posizione di :keyword
oppure di :title mi viene mostrata comunque la pagina originaria legata
all’:id.

Insomma, per capirci, provate ad aprire il seguente link:

http://www.software-windows.net/99/software/firewall/r-firewall.html

e a modificare la parola firewall oppure r.firewall.

Ho necessità di risolvere il problema perché ogni tanto mi trovo che
google mi dà pagine con contenuto duplicato…

Grazie mille per l’aiuto

Ammesso che i valori di keyword e title non ti servano, esistano cio
solo
per comporre la URL, il mio consiglio di evitare di sporcare il file di
routing.

Puoi benissimo sovrascrivere il metodo ActiveRecord::Base#to_param e
fargli
ritornare il path che serve a te.

Ad esempio

class Guide < ActiveRecord::Base
  def to_param
    if persisted?
      "#{id}/#{subcategory.name.parameterize}/#{title.parameterize}"
    else
      super
    end
  end
end

A quel punto ti baster passare

software_url(:id => guide.to_param)

dopo aver cambiato la regola di routing in

map.software ':id', :controller => 'view', :action => 'programma'

Nota che l’uso di / nella generazione di path potrebbe andare in
conflitto
con le impostazioni di default di routing di Rails. Motivo per cui in
genere
si consiglia l’uso di -.
Vedi questo screencast

In tal caso puoi passare un diverso requirement al parametro :id nella
route.

map.software ':id', ... , :id => /.*/

Personalmente lo sconsiglio poich potrebbe andare in conflitto con altri
sistemi.

Altra cosa. Preferisci sempre l’uso delle risorse. In questo caso non c’
motivo per cui tu non le debba scegliere.

map.resources :software

software_path(guide)

Il vantaggio che se usi le convenzioni, Rails funziona molto meglio.

Altro consilio. Evita catene di metodi come
“guide.title.split.join(”-“).downcase” poich la possibilit che generino
bug direttamente proporzionale al numero di metodi che hai in catena.
Un
codice cos poi molto complesso da testare e questo mi lascia pensare
che
tu non abbia creato un test che validi il costrutto. Al posto, crea un
metodo nella class Guide.

In questo caso, puoi rimpiazzare il “split.join(”-“).downcase” con un
nice
#parameterize offerto da Rails senza bisogno di un metodo aggiuntivo. In
linea di massima, evita elaborazioni molto complesse on-the-fly quando
chiami altri metodo, altrimenti se dovrai generare quel path altrove
dovrai
duplicare la logica di esecuzione.

Dulcis in fundo, arriviamo al punto fondamentale. Per impedire la
duplicazione delle route il consiglio che ti d di eseguire una verifica
nel controller. In teoria la puoi eseguire anche ora, ma il motivo per
cui
ho sottolienato l’uso di #to_param e delle risose perch la rende molto
pi semplice.

Il controllo si basa sul verificare che l’URL chiamato sia quello che
normalmente la pagina comporrebbe, in alternativa reindirizzare a quello
corretto impostando un 301. Ecco un esempio (d per assunto che #show sia
la
action che mostra il programma, che nel tuo caso si chiama programma.
Personalmente sconsiglio nel modo pi assoluto di mischiare italiano con
inglese, soprattutto in Rails)

class GuidesController

  before_filter :find_guide, :only => %( show )
  before_filter :validate_url, :only => %( show )

  def show
    # ...
  end

  private

    def find_guide
      # Importante: nel caso tu adotti una struttura dove
      # il parametro :id  "sporcato" da altri valori, assicurati
      # che il find avvenga correttamente.
      @guide = Guide.find(params[:id])
    end

    def validate_url
      if request.request_uri != guide_path(@guide)
        # rigenero il path utilizzando url poich i redirect
        # dovrebbero per RFC contenere sempre URI assoluti
        redirect_to guide_url(@guide), :status => 301
      end
    end

end

Il codice un prototype. L’ho scritto al volo senza test e senza la
versione di Rails (ad esempio Rails 3 mi pare abbia deprecato
request.request_uri) quindi perdona eventuali errori. Ad ogni modo,
dovrebbe
darti diversi spunti di approfondimento.


Simone C.
Application Developer

Site & Blog: http://www.simonecarletti.com
Email: [email protected]
LinkedIn: http://linkedin.com/in/weppos
Skype: weppos