Hello, I am trying to deal with a database table that contains a date in the form of the number of seconds since epoch. Data is inserted in this format by an existing script that I can''t change, so a schema change isn''t realistic. I would like to allow humans to view and edit this data in the form of an actual human-readable date. I figured a facade column would be the way to go here, but I am stuck on the fact that the inputs from the facade type are multiparameter. This breaks the update_attributes call in ActiveRecord::Base with a NoMethodError in my object''s controller''s update method. I have tried to add an additional attribute to the object''s attributes hash, but this code (which I put in the controller''s update method) fails silently - the attributes written out are the same before and after: puts "the attributes currently are:" @event.attributes.each do |key, value| puts "#{key} = #{value}" end @event.attributes.store("occurred_at", nil) puts "after attempting to add an attribute, the attributes are:" @event.attributes.each do |key, value| puts "#{key} = #{value}" end Any suggestions? Has anyone used a facade column on a Date? Since the problem occurs in the *controller* update method, I can''t see how to use a callback to do the conversion, am I wrong? (Is part of my problem the name of the column, which is "updated_at" ? I tried renaming it for testing but got the same error.) Thanks, Rachel Snips from the applicable files: event.rb ------------- class Event < ActiveRecord::Base # create a a field based on updated_at, that''s an actual Date kind # of object def occurred_at Time.at( read_attribute("updated_at") ) end def occurred_at=(date) write_attribute( "updated_at", date.to_i ) end end event_controller.rb -------------- ... def update @event = Event.find(params[:id]) if @event.update_attributes(params[:event]) flash[:notice] = ''Event was successfully updated.'' redirect_to :action => ''show'', :id => @event else render :action => ''edit'' end end ... _form.rhtml -------------- ... <p><label for="event_updated_at">Occurred at</label><br/> <%= datetime_select ''event'', ''occurred_at'' %></p> ... This displays the date in the dropdowns correctly. However, if I try to save a change (or even the same data), I get this: NoMethodError in Event#update You have a nil object when you didn''t expect it! The error occured while evaluating nil.klass c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1685:in `execute_callstack_for_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1684:in `each'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1684:in `execute_callstack_for_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1677:in `assign_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1339:in `attributes='' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1266:in `update_attributes'' #{RAILS_ROOT}/app/controllers/event_controller.rb:34:in `update''
Rachel McConnell <rachel@...> writes:> I am trying to deal with a database table that contains a date in the > form of the number of seconds since epoch. Data is inserted in this > format by an existing script that I can''t change, so a schema change > isn''t realistic. >[snip]> > (Is part of my problem the name of the column, which is "updated_at" ? > I tried renaming it for testing but got the same error.)updated_at is automatically updated for all ActiveRecord::Base descendants. So if this column records something else, you should definitely name it something else. Perhaps what you want to do is grab the values from the form in your controller and then have some logic in the model save it/convert it to the database column in the proper format. like add an attribute to your model (but not your db) called "my_date" and have an attribute in your database called "epoch_thingy" or whatever you call it: class MyModel attr :my_date before_save :do_that_date_thing def do_that_date_thing #do some kind of crazy date conversion here self.epoch_thingy = my_conversion(self.my_date) end end Something like that...? -damon http://damonclinkscales.com/
Rachel McConnell wrote:> I am trying to deal with a database table that contains a date in the > form of the number of seconds since epoch. Data is inserted in this > format by an existing script that I can''t change, so a schema change > isn''t realistic. > > I would like to allow humans to view and edit this data in the form of > an actual human-readable date. I figured a facade column would be the > way to go here, but I am stuck on the fact that the inputs from the > facade type are multiparameter. This breaks the update_attributes call > in ActiveRecord::Base with a NoMethodError in my object''s controller''s > update method.This may work: _form.html ---------- select_datetime @event.occurred_at, :prefix => ''event[occurred_at]'' event.rb -------- class Event < ActiveRecord::Base def occurred_at Time.at( updated_at ) end def occurred_at= (d) d.each_pair { |k,v| d[k] = v.to_i } self.updated_at = Time.local(d[''year''],d[''month''],d[''day''],d[''hour''],d[''minute'']).to_i end end -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James wrote:> Rachel McConnell wrote: > >> I am trying to deal with a database table that contains a date in the >> form of the number of seconds since epoch. Data is inserted in this >> format by an existing script that I can''t change, so a schema change >> isn''t realistic. >> >> I would like to allow humans to view and edit this data in the form of >> an actual human-readable date. I figured a facade column would be the >> way to go here, but I am stuck on the fact that the inputs from the >> facade type are multiparameter. This breaks the update_attributes >> call in ActiveRecord::Base with a NoMethodError in my object''s >> controller''s update method. > > > This may work: > > _form.html > ---------- > > select_datetime @event.occurred_at, :prefix => ''event[occurred_at]'' > > > event.rb > -------- > > class Event < ActiveRecord::Base > def occurred_at > Time.at( updated_at ) > end > > def occurred_at= (d) > d.each_pair { |k,v| d[k] = v.to_i } > self.updated_at = > Time.local(d[''year''],d[''month''],d[''day''],d[''hour''],d[''minute'']).to_i > end > end >I did think along those lines (and if that should work my problem is elsewhere, but i don''t know where). My code actually fails *before* it gets to call the occurred_at= method of the model object; or maybe that would never get called. The controller is using @event.update_attributes which does... something different. The stack trace shows this: c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1685:in `execute_callstack_for_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1684:in `each'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1684:in `execute_callstack_for_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1677:in `assign_multiparameter_attributes'' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1339:in `attributes='' c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1266:in `update_attributes'' #{RAILS_ROOT}/app/controllers/event_controller.rb:34:in `update'' Is there a different way to set the input parameters on the model, other than @event.update_attributes(params[:event]) ? I mean, I could parse the params and attempt to set everything by hand and that would probably work, but it kinda defeats the point of Rails'' infrastructure work. Rachel
Damon Clinkscales wrote:> Rachel McConnell <rachel@...> writes: > > >>I am trying to deal with a database table that contains a date in the >>form of the number of seconds since epoch. Data is inserted in this >>format by an existing script that I can''t change, so a schema change >>isn''t realistic. >> > > [snip] > >>(Is part of my problem the name of the column, which is "updated_at" ? >>I tried renaming it for testing but got the same error.) > > > updated_at is automatically updated for all ActiveRecord::Base descendants. So > if this column records something else, you should definitely name it something > else.MySQL allows auto-updated columns to be set explicitly; besides, I tried renaming it just to see what would happen and that didn''t help. For non-coding reasons a schema change really isn''t do-able for me.> > Perhaps what you want to do is grab the values from the form in your controller > and then have some logic in the model save it/convert it to the database column > in the proper format. >As I understand it, that''s exactly what a column facade does. But (I believe) since I''m trying to convert from a multipiece-data format to a single-piece format, it isn''t working :( Rachel
Rachel McConnell wrote:> Mark Reginald James wrote: >> _form.html >> ---------- >> >> select_datetime @event.occurred_at, :prefix => ''event[occurred_at]'' > > I did think along those lines (and if that should work my problem is > elsewhere, but i don''t know where). My code actually fails *before* it > gets to call the occurred_at= method of the model object; or maybe that > would never get called. The controller is using > @event.update_attributes which does... something different. The stack > trace shows this: > > c:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1685:in > `execute_callstack_for_multiparameter_attributes''Note that my suggestion uses select_datetime rather than datetime_select. This will prevent the multiparameter attribute assignment from trying to occur. -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James wrote:> Note that my suggestion uses select_datetime rather than datetime_select. > This will prevent the multiparameter attribute assignment from trying to > occur. >You''re right, I missed that! And your code works perfectly. Looks like it uses a 2 dimensional array instead of... a Hash, I think - whatever datetime_select produces. Must look into that more. Thank you very much! Rachel