Hi, Reading through past posts, I think, scratch that, I *thought* I understood how single table inheritance works. At first I thought that I''d create two tables in my database, and one inherits from the second (having a "type" column). So I think... Child table doesn''t have to define columns from parent table since that''s what inheritance is all about, isn''t it? Well, then I read you just define a single table, which holds parent *and* child records. If so, then how do you add/remove columns from a child? What I''m trying to accomplish is pretty simple. Picture a forum engine. 2 tables. One for messages another for replies (because replies don''t need some of the fields from a message). Take a look at this (simplified): Table messages: id INT(10) subject CHAR(50) body CHAR(255) author CHAR(40) email CHAR(128) created_on DATETIME Table replies: id INT(10) message_id INT(10) type CHAR(10) DEFAULT ''message'' Would that be the right way? If so, how do I make it so the reply model doesn''t include the ''subject'' column (from the message model)? If not, what''s the correct way? I could also use just one table with a FK relationship to itself, but I''m trying to practice this "inheritance" feature. Any help is appreciated! - Ivan V.
On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> wrote:> Well, then I read you just define a single table, which holds parent > *and* child records. If so, then how do you add/remove columns from a child?The actual database row will have all of the columns, however you can limit access to those columns in your model class code.> What I''m trying to accomplish is pretty simple. Picture a forum engine. > 2 tables. One for messages another for replies (because replies don''t > need some of the fields from a message). Take a look at this (simplified): > > Table messages: > id INT(10) > subject CHAR(50) > body CHAR(255) > author CHAR(40) > email CHAR(128) > created_on DATETIME > > Table replies: > id INT(10) > message_id INT(10) > type CHAR(10) DEFAULT ''message''You want: Table messages: id int(10) parent_id int(10) type char(10) body char(255) subject char(50) author char(40) email char(128) created_on datetime and: class Message < ActiveRecord::Base acts_as_tree end class Reply < Message before_save :set_subject def subject=( subject ) raise "Silly rabit, replies can''t be assigned a different subject from their parent!" end protected def set_subject write_attribute( ''subject'', parent.subject ) end end (or something along those lines) -- 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
Also, your inheritance is a little twisted, as you want to have your most generic class first (since you can''t ever "remove" an attribute from a derived class, at least not in any language that I''ve seen) - so, first Message would have author, body, email, created_on; then you could say that a Thread has a subject and a forum_id, perhaps, and a Reply has a thread_id. STI in Rails doesn''t allow you to actually REMOVE those columns, though. Your Reply model will still technically have a "subject" in it and a "forum_id", and your Threads will have "thread_id", but these fields will be NULL. If this somehow bothers you then you need separate tables for each model, with no type column. However, in practice it''s not usually a big problem - if you find yourself assigning Reply.subject then you only have yourself to blame, really :) On 10/15/05, John Wilger <johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> wrote: > > Well, then I read you just define a single table, which holds parent > > *and* child records. If so, then how do you add/remove columns from a > child? > > The actual database row will have all of the columns, however you can > limit access to those columns in your model class code. > > > What I''m trying to accomplish is pretty simple. Picture a forum engine. > > 2 tables. One for messages another for replies (because replies don''t > > need some of the fields from a message). Take a look at this > (simplified): > > > > Table messages: > > id INT(10) > > subject CHAR(50) > > body CHAR(255) > > author CHAR(40) > > email CHAR(128) > > created_on DATETIME > > > > Table replies: > > id INT(10) > > message_id INT(10) > > type CHAR(10) DEFAULT ''message'' > > You want: > > Table messages: > id int(10) > parent_id int(10) > type char(10) > body char(255) > subject char(50) > author char(40) > email char(128) > created_on datetime > > and: > > class Message < ActiveRecord::Base > acts_as_tree > end > > class Reply < Message > before_save :set_subject > > def subject=( subject ) > raise "Silly rabit, replies can''t be assigned a different subject > from their parent!" > end > > protected > def set_subject > write_attribute( ''subject'', parent.subject ) > end > end > > (or something along those lines) > > -- > 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 > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
I see your point. So what I''m now thinking is this: Table messages (Thanks for the input John!): id int(10) PK parent_id int(10) type char(10) body char(255) subject char(50) author char(40) email char(128) created_on datetime And then, on the message model: class Message < ActiveRecord::Base acts_as_tree end class Thread < Message end class Reply < Thread before_save :set_subject def subject=( subject ) raise "Silly rabit, replies can''t be assigned a different subject from their parent!" end protected def set_subject write_attribute( ''subject'', parent.subject ) end end Is that correct? If so, I''d just like some help understanding the last class. How does "def subject=(subject)" work? What does it mean? I''m sorry if this seems stupid, but I''m just learning both Ruby and Rails. Also, afterwards, to query the replies for a message, would this suffice: class MessagesController < ApplicationController def list Reply.find(:all, :conditions => ["parent_id = ?", params[:id]]) end end ? Thanks a lot! Ivan V. Patrick McCafferty wrote:> Also, your inheritance is a little twisted, as you want to have your > most generic class first (since you can''t ever "remove" an attribute > from a derived class, at least not in any language that I''ve seen) - > so, first Message would have author, body, email, created_on; then you > could say that a Thread has a subject and a forum_id, perhaps, and a > Reply has a thread_id. > > STI in Rails doesn''t allow you to actually REMOVE those columns, > though. Your Reply model will still technically have a "subject" in it > and a "forum_id", and your Threads will have "thread_id", but these > fields will be NULL. If this somehow bothers you then you need > separate tables for each model, with no type column. However, in > practice it''s not usually a big problem - if you find yourself > assigning Reply.subject then you only have yourself to blame, really :) > > On 10/15/05, *John Wilger* <johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > <mailto:johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > wrote: > > On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org > <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org>> wrote: > > Well, then I read you just define a single table, which holds parent > > *and* child records. If so, then how do you add/remove columns > from a child? > > The actual database row will have all of the columns, however you can > limit access to those columns in your model class code. > > > What I''m trying to accomplish is pretty simple. Picture a forum > engine. > > 2 tables. One for messages another for replies (because replies > don''t > > need some of the fields from a message). Take a look at this > (simplified): > > > > Table messages: > > id INT(10) > > subject CHAR(50) > > body CHAR(255) > > author CHAR(40) > > email CHAR(128) > > created_on DATETIME > > > > Table replies: > > id INT(10) > > message_id INT(10) > > type CHAR(10) DEFAULT ''message'' > > You want: > > Table messages: > id int(10) > parent_id int(10) > type char(10) > body char(255) > subject char(50) > author char(40) > email char(128) > created_on datetime > > and: > > class Message < ActiveRecord::Base > acts_as_tree > end > > class Reply < Message > before_save :set_subject > > def subject=( subject ) > raise "Silly rabit, replies can''t be assigned a different subject > from their parent!" > end > > protected > def set_subject > write_attribute( ''subject'', parent.subject ) > end > end > > (or something along those lines) > > -- > 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 > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> > http://lists.rubyonrails.org/mailman/listinfo/rails > <http://lists.rubyonrails.org/mailman/listinfo/rails> > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
"def subject=(subject)" (re)defines the assignment operator for that attribute; so Reply.subject = ... would call that method (and raise an exception) In my opinion you don''t need it; it doesn''t matter whether Reply.subject is assigned or not because you should never be using it in any method that uses a Reply. But it''s a matter of style, really. Yes, your find statement will work fine ... but make sure that you''re not actually chaining the messages together (so a reply to a reply has a parent_id of the reply instead of the original message) - if you''re doing that you''ll need some other method of building the chain. On 10/15/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> wrote:> > I see your point. So what I''m now thinking is this: > > Table messages (Thanks for the input John!): > id int(10) PK > parent_id int(10) > type char(10) > body char(255) > subject char(50) > author char(40) > email char(128) > created_on datetime > > And then, on the message model: > > class Message < ActiveRecord::Base > acts_as_tree > end > > class Thread < Message > end > > class Reply < Thread > before_save :set_subject > > def subject=( subject ) > raise "Silly rabit, replies can''t be assigned a different subject > from their parent!" > end > > protected > def set_subject > write_attribute( ''subject'', parent.subject ) > end > end > > Is that correct? If so, I''d just like some help understanding the last > class. How does "def subject=(subject)" work? What does it mean? I''m > sorry if this seems stupid, but I''m just learning both Ruby and Rails. > > Also, afterwards, to query the replies for a message, would this suffice: > > class MessagesController < ApplicationController > def list > Reply.find(:all, :conditions => ["parent_id = ?", params[:id]]) > end > end > > ? > > Thanks a lot! > > Ivan V. > > Patrick McCafferty wrote: > > Also, your inheritance is a little twisted, as you want to have your > > most generic class first (since you can''t ever "remove" an attribute > > from a derived class, at least not in any language that I''ve seen) - > > so, first Message would have author, body, email, created_on; then you > > could say that a Thread has a subject and a forum_id, perhaps, and a > > Reply has a thread_id. > > > > STI in Rails doesn''t allow you to actually REMOVE those columns, > > though. Your Reply model will still technically have a "subject" in it > > and a "forum_id", and your Threads will have "thread_id", but these > > fields will be NULL. If this somehow bothers you then you need > > separate tables for each model, with no type column. However, in > > practice it''s not usually a big problem - if you find yourself > > assigning Reply.subject then you only have yourself to blame, really :) > > > > On 10/15/05, *John Wilger* <johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > > <mailto:johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > wrote: > > > > On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org > > <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org>> wrote: > > > Well, then I read you just define a single table, which holds parent > > > *and* child records. If so, then how do you add/remove columns > > from a child? > > > > The actual database row will have all of the columns, however you can > > limit access to those columns in your model class code. > > > > > What I''m trying to accomplish is pretty simple. Picture a forum > > engine. > > > 2 tables. One for messages another for replies (because replies > > don''t > > > need some of the fields from a message). Take a look at this > > (simplified): > > > > > > Table messages: > > > id INT(10) > > > subject CHAR(50) > > > body CHAR(255) > > > author CHAR(40) > > > email CHAR(128) > > > created_on DATETIME > > > > > > Table replies: > > > id INT(10) > > > message_id INT(10) > > > type CHAR(10) DEFAULT ''message'' > > > > You want: > > > > Table messages: > > id int(10) > > parent_id int(10) > > type char(10) > > body char(255) > > subject char(50) > > author char(40) > > email char(128) > > created_on datetime > > > > and: > > > > class Message < ActiveRecord::Base > > acts_as_tree > > end > > > > class Reply < Message > > before_save :set_subject > > > > def subject=( subject ) > > raise "Silly rabit, replies can''t be assigned a different subject > > from their parent!" > > end > > > > protected > > def set_subject > > write_attribute( ''subject'', parent.subject ) > > end > > end > > > > (or something along those lines) > > > > -- > > 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 > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> > > http://lists.rubyonrails.org/mailman/listinfo/rails > > <http://lists.rubyonrails.org/mailman/listinfo/rails> > > > > > > ------------------------------------------------------------------------ > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >_______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> wrote:> Also, afterwards, to query the replies for a message, would this suffice: > > class MessagesController < ApplicationController > def list > Reply.find(:all, :conditions => ["parent_id = ?", params[:id]]) > end > endActually, including the "acts_as_tree" statement in your model definition means you can do: @message = Message.find params[ :id ] and then access the replies via the #children property: @replies = @message.children Take a look at the docs for "acts_as_tree". http://api.rubyonrails.com/classes/ActiveRecord/Acts/Tree/ClassMethods.html -- 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
Oh my, everyday I discover something amazing about ruby/rails... Redefining the assignment operator? What a clever idea! Thanks a lot for helping me learn more about ruby and rails. Ivan V. Patrick McCafferty wrote:> "def subject=(subject)" (re)defines the assignment operator for that > attribute; so Reply.subject = ... would call that method (and raise an > exception) > > In my opinion you don''t need it; it doesn''t matter whether > Reply.subject is assigned or not because you should never be using it > in any method that uses a Reply. But it''s a matter of style, really. > > Yes, your find statement will work fine ... but make sure that you''re > not actually chaining the messages together (so a reply to a reply has > a parent_id of the reply instead of the original message) - if you''re > doing that you''ll need some other method of building the chain. > > On 10/15/05, *Iván Vega Rivera* <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org > <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org>> wrote: > > I see your point. So what I''m now thinking is this: > > Table messages (Thanks for the input John!): > id int(10) PK > parent_id int(10) > type char(10) > body char(255) > subject char(50) > author char(40) > email char(128) > created_on datetime > > And then, on the message model: > > class Message < ActiveRecord::Base > acts_as_tree > end > > class Thread < Message > end > > class Reply < Thread > before_save :set_subject > > def subject=( subject ) > raise "Silly rabit, replies can''t be assigned a different subject > from their parent!" > end > > protected > def set_subject > write_attribute( ''subject'', parent.subject ) > end > end > > Is that correct? If so, I''d just like some help understanding the > last > class. How does "def subject=(subject)" work? What does it mean? I''m > sorry if this seems stupid, but I''m just learning both Ruby and Rails. > > Also, afterwards, to query the replies for a message, would this > suffice: > > class MessagesController < ApplicationController > def list > Reply.find(:all, :conditions => ["parent_id = ?", params[:id]]) > end > end > > ? > > Thanks a lot! > > Ivan V. > > Patrick McCafferty wrote: > > Also, your inheritance is a little twisted, as you want to have your > > most generic class first (since you can''t ever "remove" an attribute > > from a derived class, at least not in any language that I''ve > seen) - > > so, first Message would have author, body, email, created_on; > then you > > could say that a Thread has a subject and a forum_id, perhaps, and a > > Reply has a thread_id. > > > > STI in Rails doesn''t allow you to actually REMOVE those columns, > > though. Your Reply model will still technically have a "subject" > in it > > and a "forum_id", and your Threads will have "thread_id", but these > > fields will be NULL. If this somehow bothers you then you need > > separate tables for each model, with no type column. However, in > > practice it''s not usually a big problem - if you find yourself > > assigning Reply.subject then you only have yourself to blame, > really :) > > > > On 10/15/05, *John Wilger* <johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > <mailto:johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > <mailto:johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org <mailto:johnwilger-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > wrote: > > > > On 10/14/05, Iván Vega Rivera < ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org > <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> > > <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org <mailto:ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org>>> wrote: > > > Well, then I read you just define a single table, which > holds parent > > > *and* child records. If so, then how do you add/remove columns > > from a child? > > > > The actual database row will have all of the columns, > however you can > > limit access to those columns in your model class code. > > > > > What I''m trying to accomplish is pretty simple. Picture a > forum > > engine. > > > 2 tables. One for messages another for replies (because > replies > > don''t > > > need some of the fields from a message). Take a look at this > > (simplified): > > > > > > Table messages: > > > id INT(10) > > > subject CHAR(50) > > > body CHAR(255) > > > author CHAR(40) > > > email CHAR(128) > > > created_on DATETIME > > > > > > Table replies: > > > id INT(10) > > > message_id INT(10) > > > type CHAR(10) DEFAULT ''message'' > > > > You want: > > > > Table messages: > > id int(10) > > parent_id int(10) > > type char(10) > > body char(255) > > subject char(50) > > author char(40) > > email char(128) > > created_on datetime > > > > and: > > > > class Message < ActiveRecord::Base > > acts_as_tree > > end > > > > class Reply < Message > > before_save :set_subject > > > > def subject=( subject ) > > raise "Silly rabit, replies can''t be assigned a > different subject > > from their parent!" > > end > > > > protected > > def set_subject > > write_attribute( ''subject'', parent.subject ) > > end > > end > > > > (or something along those lines) > > > > -- > > 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 > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> > <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org>> > > http://lists.rubyonrails.org/mailman/listinfo/rails > > <http://lists.rubyonrails.org/mailman/listinfo/rails > <http://lists.rubyonrails.org/mailman/listinfo/rails>> > > > > > > > ------------------------------------------------------------------------ > > > > _______________________________________________ > > Rails mailing list > > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org <mailto:Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org> > http://lists.rubyonrails.org/mailman/listinfo/rails > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Ah, that''s very, very nice. Thanks a lot! - Ivan V. John Wilger wrote:> On 10/14/05, Iván Vega Rivera <ivanvr-Xl95p0XkWPRBDgjK7y7TUQ@public.gmane.org> wrote: > >> Also, afterwards, to query the replies for a message, would this suffice: >> >> class MessagesController < ApplicationController >> def list >> Reply.find(:all, :conditions => ["parent_id = ?", params[:id]]) >> end >> end >> > > Actually, including the "acts_as_tree" statement in your model > definition means you can do: > > @message = Message.find params[ :id ] > > and then access the replies via the #children property: > > @replies = @message.children > > Take a look at the docs for "acts_as_tree". > http://api.rubyonrails.com/classes/ActiveRecord/Acts/Tree/ClassMethods.html > > -- > 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 > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails > >