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 >