views:

271

answers:

1

I'm trying to create a custom MongoMapper data type in RoR 2.3.5 called Translatable:

class Translatable < String
  def initialize(translation, culture="en") 
  end 

  def languages
  end

  def has_translation(culture)?
  end

  def self.to_mongo(value) 
  end 

  def self.from_mongo(value) 
  end 
end 

I want to be able to use it like this:

class Page 
  include MongoMapper::Document 
  key :title, Translatable, :required => true 
  key :content, String 
end

Then implement like this:

p = Page.new 
p.title = "Hello" 
p.title(:fr) = "Bonjour" 
p.title(:es) = "Hola" 
p.content = "Some content here" 
p.save

p = Page.first
p.languages
=> [:en, :fr, :es]
p.has_translation(:fr)
=> true
en = p.title 
=> "Hello" 
en = p.title(:en)
=> "Hello"
fr = p.title(:fr) 
=> "Bonjour" 
es = p.title(:es) 
=> "Hola" 

In mongoDB I imagine the information would be stored like:

{ "_id" : ObjectId("4b98cd7803bca46ca6000002"), "title" : { "en" : 
"Hello", "fr" : "Bonjour", "es" : "Hola" }, "content" : "Some content 
here" } 

So Page.title is a string that defaults to English (:en) when culture is not specified.

I would really appreciate any help.

A: 

You haven't told us how Translatable stores its internal representation of the various translated versions. Aside from the MongoMapper integration, do you have a working Translatable class? If so, could you post the full source?

I'll assume, for argument's sake, Translateable has a Hash instance variable called @translated_versions, which maps from culture Symbols to translated Strings. You could then implement the MongoMapper integration as:

class Translatable < String
  attr_reader :translated_versions

  def initialize(value)
    @translated_versions = value
  end

  def self.to_mongo(value)
    value.translated_versions
  end

  def self.from_mongo(value) 
    self.new(value)
  end
end 

This would get you far enough to store your Translatable instances as MongoMapper keys. Note that p.languages and p.has_translation(:fr) would still not work, as you only defined those methods on Translatable, not Page. You'd either need to call p.title.languages and p.title.has_translation(:fr), or add code to Page to delegate those methods to title for you.

Matt Gillooly