Hello. I am trying to add a feature to some of my AR classes. For example I have a class: class Hotel < ActiveRecord::Base belongs_to :hotel_type belongs_to :country belongs_to :city has_and_belongs_to_many :users has_many :rooms translated_columns :description, :features end I want to be able to specify which columns should be treated specially with something like the above translated_columns. By writing translated_columns I want to add some methods to this class that will take care of handling translations for this columns. This should probably go into some module, that can be included in class Hotel. However, when I do something like this: module CustomAr def translated_columns(*columns) columns.inspect end def first_method translate the column and save it in the db end end this file is in lib/custom_ar.rb and then class Hotel < ActiveRecord::Base require ''custom_ar'' include CustomAr translated_columns :description, :features end I get undefined method "translated_columns" for Hotel Class Also, these additional methods should extend AR functionality, so probably the above CustomAr module needs something else ( a class that extends AR ??? ). I know that it is possible in Ruby to dynamically define methods but this magic is yet unknown to me. I appreciate your comments. Thanks -- Karol Hosiawa
Hi there, Wanted to hear your thoughts on this: I''ve a Document model which habtm tags (model "Tag"). So, each document gets 0..n tags associated to it. What I want to have is a toggle_tag method that I can call by giving it an id. I''ve come up with this (in the Document model): def toggle_tag(tag_id) tag = Tag.find(tag_id) if tags.include?(tag) tags.delete(tag) else tags << tag end end The following doesn''t work (which works with arrays btw): def toggle_tag(tag_id) tag = Tag.find(tag_id) tags.delete(tag) || tags << tag end Shouldn''t delete return nil if no associations where deleted from the join table, and its args when there was something to delete? Thomas
On Tuesday 10 May 2005 10:25, Karol Hosiawa wrote:> I am trying to add a feature to some of my AR classes. > For example I have a class: > > class Hotel < ActiveRecord::Base > > belongs_to :hotel_type > belongs_to :country > belongs_to :city > has_and_belongs_to_many :users > has_many :rooms > > translated_columns :description, :features > > end > > I want to be able to specify which columns should be treated > specially with something like the above translated_columns. By > writing translated_columns > I want to add some methods to this class that will take care of > handling translations for > this columns.Here''s the latest I''ve come up with to do this, loosely patterned after how Rails itself mixes together its functionality. module RailsExtension module SensiblyNamedModule # :nodoc: def self.append_features(base) super base.extend(ClassMethods) end module ClassMethods def translated_columns(param1, param2) # handle class context dependent stuff # ... define_method(name) do # handle object context dependent stuff # ... do_translated_columns(paramX, paramY) end end end private def do_translated_columns(param1, param2) ... end end end I must admit that I''m not quite clear about how useful the indirection to the do_... method really is. The idea is to avoid duplicating the bodies of the defined methods. Then, at the end of config/environments.rb (or from a file required there), put the following ActiveRecord::Base.class_eval do include RailsExtension::SensiblyNamedModule end Alternatively, require & include your module per class require ''lib/sensibly_named_module.rb'' class Hotel < ActiveRecord::Base include RailsExtension::SensiblyNamedModule translated_columns :description, :features end As always, I appreciate comments and corrections in particular. Michael -- Michael Schuerig All good people read good books mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org Now your conscience is clear http://www.schuerig.de/michael/ --Tanita Tikaram, Twist In My Sobriety
Michael Schuerig wrote:> >I must admit that I''m not quite clear about how useful the indirection >to the do_... method really is. The idea is to avoid duplicating the >bodies of the defined methods. > >Then, at the end of config/environments.rb (or from a file required >there), put the following > >ActiveRecord::Base.class_eval do > include RailsExtension::SensiblyNamedModule >end > >Alternatively, require & include your module per class > >require ''lib/sensibly_named_module.rb'' > >class Hotel < ActiveRecord::Base > include RailsExtension::SensiblyNamedModule > > translated_columns :description, :features > >end > > >As always, I appreciate comments and corrections in particular. > >Michael > > >Thanks a lot, I used your idea and this is what came out of it: module ArExtension module Translate # :nodoc: require ''translation.rb'' require ''digest/md5'' def self.append_features(base) super base.extend(ClassMethods) end module ClassMethods def translated_columns(*columns) # handle class context dependent stuff # ... columns.each do |column| define_method("t_"+column.to_s) do |*params| # handle object context dependent stuff # ... if params.empty? language="EN" else language=params[0] end if params[1].nil? translated_column_read(column,language) else text=params[1] translated_column_write(column,language,text) end end end end end private def translated_column_read(column,language) t=Translation.find_first ["code=? and language=?", self.send(column), language] if t t.text end end def translated_column_write(column,language,text) if self.send(column) t=Translation.find_first ["code=? and language=?", self.send(column), language] t=Translation.new if t.nil? t.code=self.send(column) else t=Translation.new t.code=Digest::MD5.hexdigest(text+Time.now.to_s) if t.code.nil? end t.text=text t.language=language self.update_attribute(column,t.code) t.save end end end The code is far from pretty but it works. This is what I needed. Thanks PS. Ruby really is magical :) -- Karol