Struggling a little with getting the syntax right for a STI model. Prob just being a bit dense. Couple of questions I''m hoping you guys can answer: Assume here I''ve got: class Person class Manager < Person class Slave < Person 1) How does person[:type] differ from person.type when type is the column used to specify the subclass. They seem to output the same ("Manager") but the first works with an if statement (if person[:type] = "Manager"), the second doesn''t. 2) How do I force the creation method that follows a form submission to put something into a particular subclass. At the moment I have one form that can handle all the subtypes and there''s a hidden field <%= hidden_field(''person'', ''type'', "value" => @person[:type]) %> that varies depending on how it''s called, e.g. @person = Manager.new or @person = Slave.new. However, although that seems to pass the correct variables along, the type is left as null. There''s not much on the wiki (or anywhere else) on STI, so any help would be greatly appreciated, and I''ll update the wiki. Thanks Chris T
1) you definitely want to use person[:type] instead of person.type as ''type'' is a built-in ruby method (although deprecated) and you could have some unexpected behavior if you try to use person.type. 2) to make sure I understand correctly you have something like: # simplified def new case @params[:person_type] when "Manager" @person = Manager.new when "Slave" @person = Slave.new end end in your view, do: <%= hidden_field_tag "person_type", @person[:type] %> then in your create method: #again, simplified def create case @params[:person_type] when "Manager" @person = Manager.new(@params[:person]) when "Slave" @person = Slave.new(@params[:person]) end if @person.save redirect_to :action => :list else render_action :new end end you could even go so far as to create a factory class method in your Person class class Person < ActiveRecord::Base def self.factory(type, params = nil) case type when "Manager" return Manager.new(params) when "Slave" return Slave.new(params) else return nil end end end then in your new and create methods, you can do def new @person = Person.factory(@params[:person_type]) end def create @person = Person.factory(@params[:person_type], @params[:person]) if @person.save ... end end On 3/16/06, ChrisT <chrismtaggart@gmail.com> wrote:> > Struggling a little with getting the syntax right for a STI model. Prob > just being a bit dense. > > Couple of questions I''m hoping you guys can answer: > > Assume here I''ve got: > class Person > class Manager < Person > class Slave < Person > > 1) How does person[:type] differ from person.type when type is the > column used to specify the subclass. They seem to output the same > ("Manager") but the first works with an if statement (if person[:type] > "Manager"), the second doesn''t. > > 2) How do I force the creation method that follows a form submission to > put something into a particular subclass. At the moment I have one form > that can handle all the subtypes and there''s a hidden field <%> hidden_field(''person'', ''type'', "value" => @person[:type]) %> that varies > depending on how it''s called, e.g. @person = Manager.new or @person > Slave.new. However, although that seems to pass the correct variables > along, the type is left as null. > > There''s not much on the wiki (or anywhere else) on STI, so any help > would be greatly appreciated, and I''ll update the wiki. > > Thanks > Chris T > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060316/aa0efacf/attachment.html
> 1) How does person[:type] differ from person.type when type is the > column used to specify the subclass. They seem to output the same > ("Manager") but the first works with an if statement (if person[:type] > "Manager"), the second doesn''t.>From my understandingperson.type returns the string object with the property name ''type'' person[:type] points to the string value of the property with the key ''type'' similar to if it were a hash table So comparing an object to a string value returns false. Ruby casts the string object to a string when you use it in the context of <%= person.type %> Tony -- Posted via http://www.ruby-forum.com/.
If you want to create a ''manager'' or ''slave'' but don''t know which, you can do something like this.. def create @person = Person.new @person[:type] = "Manager" # or get it from a param[:person][:type] .... In other words, if you manually set the ''type'' column to the name of the class you want it to have, when you pull that record from the database, AR will re-create it as a ''Manager'' instead of a ''Person''. _Kevin On Thursday, March 16, 2006, at 8:38 AM, Chris Hall wrote:>1) you definitely want to use person[:type] instead of person.type >as ''type'' >is a built-in ruby method (although deprecated) and you could have some >unexpected behavior if you try to use person.type. > >2) to make sure I understand correctly you have something like: > ># simplified >def new > case @params[:person_type] > when "Manager" > @person = Manager.new > when "Slave" > @person = Slave.new > end >end > >in your view, do: > ><%= hidden_field_tag "person_type", @person[:type] %> > >then in your create method: > >#again, simplified >def create > case @params[:person_type] > when "Manager" > @person = Manager.new(@params[:person]) > when "Slave" > @person = Slave.new(@params[:person]) > end > if @person.save > redirect_to :action => :list > else > render_action :new > end >end > > >you could even go so far as to create a factory class method in your Person >class > >class Person < ActiveRecord::Base > def self.factory(type, params = nil) > case type > when "Manager" > return Manager.new(params) > when "Slave" > return Slave.new(params) > else > return nil > end > end >end > >then in your new and create methods, you can do > >def new > @person = Person.factory(@params[:person_type]) >end > >def create > @person = Person.factory(@params[:person_type], @params[:person]) > if @person.save > ... > end >end > >On 3/16/06, ChrisT <chrismtaggart@gmail.com> wrote: >> >> Struggling a little with getting the syntax right for a STI model. Prob >> just being a bit dense. >> >> Couple of questions I''m hoping you guys can answer: >> >> Assume here I''ve got: >> class Person >> class Manager < Person >> class Slave < Person >> >> 1) How does person[:type] differ from person.type when type is the >> column used to specify the subclass. They seem to output the same >> ("Manager") but the first works with an if statement (if person[:type] >> "Manager"), the second doesn''t. >> >> 2) How do I force the creation method that follows a form submission to >> put something into a particular subclass. At the moment I have one form >> that can handle all the subtypes and there''s a hidden field <%>> hidden_field(''person'', ''type'', "value" => @person[:type]) %> that varies >> depending on how it''s called, e.g. @person = Manager.new or @person >> Slave.new. However, although that seems to pass the correct variables >> along, the type is left as null. >> >> There''s not much on the wiki (or anywhere else) on STI, so any help >> would be greatly appreciated, and I''ll update the wiki. >> >> Thanks >> Chris T >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> > > >_______________________________________________ >Rails mailing list >Rails@lists.rubyonrails.org >http://lists.rubyonrails.org/mailman/listinfo/rails >-- Posted with http://DevLists.com. Sign up and save your time!
Chris That (or something very similar) sorted it. Thanks. Still not 100% understanding why type can''t be passed as a parameter with the rest of the :person ones, but at least it''s working now. Cheers Chris T Chris Hall wrote:> 1) you definitely want to use person[:type] instead of person.type as > ''type'' is a built-in ruby method (although deprecated) and you could > have some unexpected behavior if you try to use person.type. > > 2) to make sure I understand correctly you have something like: > > # simplified > def new > case @params[:person_type] > when "Manager" > @person = Manager.new > when "Slave" > @person = Slave.new > end > end > > in your view, do: > > <%= hidden_field_tag "person_type", @person[:type] %> > > then in your create method: > > #again, simplified > def create > case @params[:person_type] > when "Manager" > @person = Manager.new(@params[:person]) > when "Slave" > @person = Slave.new(@params[:person]) > end > if @person.save > redirect_to :action => :list > else > render_action :new > end > end > > > you could even go so far as to create a factory class method in your > Person class > > class Person < ActiveRecord::Base > def self.factory(type, params = nil) > case type > when "Manager" > return Manager.new(params) > when "Slave" > return Slave.new(params) > else > return nil > end > end > end > > then in your new and create methods, you can do > > def new > @person = Person.factory(@params[:person_type]) > end > > def create > @person = Person.factory(@params[:person_type], @params[:person]) > if @person.save > ... > end > end > > On 3/16/06, *ChrisT* <chrismtaggart@gmail.com > <mailto:chrismtaggart@gmail.com>> wrote: > > Struggling a little with getting the syntax right for a STI model. > Prob > just being a bit dense. > > Couple of questions I''m hoping you guys can answer: > > Assume here I''ve got: > class Person > class Manager < Person > class Slave < Person > > 1) How does person[:type] differ from person.type when type is the > column used to specify the subclass. They seem to output the same > ("Manager") but the first works with an if statement (if > person[:type] > "Manager"), the second doesn''t. > > 2) How do I force the creation method that follows a form > submission to > put something into a particular subclass. At the moment I have one > form > that can handle all the subtypes and there''s a hidden field <%> hidden_field(''person'', ''type'', "value" => @person[:type]) %> that > varies > depending on how it''s called, e.g. @person = Manager.new or @person > Slave.new. However, although that seems to pass the correct variables > along, the type is left as null. > > There''s not much on the wiki (or anywhere else) on STI, so any help > would be greatly appreciated, and I''ll update the wiki. > > Thanks > Chris T > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org <mailto:Rails@lists.rubyonrails.org> > http://lists.rubyonrails.org/mailman/listinfo/rails > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Kevin Thanks for this. I ended up doing something very similar. Why does it need to be set explicitly, though, i.e. separate from the other parameters for person? [If you have the form return a hash something like "person"=>{"name"=>"Fred", "type"=>"Manager", "age"=>"28"} I''m missing something here, as it doesn''t seem to work.] Cheers Chris Kevin Olbrich wrote:> If you want to create a ''manager'' or ''slave'' but don''t know which, you > can do something like this.. > > def create > @person = Person.new > @person[:type] = "Manager" # or get it from a param[:person][:type] > .... > > In other words, if you manually set the ''type'' column to the name of the > class you want it to have, when you pull that record from the database, > AR will re-create it as a ''Manager'' instead of a ''Person''. > > _Kevin > > On Thursday, March 16, 2006, at 8:38 AM, Chris Hall wrote: > >> 1) you definitely want to use person[:type] instead of person.type >> as ''type'' >> is a built-in ruby method (although deprecated) and you could have some >> unexpected behavior if you try to use person.type. >> >> 2) to make sure I understand correctly you have something like: >> >> # simplified >> def new >> case @params[:person_type] >> when "Manager" >> @person = Manager.new >> when "Slave" >> @person = Slave.new >> end >> end >> >> in your view, do: >> >> <%= hidden_field_tag "person_type", @person[:type] %> >> >> then in your create method: >> >> #again, simplified >> def create >> case @params[:person_type] >> when "Manager" >> @person = Manager.new(@params[:person]) >> when "Slave" >> @person = Slave.new(@params[:person]) >> end >> if @person.save >> redirect_to :action => :list >> else >> render_action :new >> end >> end >> >> >> you could even go so far as to create a factory class method in your Person >> class >> >> class Person < ActiveRecord::Base >> def self.factory(type, params = nil) >> case type >> when "Manager" >> return Manager.new(params) >> when "Slave" >> return Slave.new(params) >> else >> return nil >> end >> end >> end >> >> then in your new and create methods, you can do >> >> def new >> @person = Person.factory(@params[:person_type]) >> end >> >> def create >> @person = Person.factory(@params[:person_type], @params[:person]) >> if @person.save >> ... >> end >> end >> >> On 3/16/06, ChrisT <chrismtaggart@gmail.com> wrote: >> >>> Struggling a little with getting the syntax right for a STI model. Prob >>> just being a bit dense. >>> >>> Couple of questions I''m hoping you guys can answer: >>> >>> Assume here I''ve got: >>> class Person >>> class Manager < Person >>> class Slave < Person >>> >>> 1) How does person[:type] differ from person.type when type is the >>> column used to specify the subclass. They seem to output the same >>> ("Manager") but the first works with an if statement (if person[:type] >>> "Manager"), the second doesn''t. >>> >>> 2) How do I force the creation method that follows a form submission to >>> put something into a particular subclass. At the moment I have one form >>> that can handle all the subtypes and there''s a hidden field <%>>> hidden_field(''person'', ''type'', "value" => @person[:type]) %> that varies >>> depending on how it''s called, e.g. @person = Manager.new or @person >>> Slave.new. However, although that seems to pass the correct variables >>> along, the type is left as null. >>> >>> There''s not much on the wiki (or anywhere else) on STI, so any help >>> would be greatly appreciated, and I''ll update the wiki. >>> >>> Thanks >>> Chris T >>> _______________________________________________ >>> Rails mailing list >>> Rails@lists.rubyonrails.org >>> http://lists.rubyonrails.org/mailman/listinfo/rails >>> >>> >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> >> > > > > > >
Anthony OK. That sort of makes sense :-) Cheers Chris T. Anthony Green wrote:>> 1) How does person[:type] differ from person.type when type is the >> column used to specify the subclass. They seem to output the same >> ("Manager") but the first works with an if statement (if person[:type] >> "Manager"), the second doesn''t. >> > > >From my understanding > > person.type returns the string object with the property name ''type'' > > person[:type] points to the string value of the property with the key > ''type'' similar to if it were a hash table > > So comparing an object to a string value returns false. > > Ruby casts the string object to a string when you use it in the context > of > > <%= person.type %> > > Tony > > > > >
If you know the type, you can also do something like this: person_type = "Manager" @person = eval(person_type + ".new") Or use constantize: person_type = "Manager" @person = person_type.constantize.new (Thanks again to Ezra for that last bit.) Sean On 16 Mar 2006 15:13:07 -0000, Kevin Olbrich <devlists-rubyonrails@devlists.com> wrote:> If you want to create a ''manager'' or ''slave'' but don''t know which, you > can do something like this.. > > def create > @person = Person.new > @person[:type] = "Manager" # or get it from a param[:person][:type] > .... > > In other words, if you manually set the ''type'' column to the name of the > class you want it to have, when you pull that record from the database, > AR will re-create it as a ''Manager'' instead of a ''Person''. > > _Kevin > > On Thursday, March 16, 2006, at 8:38 AM, Chris Hall wrote: > >1) you definitely want to use person[:type] instead of person.type > >as ''type'' > >is a built-in ruby method (although deprecated) and you could have some > >unexpected behavior if you try to use person.type. > > > >2) to make sure I understand correctly you have something like: > > > ># simplified > >def new > > case @params[:person_type] > > when "Manager" > > @person = Manager.new > > when "Slave" > > @person = Slave.new > > end > >end > > > >in your view, do: > > > ><%= hidden_field_tag "person_type", @person[:type] %> > > > >then in your create method: > > > >#again, simplified > >def create > > case @params[:person_type] > > when "Manager" > > @person = Manager.new(@params[:person]) > > when "Slave" > > @person = Slave.new(@params[:person]) > > end > > if @person.save > > redirect_to :action => :list > > else > > render_action :new > > end > >end > > > > > >you could even go so far as to create a factory class method in your Person > >class > > > >class Person < ActiveRecord::Base > > def self.factory(type, params = nil) > > case type > > when "Manager" > > return Manager.new(params) > > when "Slave" > > return Slave.new(params) > > else > > return nil > > end > > end > >end > > > >then in your new and create methods, you can do > > > >def new > > @person = Person.factory(@params[:person_type]) > >end > > > >def create > > @person = Person.factory(@params[:person_type], @params[:person]) > > if @person.save > > ... > > end > >end > > > >On 3/16/06, ChrisT <chrismtaggart@gmail.com> wrote: > >> > >> Struggling a little with getting the syntax right for a STI model. Prob > >> just being a bit dense. > >> > >> Couple of questions I''m hoping you guys can answer: > >> > >> Assume here I''ve got: > >> class Person > >> class Manager < Person > >> class Slave < Person > >> > >> 1) How does person[:type] differ from person.type when type is the > >> column used to specify the subclass. They seem to output the same > >> ("Manager") but the first works with an if statement (if person[:type] > >> "Manager"), the second doesn''t. > >> > >> 2) How do I force the creation method that follows a form submission to > >> put something into a particular subclass. At the moment I have one form > >> that can handle all the subtypes and there''s a hidden field <%> >> hidden_field(''person'', ''type'', "value" => @person[:type]) %> that varies > >> depending on how it''s called, e.g. @person = Manager.new or @person > >> Slave.new. However, although that seems to pass the correct variables > >> along, the type is left as null. > >> > >> There''s not much on the wiki (or anywhere else) on STI, so any help > >> would be greatly appreciated, and I''ll update the wiki. > >> > >> Thanks > >> Chris T > >> _______________________________________________ > >> Rails mailing list > >> Rails@lists.rubyonrails.org > >> http://lists.rubyonrails.org/mailman/listinfo/rails > >> > > > > > >_______________________________________________ > >Rails mailing list > >Rails@lists.rubyonrails.org > >http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > > > -- > Posted with http://DevLists.com. Sign up and save your time! > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
And for anyone who cares, if you want different validation rules in the parent model use: if (type.to_s == "Member") It took me a good couple of hours to figure that one out. Dan> person.type returns the string object with the property name ''type'' > > person[:type] points to the string value of the property with the key > ''type'' similar to if it were a hash table > > So comparing an object to a string value returns false. > > Ruby casts the string object to a string when you use it in the context > of > > <%= person.type %> >
Dan, Anthony, etc Thanks for this. I''ll try to add a couple of notes to the wiki entry tomorrow. CHris T Dan Harper wrote:> And for anyone who cares, if you want different validation rules in > the parent model use: > if (type.to_s == "Member") > > It took me a good couple of hours to figure that one out. > > Dan > >> person.type returns the string object with the property name ''type'' >> >> person[:type] points to the string value of the property with the key >> ''type'' similar to if it were a hash table >> >> So comparing an object to a string value returns false. >> >> Ruby casts the string object to a string when you use it in the >> context of >> >> <%= person.type %> >> > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >