So by default to get STI, I would have something like: create_table :items do |t| t.column "type", :string t.column "title", :string end But if I want to store those type values in a separate table, such that I have ... create_table :items do |t| t.column "item_type_id", :string t.column "title", :string end create_table :item_types do |t| t.column "name", :string end How would I do that? Bruce
I don''t know that you do. I never thought about doing that, but I''m not sure why you''d want to. What''s your reasoning? I mainly have model files for each type and keep track of them that way. I guess that since I know what types/models there''ll be (and there won''t be many), I''m comfortable hardcoding that type of stuff. But maybe there''s a better way? Sean On 4/22/06, Bruce D''Arcus <bdarcus.lists@gmail.com> wrote:> So by default to get STI, I would have something like: > > create_table :items do |t| > t.column "type", :string > t.column "title", :string > end > > But if I want to store those type values in a separate table, such > that I have ... > > create_table :items do |t| > t.column "item_type_id", :string > t.column "title", :string > end > > create_table :item_types do |t| > t.column "name", :string > end > > How would I do that? > > Bruce > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Sean Hussey <seanhussey@...> writes:> I don''t know that you do. I never thought about doing that, but I''m > not sure why you''d want to. What''s your reasoning? > > I mainly have model files for each type and keep track of them that > way. I guess that since I know what types/models there''ll be (and > there won''t be many), I''m comfortable hardcoding that type of stuff.Two things: First, I''m really not much of RDBMS person, but it seems to me that the very logic of these systems is to normalize. If I have critical typing information (as I do here), then it seems more intuitive to me that I ought to store it in its own table, rather than as a simple string. Second, this is largely a prototype for a non-Rails app. I want programmers to be able to pick up the SQL schema and use it without having to dig into Rails-specific code to understand what''s going on. Bruce
On Apr 22, 2006, at 7:17 pm, Bruce D''Arcus wrote:> Two things: > > First, I''m really not much of RDBMS person, but it seems to me that > the very > logic of these systems is to normalize. If I have critical typing > information > (as I do here), then it seems more intuitive to me that I ought to > store it in > its own table, rather than as a simple string. > > Second, this is largely a prototype for a non-Rails app. I want > programmers to > be able to pick up the SQL schema and use it without having to dig > into > Rails-specific code to understand what''s going on. > > BruceBruce How about creating your tables like this create_table :items do |t| t.column "type", :string t.column "title", :string end create_table :item_types do |t| t.column "type_code", :string end add_index :item_types, :type_code, :unique execute "ALTER TABLE items ADD CONSTRAINT FK__items__item_types FOREIGN KEY (type) REFERENCES item_types(type_code);" Now Rails is happy, and your database has referential integrity. Admittedly, you are using a meaningful string to look up a meaningless integer (item_types.id) which is back-to-front, but it''s better than nothing. There is a better way of solving this, but you said you aren''t an RDBMS person, so maybe the above is a suitable compromise between design and complexity? Ashley
Ashley Moran <work@...> writes: [...]> Now Rails is happy, and your database has referential integrity. > Admittedly, you are using a meaningful string to look up a > meaningless integer (item_types.id) which is back-to-front, but it''s > better than nothing.Thanks Ashley. So does this suggest that it''s quite hard to make Rails "happy" with subclassing based on a value in another table? Bruce
The STI mechanism is set up this way. For one thing, usually your type column just holds the name of a class. This way rails can just create a new object of the correct type from the returned value. Otherwise, you might need to do another query to look up the relevant class type. If you really want to, you could dig into the STI code and set it up to join the type information from another table, but that seems like more work than it''s worth. On Sunday, April 23, 2006, at 1:20 PM, Bruce D''Arcus wrote:>Ashley Moran <work@...> writes: > >[...] > >> Now Rails is happy, and your database has referential integrity. >> Admittedly, you are using a meaningful string to look up a >> meaningless integer (item_types.id) which is back-to-front, but it''s >> better than nothing. > >Thanks Ashley. > >So does this suggest that it''s quite hard to make Rails "happy" with >subclassing based on a value in another table? > >Bruce > >_______________________________________________ >Rails mailing list >Rails@lists.rubyonrails.org >http://lists.rubyonrails.org/mailman/listinfo/rails_Kevin -- Posted with http://DevLists.com. Sign up and save your mailbox.
On Apr 23, 2006, at 2:20 pm, Bruce D''Arcus wrote:> So does this suggest that it''s quite hard to make Rails "happy" with > subclassing based on a value in another table?I think so. I''ve had a look through the source and it is based on extracting a string value from a single column (which defaults to "type"), in fact this is the code (base.rb): class ActiveRecord::Base class << self private def instantiate(record) object if subclass_name = record[inheritance_column] if subclass_name.empty? allocate else require_association_class(subclass_name) begin compute_type(subclass_name).allocate rescue NameError raise SubclassNotFound, "ERROR MESSAGE REMOVED" end end else allocate end object.instance_variable_set("@attributes", record) object end end end If you wanted to make this look up values in another table you could extend this along these lines: class ActiveRecord::Base class << self def inheritance_table nil end def set_inheritance_table(value = nil, &block) define_attr_method :inheritance_table, value, &block end alias :inheritance_table= :set_inheritance_table private def instantiate(record) if inheritance_table inheritance_table_class = class_name (inheritance_table).constantize if subclass_id = record[inheritance_column] # would need to make this configurable: subclass_name = inheritance_table_class.find (subclass_id).type_description end else subclass_name = record[inheritance_column] end object if subclass_name if subclass_name.empty? allocate else require_association_class(subclass_name) begin compute_type(subclass_name).allocate rescue NameError raise SubclassNotFound, "ERROR MESSAGE REMOVED" end end else allocate end object.instance_variable_set("@attributes", record) object end end end The above is mainly untested copy-and-paste, and falls way short of the standards of Rails code, but I''m sure you get the idea. Maybe you could write it as a plugin? It''s really easy to rewrite parts of the Rails core with a plugin, and the above could form the basis of it. (Also just reading the Rails code has many benefits in itself.) It depends how much work you want to put into getting the type column into its own table! I like your idea though. I think STI is messy. It''ll never win my heart but at least getting the class name into its own table is an improvement, from a database design point of view. Ashley
Reasonably Related Threads
- ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'Transactions::DummyDdnlTransaction'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Pleas
- error when adding a new table to the existing application
- Loading records during class definition
- Can''t add data during migration if column is called "type"
- select information from sqlite_master error