Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do ruby on rails multi parameter attributes *really* work (datetime_select)

I believe that datetime_select is black magic. What I'm really trying to figure out is the whole 1i,2i,3i,4i... multiple parameters stuff. Specifically how is it handled in the back end (activerecord, something else?). What's with the 'i' after the order-number? Is it a type-specifier? If so what are other types that are available? I've read the source of date_helper.rb and it's quite opaque.

Here's my motivation:

I've got a :datetime column in my model and I want to input in the view via two text_fields: one for date and one for time. They need to be validated, merged together, then stored into the datetime column. Ultimately I'll be using a javascript calendar to input dates into the date field.

So has anybody done this? I tried using virtual attributes (incredibly undocumented besides the rudimentary railscast) and the issue was that when a new activerecord object is created and has nil attributes, the virtual attribute fails (undefined method strftime for nil class, which makes sense).

Anybody have any suggestions or best practices? Thanks!

like image 254
Dean Stamler Avatar asked Sep 23 '09 18:09

Dean Stamler


1 Answers

I had the same question. Here's what I found...

http://apidock.com/rails/ActiveRecord/Base/assign_multiparameter_attributes

assign_multiparameter_attributes(pairs) private

Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters. So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the parentheses to have the parameters typecasted before they’re used in the constructor. Use i for Fixnum, f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.

So the numbers are for the parameters of the data type that the column is. The "i" is to convert it to an integer. Other types are supported like "f" for float, etc.

You can see here in execute_callstack_for_multiparameter_attributes that it detects the target type and instantiates it passing the values.

So, to try directly answering the posed question, I don't think you can use it to override how a DateTime is created because it uses the constructor which doesn't support the format you want to pass in. My work-around was to split the DateTime column out to one Date and one Time column. Then the UI could work the way I wanted.

I wonder if it might be possible to create attribute accessors on the class that represent the date and time separately but keep a single DateTime column. Then the form could reference those separate accessors. That might be workable. Another option might be to use composed_of to customize the type further.

Hope that helps someone else. :)

like image 112
Mark Eric Avatar answered Sep 21 '22 13:09

Mark Eric