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 >