I think I may be missing the rails idiom for working with reference data (lists of colors, sizes, shapes, etc.). I''ve generally handled it by having a table for each type like: CREATE TABLE color_types ( code VARCHAR(15) NOT NULL, name VARCHAR(80) NOT NULL, void TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY(code) ); The void column is so a color could be removed even if there are rows in tables referencing it as a FK. On the line_item (or equivalent) table would be color_type_code FK-ing back to color_types. So in rails I set up a ReferenceDataManager class (tried also as a module) to handle this. What I was planning was this: * application_helper has an instance of ReferenceDataManager (rdm) * rdm has a map of lists -- lists are lazy loaded and then accessed from the map * rdm goes directly to the DB to get the list The last point is where I''m having trouble. I was thinking I would access a list like this from a view: <%= select(''product'', ''color_type'', get_list("color_types")) %> get_list is on the application_helper. The rdm is basically like so: class ReferenceDataManager < ActiveRecord::Base @@list_map = {} def get_list(type_list) @@list_map[type_list] = retrieve_list(type_list) unless @@list_map.member?type_list end private def retrieve_list(type_list) self.find_by_sql "select * from #{type_list} t where t.VOID = 0" end end The line self.find_by_sql "select * from #{type_list}" returns that the method cannot be found: /gems/activerecord-1.10.1/lib/active_record/base.rb:1174:in `method_missing'' ./script/../config/..//lib/reference_data_manager.rb:12:in `retrieve_list'' Is there a common way such lists are handled? I was thinking that I could get away without creating little model objects for each type table, but is that a false economy? I started using YAML for the type lists, but would like to have the FK link if possible. (At least with the ReferenceDataManager I can change out the implementation for retrieve_list.) This is seeming too complex. The above method_missing is as close as I''ve gotten. I went through a lot of similar failures also. Thanks! Tom
François Beausoleil
2005-Jun-13 20:04 UTC
Re: Reference data - select list data management
Hi ! Tom Wilcoxen said the following on 2005-06-13 15:57:> Is there a common way such lists are handled? I was thinking that I > could get away without creating little model objects for each type > table, but is that a false economy? I started using YAML for the typeI went the model way. So, I have ActivityType and ContactFrequency that map to tables activity_types and contact_frequencies, respectively. I don''t have much in these reference table models, except a has_many :contacts. Conversely, Contact belongs_to :activity_types. Hope that helps, but I will be very interested in any other idioms. Bye ! François
On Monday 13 June 2005 21:57, Tom Wilcoxen wrote:> I think I may be missing the rails idiom for working with reference > data (lists of colors, sizes, shapes, etc.). I''ve generally handled > it by having a table for each type like:[snip]> class ReferenceDataManager < ActiveRecord::Base > > @@list_map = {} > > def get_list(type_list) > @@list_map[type_list] = retrieve_list(type_list) unless > @@list_map.member?type_list > end > > private > > def retrieve_list(type_list) > self.find_by_sql "select * from #{type_list} t where t.VOID = 0"Here you (well, actually ActiveRecord) are trying to create instances of ReferenceDataManager. That''s surely not what you want.> end > > end[snip]> Is there a common way such lists are handled? I was thinking that I > could get away without creating little model objects for each type > table, but is that a false economy?If you want objects from the DB, you need the little model classes. Here''s what I use in BoilerPlate: module BoilerPlate # :nodoc: module PreloadSupport # :nodoc: def self.append_features(base) super base.extend(ClassMethods) end module ClassMethods # Preload all instances of this class when this file is loaded. # The instances are available through the +all+ property. # # Changes to instances are not automatically visible, thus # in cases where instances are added/deleted/changed, you # need to call +klass.preload+ explicitly again. def preload(options = {}) cattr_accessor :all private_class_method :all self.all = self.find(:all, options) end end end end Then, in your case, you''d call ColorType.all to access a list of all the instances of the class. Feel free to change the code above to do lazy loading, but I don''t think it''s worth the effort. Michael -- Michael Schuerig The Fifth Rider of the Apocalypse mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org is a programmer. http://www.schuerig.de/michael/
On Jun 13, 2005, at 12:57 PM, Tom Wilcoxen wrote:> I think I may be missing the rails idiom for working with reference > data (lists of colors, sizes, shapes, etc.). I''ve generally handled it > by having a table for each type like: > > CREATE TABLE color_types ( > code VARCHAR(15) NOT NULL, > name VARCHAR(80) NOT NULL, > void TINYINT(1) NOT NULL DEFAULT 0, > PRIMARY KEY(code) > );How about the ColorType model? class ColorType ALL = find(:all, :conditions => "void=''1''") OPTIONS_FOR_SELECT = ALL.map { |type| [type.code, type.name] } end> <%= select(''product'', ''color_type'', get_list("color_types")) %><%= select ''product'', ''color_type'', ColorType::OPTIONS_FOR_SELECT %> jeremy
Thanks for all the responses. I think I was trying to get out of creating models for all the type tables, which I think was anti-rails-ish. It went together quite easily when I gave in and added those. I ended up using a combination of the suggestions -- thanks to all! -Tom On 6/13/05, Jeremy Kemper <jeremy-w7CzD/W5Ocjk1uMJSBkQmQ@public.gmane.org> wrote:> On Jun 13, 2005, at 12:57 PM, Tom Wilcoxen wrote: > > I think I may be missing the rails idiom for working with reference > > data (lists of colors, sizes, shapes, etc.). I''ve generally handled it > > by having a table for each type like: > > > > CREATE TABLE color_types ( > > code VARCHAR(15) NOT NULL, > > name VARCHAR(80) NOT NULL, > > void TINYINT(1) NOT NULL DEFAULT 0, > > PRIMARY KEY(code) > > ); > > How about the ColorType model? > > class ColorType > ALL = find(:all, :conditions => "void=''1''") > OPTIONS_FOR_SELECT = ALL.map { |type| [type.code, type.name] } > end > > > > <%= select(''product'', ''color_type'', get_list("color_types")) %> > > <%= select ''product'', ''color_type'', ColorType::OPTIONS_FOR_SELECT %> > > jeremy >