# -*- Ruby -*- # # Legalese: this code is licensed under the GPL v2. # # This is an hack to the rails'Inflector that extends the # rails default table name <-> model name english convention # using a set of translations from the model name to the # singular and plural, non-english, form. # # You can also select whether to put the string "id" as a prefix # or a suffix of the translated word, by setting # Inflector.translated_id_position as :after or :before. # # ActiveRecord::Base#undecorated_table_name is also overwritten, # because it doesn't call Inflector#tableize but rather reimplements # it instead. # # Lastly, you gain two more string and inflector methods # foreign_key? and foreign_class. # # Usage: # save this file into lib/inflector_translations.rb (or whatever name you like) # # put in config/environment.rb: # --8<-------------------------------------->8-- # require 'inflector_translations' # # Inflector.inflections do |inflect| # inflect.translate 'product', 'prodotto', 'prodotti' # inflect.translate 'type', 'tipologia', 'tipologie' # inflect.translate 'order', 'ordine', 'ordini' # end # # Inflector.translated_id_position = :before (or :after) # # --8<-------------------------------------->8-- # # >> Type.table_name # => "tipologie" # # >> Type.name.foreign_key # => "id_tipologia" # # >> Inflector.translated_id_position = :after # => :after # # >> Type.name.foreign_key # => "tipologia_id" # # Now you can remove many of the burden from your models: # # class Product < ActiveRecord::Base # set_table_name 'prodotti' # belongs_to :type, :foreign_key => 'id_tipologia' # has_many :orders, :foreign_key => 'id_prodotto' # end # # becomes a typical rails model, with convention and without configuration # # class Product < ActiveRecord::Base # belongs_to :type # has_many :orders # end # # -- # (C) 2006 Marcello Barnaba # module Inflector module_eval { attr_accessor :translated_id_position @translated_id_position = :before } # Returns the given string removing any 'id' prefix or suffix, # changing underscores into spaces and Capitalizing the result # def humanize(lower_case_and_underscored_word) remove_id(lower_case_and_underscored_word.to_s).gsub(/_/, " ").capitalize end # Returns a table name inferred from the given word, by removing # any ModuleName:: prefixes, transforming CamelCase into under_score # and singularizing or pluralizing, as given in the second argument. # # This method checks for and applies previously defined translations. # def tableize(word, plural = true) word = underscore(demodulize(word)) tran = plural ? :pluralize : :singularize inflections.find_translation(singularize(word), tran) || self.send(tran, word) end # Checks whether the given word looks like a foreign key column name # def foreign_key?(word) word = underscore(word) [/\w+_id$/, /^id_\w+/].find { |re| re.match(word) } ? true : false end # Returns a foreign key column name for the given word. # This method checks for and applies previously defined translations. # alias_method :orig_foreign_key, :foreign_key #:nodoc: def foreign_key(word, separate_class_name_and_id_with_underscore = true) if tran = inflections.find_translation(underscore(word)) _ = separate_class_name_and_id_with_underscore ? '_' : '' translated_id_position == :before ? "id#{_}#{tran}" : "#{tran}#{_}id" else orig_foreign_key(word, separate_class_name_and_id_with_underscore) end end # Tries to instantiate the model class referenced by the given foreign # key. # def foreign_class(word) word = remove_id(underscore(word)) constantize(camelize(inflections.find_translated(word) || singularize(word))) end protected def remove_id(word) word.gsub(translated_id_position == :after ? /_id$/ : /^id_/, '') end inflections.instance_eval { @translations = [] } class Inflections attr_reader :translations # Insert a new translation. Give the word in singular form. # def translate(word, singular, plural) @translations.insert(0, [word.underscore, {:singularize => singular, :pluralize => plural}]) end # Returns given word's translation, either singular or plural # def find_translation(word, transformation = :singularize) if tran = @translations.find { |w, sp| w == word } tran[1][transformation] end end # Returns english translation of given word # def find_translated(word) if tran = @translations.find { |w, sp| sp.values.include?(word) } tran[0] end end end end # Added String#foreign_key? and String#foreign_class, which call # the respective Inflector's method passing self as the first # parameter. # class String [:foreign_key?, :foreign_class].each { |meth| define_method(meth) { Inflector.send(meth, self) } } end # Overwrite ActiveRecord::Base#undecorated_table_name with # a facade around Inflector#tableize # module ActiveRecord class Base class << self private def undecorated_table_name(class_name = base_class.name) Inflector.tableize(class_name, pluralize_table_names) end end end end # EOF