Hello, I''ve been keeping my eye on Rails for sometime and my ''enterprise app'' has finally hit the 1.0 mark, so I have some down time and I''m considering migrating it over to Rails. Currently it''s in Java using Jsp/Jstl, Spring, Hibernate, and Postgres 8.x. Currently I have about 85k LOC for Java, 11k LOC for Jsp/Jstl, and 12k LOC for xml (ugh). I''ve been reading for the past days about some of the issues that will affect my migration: - Compoment based views and controllers - Transactions that are run at my service level that envelop multiple DAO classes - Quartz (cron-like) scheduling - Email notifications - Multi-user, multi-company, roles and groups definitions and restrictions So far I''ve successfully used a few ActiveRecord Model objects from my existing development db. I understand the controllers and have successfully used scaffold to generate some simple CRUD admin stuff. However, now I''m trying for a Model & Controller which is part of our content management system. We have a table layout like so: Content ------- id - prim key, auto incr title - text ContentNews ----------- content_id - prim key/foreign key to content(id) next_article - number ContentEvent ------------ content_id - prim key/foreign key to content(id) location - text start_date - date end_date - date ContentJob ---------- content_id - prim key/foreign key to content(id) contact_info - text expire_date - date In Hibernate, I could just have the news, events, and job classes all subclass the content class. It managed prim/foreign key insertions and everything else via my mapping file and acted just like regular Java subclasses. However, reading about ActiveRecord, it''s obvious it doesn''t (yet) handle class table inheritance. Unfortunately for me, I cannot re-design these tables and have this relationship in a few other places in my db. Does anyone have any suggestions on how to get past this? I noticed in the Rails development site, there was a CTI issue in the ''Research'' section, but no resolution yet. I don''t mind hacking some stuff in to get it to work, but if something official is going to be rolled into the next release, then maybe I can just use those patches. I''m kinda getting excited to see how much conversion I can get done in the next month. However, CTI is critical for my app and if there''s no way around it (besides re-doing existing tables) then I''m gonna have to go back to Java and wait for this functionality to make it into an official release. :( Suggestions, links, etc all helpful. Thanks, Jason
On 10/19/05, Jason Lee <jasonlee9-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hello, > > I''ve been keeping my eye on Rails for sometime and my ''enterprise > app'' has finally hit the 1.0 mark, so I have some down time and I''m > considering migrating it over to Rails. Currently it''s in Java using > Jsp/Jstl, Spring, Hibernate, and Postgres 8.x. Currently I have about > 85k LOC for Java, 11k LOC for Jsp/Jstl, and 12k LOC for xml (ugh). > > I''ve been reading for the past days about some of the issues that > will affect my migration: > > - Compoment based views and controllers > - Transactions that are run at my service level that envelop multiple > DAO classes > - Quartz (cron-like) scheduling > - Email notifications > - Multi-user, multi-company, roles and groups definitions and > restrictions > > So far I''ve successfully used a few ActiveRecord Model objects from > my existing development db. I understand the controllers and have > successfully used scaffold to generate some simple CRUD admin stuff. > > However, now I''m trying for a Model & Controller which is part of our > content management system. We have a table layout like so: > > Content > ------- > id - prim key, auto incr > title - text > > ContentNews > ----------- > content_id - prim key/foreign key to content(id) > next_article - number > > ContentEvent > ------------ > content_id - prim key/foreign key to content(id) > location - text > start_date - date > end_date - date > > ContentJob > ---------- > content_id - prim key/foreign key to content(id) > contact_info - text > expire_date - date > > In Hibernate, I could just have the news, events, and job classes all > subclass the content class. It managed prim/foreign key insertions > and everything else via my mapping file and acted just like regular > Java subclasses. However, reading about ActiveRecord, it''s obvious it > doesn''t (yet) handle class table inheritance. Unfortunately for me, I > cannot re-design these tables and have this relationship in a few > other places in my db. > > Does anyone have any suggestions on how to get past this? I noticed > in the Rails development site, there was a CTI issue in the > ''Research'' section, but no resolution yet. I don''t mind hacking some > stuff in to get it to work, but if something official is going to be > rolled into the next release, then maybe I can just use those patches. > > I''m kinda getting excited to see how much conversion I can get done > in the next month. However, CTI is critical for my app and if there''s > no way around it (besides re-doing existing tables) then I''m gonna > have to go back to Java and wait for this functionality to make it > into an official release. :( > > Suggestions, links, etc all helpful. Thanks, > > JasonI do something similar with Postgresql table inheritance: http://www.postgresql.org/docs/current/static/ddl-inherit.html John Wilger has an article on mimicking CTI with PostgreSQL also: http://johnwilger.com/articles/2005/09/29/class-table-inheritance-in-rails-with-postgresql. Frankly, that''s a lot of code, and my setup seems to be working fine. Just set_sequence_name on the tables to use the sequence of the base table and you''re fine. -- rick http://techno-weenie.net
On Wed, 2005-10-19 at 14:19 -0500, Rick Olson wrote:> On 10/19/05, Jason Lee <jasonlee9-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > In Hibernate, I could just have the news, events, and job classes all > > subclass the content class. It managed prim/foreign key insertions > > and everything else via my mapping file and acted just like regular > > Java subclasses. However, reading about ActiveRecord, it''s obvious it > > doesn''t (yet) handle class table inheritance. Unfortunately for me, I > > cannot re-design these tables and have this relationship in a few > > other places in my db. > > > > Does anyone have any suggestions on how to get past this? I noticed > > in the Rails development site, there was a CTI issue in the > > ''Research'' section, but no resolution yet. I don''t mind hacking some > > stuff in to get it to work, but if something official is going to be > > rolled into the next release, then maybe I can just use those patches.<snip>> I do something similar with Postgresql table inheritance: > http://www.postgresql.org/docs/current/static/ddl-inherit.html > > John Wilger has an article on mimicking CTI with PostgreSQL also: > http://johnwilger.com/articles/2005/09/29/class-table-inheritance-in-rails-with-postgresql. > Frankly, that''s a lot of code, and my setup seems to be working fine. > Just set_sequence_name on the tables to use the sequence of the base > table and you''re fine.I''ve looked at these methods using PostgreSQL, and they seem fine for most cases. However, what about polymorphism? If I request all objects of a parent type, is there a way to get all the objects of the subtypes as well WITHOUT issuing tons and tons of queries? Something to think about... Martin
On Oct 19, 2005, at 12:19 PM, Rick Olson wrote:> > I do something similar with Postgresql table inheritance: > http://www.postgresql.org/docs/current/static/ddl-inherit.html > > John Wilger has an article on mimicking CTI with PostgreSQL also: > http://johnwilger.com/articles/2005/09/29/class-table-inheritance- > in-rails-with-postgresql. > Frankly, that''s a lot of code, and my setup seems to be working fine. > Just set_sequence_name on the tables to use the sequence of the base > table and you''re fine. >Rick, The table inheritance would have been useful in the beginning, but at this stage, I probably won''t be able to use it. However, for future additions it might be useful. Read John''s article. I suppose if those are the changes I''ll need to make - and they work - then I might be able to do it. Thanks, -jason
On 10/19/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I do something similar with Postgresql table inheritance: > http://www.postgresql.org/docs/current/static/ddl-inherit.htmlRick''s method is certainly preferable to what I wrote up as long as you are satisfied with maintaining constraints only at the model level and not in the DB. It still suffers from the problem of not giving you all the attributes of an object when you use the parent class''s #find method. For instance, if you have: class Foo < ActiveRecord::Base end class Bar < Foo self.table_name = ''bars'' self.sequence_name = ''foos_id_seq'' end and the following schema: create_table :foos do |t| t.column :in_foo, :string t.column :type, :string end create_table :bars, :id => false, :options => ''INHERIT (foos)'' do |t| t.column :in_bar, :string end and then you create a new Bar: b = Bar.new b.in_foo = ''I am'' b.in_bar = ''I am'' b.save f = Foo.find b.id f == b #=> true f.in_foo #=> ''I am'' f.class #=> Bar That works fine, but: f.in_bar Will raise a NoMethodError. This is because even though the object was instantiated as an instance of class Bar, on instantiation it was only provided with the _data_ from the ''foos'' table. Because of the way ActiveRecord initializes the object, not only does it not have the data for the in_bar property, it doesn''t even recognize the property on this object. In the method I described on my website [1], I changed some ActiveRecord internals in order to force the object to be instantiated with the correct table. Unfortunately, this results in a huge performance hit, since you now have to execute an additional query for _every_object_ returned by the find method (well, actually just objects that aren''t instances of the class from which #find was called). The other option is to lose the (nice) behavior you get with STI of having #find return objects of the leaf classes. Just remove the ''type'' column from your base table altogether. You could then define Foo as: class Foo < ActiveRecord::Base def to_bar Bar.find self.id end end This way, you could use the object as an instance of Foo (which is probably all you need in most cases when you would be iterating over a collection of all the ''Foo'' entities), but have an easy to remember way to convert it to an instance of Bar when you need to. If the Foo wasn''t also a Bar, you''d get an ActiveRecord::RecordNotFound exception when calling Foo#to_bar, which is probably less than ideal. Fixing that issue -- as well as possibly automatically adding the conversion methods when creating new classes that inherit from the base -- is left as an exercise to the reader. ;-) [1] http://johnwilger.com/articles/2005/09/29/class-table-inheritance-in-rails-with-postgresql -- Regards, John Wilger ----------- Alice came to a fork in the road. "Which road do I take?" she asked. "Where do you want to go?" responded the Cheshire cat. "I don''t know," Alice answered. "Then," said the cat, "it doesn''t matter." - Lewis Carrol, Alice in Wonderland
On Oct 19, 2005, at 2:05 PM, John Wilger wrote:> On 10/19/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > >> I do something similar with Postgresql table inheritance: >> http://www.postgresql.org/docs/current/static/ddl-inherit.html >> > > Rick''s method is certainly preferable to what I wrote up as long as > you are satisfied with maintaining constraints only at the model level > and not in the DB.<snip>> > > The other option is to lose the (nice) behavior you get with STI of > having #find return objects of the leaf classes. Just remove the > ''type'' column from your base table altogether. You could then define > Foo as: > > class Foo < ActiveRecord::Base > def to_bar > Bar.find self.id > end > end > > This way, you could use the object as an instance of Foo (which is > probably all you need in most cases when you would be iterating over a > collection of all the ''Foo'' entities), but have an easy to remember > way to convert it to an instance of Bar when you need to. If the Foo > wasn''t also a Bar, you''d get an ActiveRecord::RecordNotFound exception > when calling Foo#to_bar, which is probably less than ideal. Fixing > that issue -- as well as possibly automatically adding the conversion > methods when creating new classes that inherit from the base -- is > left as an exercise to the reader. ;-)Hmmm. So if I added new tables that inherit from the base table like: Content ------- id - prim key, auto incr title - text ContentNews - inherit from Content ----------- next_article - number class Content < ActiveRecord::Base self.table_name = ''content'' self.sequence_name = ''content_id_seq'' end Class ContentNews < Content self.table_name = ''content_news'' end then this would be preferable? Would Rails then deal with each object appropriately? (I don''t so much care about going from Content -> ContentNews as I do ContentNews -> Content). Or are there other details I''m missing? Thanks, - jason
> In Hibernate, I could just have the news, events, and job classes all > subclass the content class. It managed prim/foreign key insertions > and everything else via my mapping file and acted just like regular > Java subclasses. However, reading about ActiveRecord, it''s obvious it > doesn''t (yet) handle class table inheritance. Unfortunately for me, I > cannot re-design these tables and have this relationship in a few > other places in my db.If your table setup really isn''t more complicated than what you listed above, I''d recommend using single-table inheritance. If you can''t touch the schema, perhaps you can do a view that just exposes the following table: Content ------- id - prim key, auto incr title - text next_article - number (only used by ContentNews) location - text (only used by ContentEvent) start_date - date (only used by ContentEvent) end_date - date (only used by ContentEvent) contact_info - text (only used by ContentJob) expire_date - date (only used by ContentJob) type - text (contains "ContentNews", "ContentEvent", or "ContentJob") STI won''t solve your problems if you have very different classes and a lot of them. But if the domain truly is as simple as listed, then I think its a perfect case for STI. In short, it''s both easier and faster (no joins). Anyway, please don''t let that discourage you from pursuing the development of other inheritance schemes. I''d surely like to see them in Rails. But if you''re not in it for the fun, then this looks like a perfect opportunity to be pragmatic. -- David Heinemeier Hansson http://www.loudthinking.com -- Broadcasting Brain http://www.basecamphq.com -- Online project management http://www.backpackit.com -- Personal information manager http://www.rubyonrails.com -- Web-application framework
On Oct 19, 2005, at 3:04 PM, David Heinemeier Hansson wrote:>> In Hibernate, I could just have the news, events, and job classes all >> subclass the content class. It managed prim/foreign key insertions >> and everything else via my mapping file and acted just like regular >> Java subclasses. However, reading about ActiveRecord, it''s obvious it >> doesn''t (yet) handle class table inheritance. Unfortunately for me, I >> cannot re-design these tables and have this relationship in a few >> other places in my db. >> > > If your table setup really isn''t more complicated than what you listed > above, I''d recommend using single-table inheritance. If you can''t > touch the schema, perhaps you can do a view that just exposes the > following table: > > Content > ------- > id - prim key, auto incr > title - text > next_article - number (only used by ContentNews) > location - text (only used by ContentEvent) > start_date - date (only used by ContentEvent) > end_date - date (only used by ContentEvent) > contact_info - text (only used by ContentJob) > expire_date - date (only used by ContentJob) > type - text (contains "ContentNews", "ContentEvent", or "ContentJob") > > STI won''t solve your problems if you have very different classes and a > lot of them. But if the domain truly is as simple as listed, then I > think its a perfect case for STI. In short, it''s both easier and > faster (no joins). > > Anyway, please don''t let that discourage you from pursuing the > development of other inheritance schemes. I''d surely like to see them > in Rails. But if you''re not in it for the fun, then this looks like a > perfect opportunity to be pragmatic.Thanks for the response. My content examples were just a small piece; if I was to do STI, the table would be around 25+ columns wide. And that''s just for these three content types. In the future we''ll be adding more types and I''m not sure if it makes sense to keep growing columns out vs. new liked tables (taking the long view, I think STI probably won''t be a good solution for our content model). All input is good tho. I think I''ll have to delve into AR a little more to see if I want to take either the inherited Postgres tables, John''s approach, or the STI approach. After working on my project for so long, it didn''t take but 15 mins of a Rails presentation to see it''s power and usefulness. I have a lot of time invested in my Java app and the AR issue is just one part. I am, however, ready to have a fun programming project, so maybe this will be a good exercise. If I migrate everything over at some point, I''ll be sure to let everyone know. Thanks, - jason
Martin May wrote:> I''ve looked at these methods using PostgreSQL, and they seem fine for > most cases. However, what about polymorphism? If I request all objects > of a parent type, is there a way to get all the objects of the subtypes > as well WITHOUT issuing tons and tons of queries? > > Something to think about...An ORM that I''ve seen able to implement CTI and polymorphic object calls is SQLObject v7 by Ian Bicking. It''s written in Python. I really miss CTI in RoR. Expecially for the ''CMSish'' scenarios described in this thread, where STI doesn''t make sense at all. Is anybody developing CTI for Rails?!? Edoardo "Dado" Marcora