I am running into a very odd problem. I have an ActiveRecord called Objective with a public create method. When this method is called in a controller the return value is a Hash instead of Objective. When I test the method in Rspec for the model it returns as Objective. Does anyone have an idea about why the return type would be different and if so how to fix it so it always returns Objective? Code: class Objective < ActiveRecord::Base belongs_to :user has_many :next_actions, :order => ''id DESC'', :conditions => {:completed => false} has_many :action_items, :order => ''position'' has_many :progress_updates serialize :freq_value validates_presence_of :name, :due_date, :completion, :pr_u_frequency_id validates_numericality_of :completion, :only_integer => true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 def self.create(attributes, user_id) #create new record with user_id correctly set attributes.delete :freq_options #deletes this unused key obj = self.new(attributes) obj.user_id = user_id obj.save ? obj : nil end end class ObjectivesController < ApplicationController before_filter :require_user layout false def create objective = Objective.create(params[:objective], current_user.id) Rails.logger.info("****objective.class = #{objective.class}****") end end
I should mention that the Hash does contain the Objective''s data. the reason it is important that Objective is returned instead of Hash is because I want to be able to call methods on it. On Oct 24, 8:31 am, drewB <dbats...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I am running into a very odd problem. I have an ActiveRecord called > Objective with a public create method. When this method is called in > a controller the return value is a Hash instead of Objective. When I > test the method in Rspec for the model it returns as Objective. > > Does anyone have an idea about why the return type would be different > and if so how to fix it so it always returns Objective? > > Code: > > class Objective < ActiveRecord::Base > belongs_to :user > has_many :next_actions, :order => ''id DESC'', :conditions => > {:completed => false} > has_many :action_items, :order => ''position'' > has_many :progress_updates > > serialize :freq_value > > validates_presence_of :name, :due_date, :completion, :pr_u_frequency_id > validates_numericality_of :completion, :only_integer => > true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 > > def self.create(attributes, user_id) > #create new record with user_id correctly set > attributes.delete :freq_options #deletes this unused key > obj = self.new(attributes) > obj.user_id = user_id > obj.save ? obj : nil > > end > > end > > class ObjectivesController < ApplicationController > before_filter :require_user > > layout false > > def create > objective = Objective.create(params[:objective], current_user.id) > Rails.logger.info("****objective.class = #{objective.class}****") > end > end
bonyfish choi
2009-Oct-25 13:07 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
hi,drewB first,I don''t agree about the code of create method,use another method name seems better. second,you mentioned that "objective.class" will return Hash? It''s impossible,Objective#create return a instance of Objective or nil~~ finally,show out your code about Rspec,please~
Thanks for your reply. On Oct 25, 6:07 am, bonyfish choi <mc02...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> hi,drewB > first,I don''t agree about the code of create method,use another > method name seems better.Why don''t you agree?> second,you mentioned that "objective.class" will return Hash? It''s > impossible,Objective#create return a instance of Objective or nil~~I agree it is very strange but the log file clearly shows that it is returning a Hash (so are the error messages I get when I try to call a method).> finally,show out your code about Rspec,please~#I am using machinist. Objective.plan returns a hash with values I specify elsewhere it "should return objective when create called" do obj = Objective.create(Objective.plan, 5) obj.class.to_s.should == "Objective" end
Marnen Laibow-Koser
2009-Oct-25 21:15 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
drewB wrote: [...]> Code:> > class Objective < ActiveRecord::Base > belongs_to :user > has_many :next_actions, :order => ''id DESC'', :conditions => > {:completed => false} > has_many :action_items, :order => ''position'' > has_many :progress_updates > > serialize :freq_value > > > validates_presence_of :name, :due_date, :completion, :pr_u_frequency_id > validates_numericality_of :completion, :only_integer => > true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 > > def self.create(attributes, user_id) > #create new record with user_id correctly set > attributes.delete :freq_options #deletes this unused key > obj = self.new(attributes) > obj.user_id = user_id > obj.save ? obj : nil > > end >I don''t know if this is directly related to your problem, but why are you overriding AR::Base.create ? You shouldn''t need to; just do @user.objectives.create(attributes). You''re trying to reinvent what AR already gives you for free.> end >[...] Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
It is overwritten because the objective requires a user_id which comes from a different place than the other attributes. I could simply use create and add more code at the controller level but I prefer to push that down to the model. On Oct 25, 2:15 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- s.net> wrote:> drewB wrote: > > [...]> Code: > > > > > > > class Objective < ActiveRecord::Base > > belongs_to :user > > has_many :next_actions, :order => ''id DESC'', :conditions => > > {:completed => false} > > has_many :action_items, :order => ''position'' > > has_many :progress_updates > > > serialize :freq_value > > > validates_presence_of :name, :due_date, :completion, :pr_u_frequency_id > > validates_numericality_of :completion, :only_integer => > > true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 > > > def self.create(attributes, user_id) > > #create new record with user_id correctly set > > attributes.delete :freq_options #deletes this unused key > > obj = self.new(attributes) > > obj.user_id = user_id > > obj.save ? obj : nil > > > end > > I don''t know if this is directly related to your problem, but why are > you overriding AR::Base.create ? You shouldn''t need to; just do > @user.objectives.create(attributes). You''re trying to reinvent what AR > already gives you for free. > > > end > > [...] > > Best, > -- > Marnen Laibow-Koserhttp://www.marnen.org > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > -- > Posted viahttp://www.ruby-forum.com/.
bonyfish choi
2009-Oct-26 05:36 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
Marnen Laibow-Koser had pointed out the reason. put more code at the model is best practice,but in this situation,ActiveRecord already gives you a brief solution~ your problem seems so strange....I will write codes to test it...
bonyfish choi
2009-Oct-26 05:56 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
maybe you should use another method name and try again~~ On Oct 26, 1:36 pm, bonyfish choi <mc02...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Marnen Laibow-Koser had pointed out the reason. > put more code at the model is best practice,but in this > situation,ActiveRecord already gives you a brief solution~ > > your problem seems so strange....I will write codes to test it...
Marnen Laibow-Koser
2009-Oct-26 12:49 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
drewB wrote:> It is overwritten(Overridden. Overwritten means something else.)> because the objective requires a user_id which comes > from a different place than the other attributes. I could simply use > create and add more code at the controller levelThis is the sort of very simple logic that is appropriate in the controller.> but I prefer to push > that down to the model.Then create a method with a different name -- say, create_with_user_id -- or use a before_create callback to set the user_id. Don''t override create.> On Oct 25, 2:15�pm, Marnen Laibow-Koser <rails-mailing-l...@andreas-Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
Frederick Cheung
2009-Oct-26 13:03 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
On Oct 26, 12:49 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- s.net> wrote:> > Then create a method with a different name -- say, create_with_user_id > -- or use a before_create callback to set the user_id. Don''t override > create.or in this case, using associations and writing some_user.objectives.create(...) would be even nicer. Would still be interesting to find exactly what is going on. Fred> > > On Oct 25, 2:15 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- > > Best, > -- > Marnen Laibow-Koserhttp://www.marnen.org > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > -- > Posted viahttp://www.ruby-forum.com/.
On Oct 26, 6:03 am, Frederick Cheung <frederick.che...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On Oct 26, 12:49 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- > > s.net> wrote: > > > Then create a method with a different name -- say, create_with_user_id > > -- or use a before_create callback to set the user_id. Don''t override > > create. > > or in this case, using associations and writing > some_user.objectives.create(...) would be even nicer.I see where you are coming from.> Would still be interesting to find exactly what is going on.Yes, very much so!> > Fred > > > > > > On Oct 25, 2:15 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- > > > Best, > > -- > > Marnen Laibow-Koserhttp://www.marnen.org > > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > > -- > > Posted viahttp://www.ruby-forum.com/.
Try this: class ObjectivesController < ApplicationController before_filter :require_user layout false def create objective = current_user.objectives.create(params[:objective]) end end And as others have said, don''t overwrite AR class methods like ''create'', otherwise you will enter a world of pain. Also, you are deleting a param called ''freq_options'', if the model does not need it then it shouldn''t be in the hash. If the controller needs it, then pass it as params[:freq_options] rather than params [:objective][:freq_options]. If it''s not used there, then why pass it at all? -- W On Oct 24, 11:31 am, drewB <dbats...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I am running into a very odd problem. I have an ActiveRecord called > Objective with a public create method. When this method is called in > a controller the return value is a Hash instead of Objective. When I > test the method in Rspec for the model it returns as Objective. > > Does anyone have an idea about why the return type would be different > and if so how to fix it so it always returns Objective? > > Code: > > class Objective < ActiveRecord::Base > belongs_to :user > has_many :next_actions, :order => ''id DESC'', :conditions => > {:completed => false} > has_many :action_items, :order => ''position'' > has_many :progress_updates > > serialize :freq_value > > validates_presence_of :name, :due_date, :completion, :pr_u_frequency_id > validates_numericality_of :completion, :only_integer => > true, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 > > def self.create(attributes, user_id) > #create new record with user_id correctly set > attributes.delete :freq_options #deletes this unused key > obj = self.new(attributes) > obj.user_id = user_id > obj.save ? obj : nil > > end > > end > > class ObjectivesController < ApplicationController > before_filter :require_user > > layout false > > def create > objective = Objective.create(params[:objective], current_user.id) > Rails.logger.info("****objective.class = #{objective.class}****") > end > end
Marnen Laibow-Koser
2009-Oct-26 16:51 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
Wes wrote:> Try this: > > class ObjectivesController < ApplicationController > before_filter :require_user > layout false > def create > objective = current_user.objectives.create(params[:objective]) > end > endNo! Create shouldn''t be a controller method.> > And as others have said, don''t overwriteover*ride*> AR class methods like > ''create'', otherwise you will enter a world of pain.Yeah. If you must override, it''s probably best to do something like def create(attributes, user_id) super(attributes.merge :user_id => user_id) end but even this is kind of bad.> > Also, you are deleting a param called ''freq_options'', if the model > does not need it then it shouldn''t be in the hash. If the controller > needs it, then pass it as params[:freq_options] rather than params > [:objective][:freq_options]. If it''s not used there, then why pass it > at all?Good catch!> > -- WBest, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
On Oct 26, 9:51 am, Marnen Laibow-Koser <rails-mailing-l...@andreas- s.net> wrote:> Wes wrote: > > Try this: > > > class ObjectivesController < ApplicationController > > before_filter :require_user > > layout false > > def create > > objective = current_user.objectives.create(params[:objective]) > > end > > end > > No! Create shouldn''t be a controller method.Why not?> > > > And as others have said, don''t overwrite > > over*ride* > > > AR class methods like > > ''create'', otherwise you will enter a world of pain.Thanks for the good practice tip.> Yeah. If you must override, it''s probably best to do something like > > def create(attributes, user_id) > super(attributes.merge :user_id => user_id) > end > > but even this is kind of bad. > > > > > Also, you are deleting a param called ''freq_options'', if the model > > does not need it then it shouldn''t be in the hash. If the controller > > needs it, then pass it as params[:freq_options] rather than params > > [:objective][:freq_options]. If it''s not used there, then why pass it > > at all? > > Good catch! >It will eventually be used, just not yet.> > > -- W > > Best, > -- > Marnen Laibow-Koserhttp://www.marnen.org > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > -- > Posted viahttp://www.ruby-forum.com/.
On Oct 26, 12:51 pm, Marnen Laibow-Koser <rails-mailing-l...@andreas- s.net> wrote:> Wes wrote: > > Try this: > > > class ObjectivesController < ApplicationController > > before_filter :require_user > > layout false > > def create > > objective = current_user.objectives.create(params[:objective]) > > end > > end > > No! Create shouldn''t be a controller method.Huh? It''s rails convention. A restful controller has 6 actions (index, show, create, edit, update, destroy).> > > And as others have said, don''t overwrite > > over*ride*Wow, why so pedantic? The intent was clear. Did I kick your puppy or something?> > AR class methods like > > ''create'', otherwise you will enter a world of pain. > > Yeah. If you must override, it''s probably best to do something like > > def create(attributes, user_id) > super(attributes.merge :user_id => user_id) > end > > but even this is kind of bad.That''s a really bad example as the additional parameter is handled via an association. Besides, if an attribute is not in the request attributes hash, it''s much easier to just add it in the controller, since that''s what you''re already doing in a backwards sort of way. Ex: Foo.create(params[:foo].merge(:my_var => ''bar'')) vs. Foo.create (params[:foo], ''bar'') + an ugly overridden method in the class -- W> > Also, you are deleting a param called ''freq_options'', if the model > > does not need it then it shouldn''t be in the hash. If the controller > > needs it, then pass it as params[:freq_options] rather than params > > [:objective][:freq_options]. If it''s not used there, then why pass it > > at all? > > Good catch! > > > > > -- W > > Best, > -- > Marnen Laibow-Koserhttp://www.marnen.org > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > -- > Posted viahttp://www.ruby-forum.com/.
On Oct 26, 1:27 pm, drewB <dbats...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On Oct 26, 9:51 am, Marnen Laibow-Koser <rails-mailing-l...@andreas- > > s.net> wrote: > > Wes wrote: > > > Try this: > > > > class ObjectivesController < ApplicationController > > > before_filter :require_user > > > layout false > > > def create > > > objective = current_user.objectives.create(params[:objective]) > > > end > > > end > > > No! Create shouldn''t be a controller method. > > Why not?There''s no reason not to. In fact it''s a Rails convention to do so.> > > And as others have said, don''t overwrite > > > over*ride* > > > > AR class methods like > > > ''create'', otherwise you will enter a world of pain. > > Thanks for the good practice tip. > > > > > > > Yeah. If you must override, it''s probably best to do something like > > > def create(attributes, user_id) > > super(attributes.merge :user_id => user_id) > > end > > > but even this is kind of bad. > > > > Also, you are deleting a param called ''freq_options'', if the model > > > does not need it then it shouldn''t be in the hash. If the controller > > > needs it, then pass it as params[:freq_options] rather than params > > > [:objective][:freq_options]. If it''s not used there, then why pass it > > > at all? > > > Good catch! > > It will eventually be used, just not yet.Ok, if you intend to use it later, then you can just specify an accessor in your model, that way you can pass it in without error. class Objective < ActiveRecord::Base attr_accessor :freq_options end Then later if you add this as a db attribute, you can remove the accessor. Otherwise you may want to do some manipulation of other data in the model based on the value of this accessor (via callbacks). -- W> > > > > -- W > > > Best, > > -- > > Marnen Laibow-Koserhttp://www.marnen.org > > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > > -- > > Posted viahttp://www.ruby-forum.com/.
Marnen Laibow-Koser
2009-Oct-26 17:56 UTC
Re: ActiveRecord is being converted to Hash unexpectedly
drewB wrote:> On Oct 26, 9:51�am, Marnen Laibow-Koser <rails-mailing-l...@andreas- > s.net> wrote: >> >> No! �Create shouldn''t be a controller method. > > Why not?Sorry, that was a flash of abject stupidity on my part. :) Please feel free to ignore it.> >> >> >> > And as others have said, don''t overwrite >> >> over*ride* >> >> > AR class methods like >> > ''create'', otherwise you will enter a world of pain. > > Thanks for the good practice tip. > >> > Also, you are deleting a param called ''freq_options'', if the model >> > does not need it then it shouldn''t be in the hash. If the controller >> > needs it, then pass it as params[:freq_options] rather than params >> > [:objective][:freq_options]. If it''s not used there, then why pass it >> > at all? >> >> Good catch! >> > > It will eventually be used, just not yet.Then you don''t need it. Put it in when you do. Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
Thanks everyone for the help. I didn''t end up figuring out what was causing the problem but changing the code to current_user.Objective... fixed the problem and makes a lot more sense. I hope not too many puppies were hurt during this exchange :). On Oct 26, 10:56 am, Marnen Laibow-Koser <rails-mailing-l...@andreas- s.net> wrote:> drewB wrote: > > On Oct 26, 9:51 am, Marnen Laibow-Koser <rails-mailing-l...@andreas- > > s.net> wrote: > > >> No! Create shouldn''t be a controller method. > > > Why not? > > Sorry, that was a flash of abject stupidity on my part. :) Please feel > free to ignore it. > > > > > > >> > And as others have said, don''t overwrite > > >> over*ride* > > >> > AR class methods like > >> > ''create'', otherwise you will enter a world of pain. > > > Thanks for the good practice tip. > > >> > Also, you are deleting a param called ''freq_options'', if the model > >> > does not need it then it shouldn''t be in the hash. If the controller > >> > needs it, then pass it as params[:freq_options] rather than params > >> > [:objective][:freq_options]. If it''s not used there, then why pass it > >> > at all? > > >> Good catch! > > > It will eventually be used, just not yet. > > Then you don''t need it. Put it in when you do. > > Best, > -- > Marnen Laibow-Koserhttp://www.marnen.org > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > -- > Posted viahttp://www.ruby-forum.com/.