Partager un méthode partout dans Rail


#1

Bonjour à tous pour mon premier message sur cette liste, étant un
nouvel utilisation (et déjà fan) de RoR.

Je voudrais partager une méthode qui permet de convertir les accents
en caractères correspondants non accentués.
Je l’utilise pour générer des url propres en redéfinissant la méthode
to_param

Dois-je placer ce code pour l’utiliser partout dans Rails ?

def self.normalize(str)
n = str.chars.downcase.strip.to_s
n.gsub!(/[à áâãäåāă]/, ‘a’)
n.gsub!(/æ/, ‘ae’)
n.gsub!(/[ďđ]/, ‘d’)
n.gsub!(/[çćčĉċ]/, ‘c’)
n.gsub!(/[èéêëēęěĕė]/, ‘e’)
n.gsub!(/Æ’/, ‘f’)
n.gsub!(/[ĝğġģ]/, ‘g’)
n.gsub!(/[ĥħ]/, ‘h’)
n.gsub!(/[ììíîïīĩĭ]/, ‘i’)
n.gsub!(/[įıijĵ]/, ‘j’)
n.gsub!(/[ķĸ]/, ‘k’)
n.gsub!(/[łľĺļŀ]/, ‘l’)
n.gsub!(/[ñńňņʼnŋ]/, ‘n’)
n.gsub!(/[òóôõöøōőŏŏ]/, ‘o’)
n.gsub!(/OE/, ‘oe’)
n.gsub!(/Ä…/, ‘q’)
n.gsub!(/[ŕřŗ]/, ‘r’)
n.gsub!(/[śšşŝș]/, ‘s’)
n.gsub!(/[ťţŧț]/, ‘t’)
n.gsub!(/[ùúûüūůűŭũų]/, ‘u’)
n.gsub!(/ŵ/, ‘w’)
n.gsub!(/[ýÿŷ]/, ‘y’)
n.gsub!(/[žżź]/, ‘z’)
n.gsub!(/\s+/, ’ ')
n.gsub!(/[^\sa-z0-9_-]/, ‘’)
n
end

Ensuite, je voudrais faire :
class XX < ActiveRecord::Base
def to_param
“#{id}-#{nom.gsub(/[^a-z1-9]+/i, ‘-’)}”
end
end

Merci par avance,

Cordialement,

Pierre.


#2

Pardon, je corrige, ensuite je voudrais faire :

def to_param
“#{id}-#{nom.normalize.gsub(/[^a-z1-9]+/i, ‘-’)}”
end

Bien sur :slight_smile:

Le 29/07/07, removed_email_address@domain.invalid removed_email_address@domain.invalid a écrit :


#3

Pour ma part, pour les petites modifications du langage, je le place
à la fin de environment.rb (parce que pour, c’est une modification de
l’environnement…) ; si tu en as trop, mets les dans un module et
étend tes classes à partir de là .
Donc je te propose de rajouter ceci :

class ActiveRecord::Base

tes modifications dans la classe

end

Mais peut-être que quelqu’un d’autre a une préférence pour une autre
solution.

Le 29/07/07, Pierre V.removed_email_address@domain.invalid a écrit :

nouvel utilisation (et déjà fan) de RoR.
n.gsub!(/[à áâãäåāă]/, ‘a’)
n.gsub!(/[łľĺļŀ]/, ‘l’)
n.gsub!(/[žżź]/, ‘z’)
end


Guillaume DESRAT / Zifro AKA guillaumed
http://zlab.fr/


#4

La facon logique de faire serait d en faire une methode d instance de
String
ou du multicharset de Rails 1.2.
L inconvenient etant le risque de collision dans l espace de nommage et
le fait que String commence deja a etre pollue d une centaine de methode
plus ou moins utile.

L autre possibilite est d en faire une methode statique de module, de
placer le module dans /lib avec un nom de fichier correspondant a la
version
underscore du nom du module afin que ce soit charge automatiquement par
rails. Exemlpe:

module Normalizer
def self.execute(str)

end
end

fichier normalizer.rb dans /lib, ensuite Normalizer.execute est
accessible
de partout dans rails


#5

Ca n’est peut-être pas tout à fait “iso-fonctionnel”, mais tu peux
essayer de remplacer tous tes appels à gsub par :

trans = Iconv.new(‘US-ASCII//TRANSLIT’, ‘utf-8’)
trans.iconv str

++

yk

Le 29/07/07, removed_email_address@domain.invalidremoved_email_address@domain.invalid a écrit :


#6

Merci pour vos réponses.

J’ai fait au plus simple.

J’ai ajouté dans environnement.rb les lignes suivantes :

class ActiveRecord::Base
def url_propre(str)
n = str.chars.downcase.strip.to_s
n.gsub!(/[à áâãäåāă]/, ‘a’)
n.gsub!(/æ/, ‘ae’)
n.gsub!(/[ďđ]/, ‘d’)
n.gsub!(/[çćčĉċ]/, ‘c’)
n.gsub!(/[èéêëēęěĕė]/, ‘e’)
n.gsub!(/Æ’/, ‘f’)
n.gsub!(/[ĝğġģ]/, ‘g’)
n.gsub!(/[ĥħ]/, ‘h’)
n.gsub!(/[ììíîïīĩĭ]/, ‘i’)
n.gsub!(/[įıijĵ]/, ‘j’)
n.gsub!(/[ķĸ]/, ‘k’)
n.gsub!(/[łľĺļŀ]/, ‘l’)
n.gsub!(/[ñńňņʼnŋ]/, ‘n’)
n.gsub!(/[òóôõöøōőŏŏ]/, ‘o’)
n.gsub!(/OE/, ‘oe’)
n.gsub!(/Ä…/, ‘q’)
n.gsub!(/[ŕřŗ]/, ‘r’)
n.gsub!(/[śšşŝș]/, ‘s’)
n.gsub!(/[ťţŧț]/, ‘t’)
n.gsub!(/[ùúûüūůűŭũų]/, ‘u’)
n.gsub!(/ŵ/, ‘w’)
n.gsub!(/[ýÿŷ]/, ‘y’)
n.gsub!(/[žżź]/, ‘z’)
n.gsub!(/\s+/, ’ ‘)
n.gsub!(/[^a-zA-Z0-9]/, ‘-’)
n.gsub!(/-+/,’-’)
n
end
end

Attention, pensez à redémarrer votre serveur après avoir modifié
environnement.rb !

Puis dans mes modèles, j’utilise :

def to_param
“#{id}-#{url_propre(nom)}”
end

Et c’est super :slight_smile:

Pierre.

On 29 juil, 23:24, “Guillaume “Zifro” DESRAT”


#7

On 7/29/07, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

Bonjour à tous pour mon premier message sur cette liste, étant un
nouvel utilisation (et déjà fan) de RoR.

Je voudrais partager une méthode qui permet de convertir les accents
en caractères correspondants non accentués.

J’ai une fonction similaire dans mes plugins. Attention toutefois, ta
fonction ne prend pas en compte les majuscules accentuées (le downcase
ne
fonctionne que pour l’ascii de base donc ta majuscule accentuée restera
telle quelle). Il te faudrait ajouter ça.
Si tu te contentes du français je te propose aussi d’épurer tes
expressions.
Plus tu en ajoutes plus ça prendra de temps. Si tu veux faire du
dynamique
avec to_param comme je le lis dans le fil de discussion, ta
normalisation
prendra effet plusieurs fois par page. Il vaudrait mieux ne faire que
l’utile.

Attention aussi à la méthode iconv. Elle est beaucoup plus rapide,
beaucoup
plus efficace, mais suivant les systèmes, le é peut donner soit e soit
e’
(avec l’apostrophe juste après). Perso dans ma fonction similaire j’ai
d’abord utilisé iconv, puis j’ai mis ce qui suit (ma méthode s’appelle
“to_ascii”) :

def to_ascii
Iconv.new(‘ASCII//TRANSLIT’, ‘UTF-8’).iconv(self)
end
if “é”.to_ascii != “e”
def to_ascii
# … remplacements avec gsub
end
end

Perso j’ai ajouté ça directement à String vu que je l’utilise Ã
plusieurs
endroits.

Dois-je placer ce code pour l’utiliser partout dans Rails ?

Logiquement tu fais un plugin. Dans ton répertoire /vendor/plugins tu
fais
un nouveau répertoire avec un init.rb pour charger tout ça.
Après au choix, où tu fais un module qui étendra ton modèle, ou tu étend
ta
classe String (suivant que tu veux utiliser ça juste pour les urls de
rails
ou de manière plus générique)


Éric Daspet
http://eric.daspet.name/


#8

Eric, merci beaucoup pour ses précisions.

J’ai pas encore les réflexes d’une programmation 100% orientée objet.
J’avais pas pensé à étendre la classe String :wink:


#9

Guillaume :

Pour ma part, pour les petites modifications du langage,
je le place à la fin de environment.rb (parce que pour, c’est une
modification de l’environnement…) ; si tu en as trop, mets les
dans un module et étend tes classes à partir de là.

Houlala, je trouve ça très crade, config/environment.rb est
réservé à la configuration (et d’ailleurs pour que ce soit plus clean,
dans Edge/2.0, on utilise(ra) des fichiers dans config/initializers/ )
et toute modification (aussi minime soit-elle) des classes de base
de Ruby ou de Rails devrait se faire àmha dans lib/ (ou dans un plugin
comme l’a dit Eric), dans un ou plusieurs fichiers au nom pertinent.

C’est encore plus vrai si on met son projet en open source.

Donc je te propose de rajouter ceci :

class ActiveRecord::Base

tes modifications dans la classe

end

Mais peut-être que quelqu’un d’autre a une préférence pour une
autre solution.

clair. cf plus haut.

– Jean-François.


Ruby ( http://www.rubyfrance.org ) on Rails ( http://www.railsfrance.org
)


#10

Pierre :

Bonjour à tous pour mon premier message sur cette liste,
étant un nouvel utilisation

salut et bienvenue, mais tu seras le seul dans ce cas, car
ici il n’y a que des utilisateurs de Rails.

 n = str.chars.downcase.strip.to_s
 n.gsub!(/[à áâãäåāă]/,    'a')
 n.gsub!(/æ/,            'ae')

[snip : pleins de #gsub! ]

Pour compléter les dires de mes colistiers, si tu prends
l’option non Iconv, il faut pour des raisons de performances,
que tu minimises les appels à String#gsub! en utilisant aussi
String#tr!

Ensuite 2 remarques :

class XX < ActiveRecord::Base
def to_param
“#{id}-#{nom.gsub(/[^a-z1-9]+/i, ‘-’)}”
end
end

1/ ça suppose que tous tes modèles AR::B possèdent
un attribut ‘nom’

2/ Si le nom est une chaîne vide (voire le résultat de la
normalization donne une chaîne vide), tu peux obtenir
des trucs comme “395-”

РJean-Fran̤ois.


Ruby ( http://www.rubyfrance.org ) on Rails ( http://www.railsfrance.org
)


#11

Bonsoir,

def to_ascii
Iconv.new(‘ASCII//TRANSLIT’, ‘UTF-8’).iconv(self)
end
if “é”.to_ascii != “e”
def to_ascii
# … remplacements avec gsub
end
end

A toutes fins utiles et vu que Iconv ne marche pas partout, j’ai de
mon côté ceci (dont je ne suis pas tout à fait satisfait, mais qui
marche raisonnablement bien dans mes cas):

====================
module DiacriticsFu
def self.escape(str)

ActiveSupport::Multibyte::Handlers::UTF8Handler.normalize(str,:d).split(//
u).reject { |e| e.length > 1 }.join
end
end

Les tests:

====================
require File.dirname(FILE) + ‘/…/spec_helper’
require ‘diacritics_fu’

describe “DiacriticsFu.escape” do

it “should remove the accents with grace” do
DiacriticsFu::escape(“éphémère”).should eql(“ephemere”)
DiacriticsFu::escape(“éêèïîù”).should eql(“eeeiiu”)
end

KNOWN_DIACRITICS = { “a” => “àäâ”, “e” => “éèêë”, “i” => “îï”, “o”
=> “ôö”, “u” => “üû”, “c” => “ç”,
“I” => “ÏΔ, “E” => “ÊË”, “n” => “ñ”, “O” =>
“ÔÖ”, “Y” => “Ÿ”, “y” => “ÿ”, “N” => “Ñ” }

KNOWN_DIACRITICS.each do |expected_replacement,originals|
it “should transform any of ‘#{originals}’ into
‘#{expected_replacement}’” do
originals.split(//).each do |original|
DiacriticsFu.escape(original).should eql(expected_replacement)
end
end
end
end

C’est un besoin quand même assez répandu, est-ce que quelqu’un
connaîtune petite gem simple qui ferait ce genre de chose directement ?

– Thibaut