Problème N°1 : Les noms de tables.

Notre premier problème est donc que Rails considère par défaut qu'un nom de modèle doit-être un singulier et que le nom de la table correspondante doit être un pluriel.

Nous pourrions donc ajouter à l'un de nos modèles la ligne suivante :

self.pluralize_table_names = false

Mais selon moi, cette propriété étant commune à tous nos modèles, il n'est pas logique de la placer dans l'un d'entre eux. Nous allons donc spécifier cette propriété générale à tous les instances d'AciveRecord ailleurs.

Pour cela, la version 2 de Rails nous offre un dossier config/initializers où placer tous nos scripts à exécuter au démarrage de l'application après les configurations par défaut, c'est donc l'endroit parfait pour rajouter un script "do_not_pluralize.rb" avec pour contenu :

module ActiveRecord
  class Base
    self.pluralize_table_names = false
  end
end

Et voilà, nous venons d'overrider le paramètre pluralize_table_names d'ActiveRecord::Base et désormais, tout est clean.

Problème N°2 : Des chaînes de caractères comme id, drôle d'idée...

Les id de notre table "comment" (nom d'emprunt) sont donc des strings. Cela ne pose aucun problème à activeRecord qui saura évidemment faire un find("a12.bcd.3456789") si "a12.bcd.3456789" est la valeur du champ id de notre enregistrement.

Là où intervient le problème, c'est que comme vous êtes quelqu'un d'attentif, vous savez qu'avec Rails2, REST et les named routes ont enfin droit leurs heures de gloire.

Or, cela implique que l'URL d'accès à votre enregistrement soit de la forme :

/comments pour la liste des commentaires.
/comments/1 pour le commentaire 1
/comments/last pour une méthode supplémentaire last que vous auriez définie et qui vous ramènerait probablement les derniers commentaires.

Or avec notre id, l'url est de la forme "/comments/a12.bcd.3456789".

Rails pense alors que 'a12.bcd.3456789' est une méthode à appeler mais il ne la trouvera évidement jamais.

Edit du 17/04/08
Avant de vous montrer la solution que j'ai utilisé dans mon cas je vais suite au commentaire de Nicolas, de boldr.fr vous montrer une solution qui fonctionnera dans la majorité des cas (mais pas le mien.)

Afin de dire à rails d'utiliser autre chose qu'un id numérique dans les url de la forme "/comments/1" il existe une option des ressources appellée member_path. En modifiant donc votre fichier "config/routes.rb", vous pouvez indiqué à Rails d'utiliser l'id de votre table pour avoir des url de la forme "/comments/a12bcd3456789" comprises par rails.

Il suffit donc de remplacer :

map.resources :comments

par

map.resources :comments, :member_path => '/comments/:id'

Grâce à celà, vous éviterez beaucoup d'ennuis mais malheureusement, la solution ne fonctionne pas si l'id nouveau contient des '.' car rails se sert de ce caractère pour séparer la partie relative à l'url de l'action de la partie relative au format de retour (html, xml, js...).

La solution dans mon cas devait donc venir d'autre part...

Dans le cas que j'ai eu à d'étudier, le salut est venu du fait que la suite de nombre suffixant l'id (ici '3456789') était unique, j'ai donc décider d'utiliser celle-ci comme paramètre de l'URL.

Pour récupérer ce nouvel id (que j'appellerai numeric_id), j'ai donc écrit la méthode suivante :

def numeric_id
    self.id.split('.').last.to_i
  end

Il ne me restait plus qu'à indiquer à rails d'utiliser ce paramètre dans les URL grâce à la méthode to_param [1] (toujours dans mon modèle).

def to_param
    "#{self.numeric_id}"
  end

Grâce à cela, j'ai donc des url "/comments/3456789" que Rails analisera sans problème.

Dernières modifications, il faut indiquer aux méthodes agissant sur un seul enregistrement dans le controller (show, edit, update, destroy et celle que vous pourriez créer) d'utiliser notre nouvel identifiant numérique plutôt que celui par défaut.

Pour cela je rajoute une méthode find_by_numeric_id dans notre modèle :

def self.find_by_numeric_id(nid) Comment.find(:first,:conditions => ['id LIKE ? ', '%'+nid.to_s]) end

Et je modifie les méthodes précédemment citées pour utiliser notre find, ma méthode show devient donc :

# GET /comments/1
  # GET /comments/1.xml
  def show
    @comment = Comment.find_by_numeric_id(params[:id])
   
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @comment }
    end
  end

Et voilà vous avez désormais une base seine sur laquelle faire reposer la suite de votre développement.

Je me répète mais ce genre de modification ne doit être utilisé que si vous ne pouvez pas faire autrement

[1]Attention, si vous prévoyez d'utiliser la méthode to_param dans le cas d'un model Active_ressource, allez faire un tour ici afin de résoudre un bug de rails (corrigé dans la version SVN) qui fait que activeressource utilise parfois l'id au lieu de to_param.