views:

489

answers:

2

I am trying to use a time_select to input a time into a model that will then perform some calculations.

the time_select helper prepares the params that is return so that it can be used in a multi-parameter assignment to an Active Record object.

Something like the following

  Parameters: {"commit"=>"Calculate", "authenticity_token"=>"eQ/wixLHfrboPd/Ol5IkhQ4lENpt9vc4j0PcIw0Iy/M=", "calculator"=>{"time(2i)"=>"6", "time(3i)"=>"10", "time(4i)"=>"17", "time(5i)"=>"15", "time(1i)"=>"2009"}}

My question is, what is the best way to use this format in a non-active record model. Also on a side note. What is the meaning of the (5i), (4i) etc.? (Other than the obvious reason to distinguish the different time values, basically why it was named this way)

Thank you

+1  A: 

The letter after the number stands for the type to which you wish it to be cast. In this case, integer. It could also be f for float or s for string.

I just did this myself and the easiest way that I could find was to basically copy/paste the Rails code into my base module (or abstract object).

I copied the following functions verbatim from ActiveRecord::Base

  • assign_multiparameter_attributes(pairs)
  • extract_callstack_for_multiparameter_attributes(pairs)
  • type_cast_attribute_value(multiparameter_name, value)
  • find_parameter_position(multiparameter_name)

I also have the following methods which call/use them:

def setup_parameters(params = {})
  new_params = {}
  multi_parameter_attributes = []

  params.each do |k,v|
    if k.to_s.include?("(")
      multi_parameter_attributes << [ k.to_s, v ]
    else
      new_params[k.to_s] = v
    end
  end

  new_params.merge(assign_multiparameter_attributes(multi_parameter_attributes))
end

# Very simplified version of the ActiveRecord::Base method that handles only dates/times
def execute_callstack_for_multiparameter_attributes(callstack)
  attributes = {}

  callstack.each do |name, values|

    if values.empty?
      send(name + '=', nil)
    else
      value = case values.size
        when 2 then t = Time.new; Time.local(t.year, t.month, t.day, values[0], values[min], 0, 0)
        when 5 then t = Time.time_with_datetime_fallback(:local, *values)
        when 3 then Date.new(*values)
        else nil
      end

      attributes[name.to_s] = value
    end

  end

  attributes
end

If you find a better solution, please let me know :-)

Topher Fangio
+2  A: 

You can create a method in the non active record model as follows

# This will return a Time object from provided hash
def parse_calculator_time(hash)
  Time.parse("#{hash['time1i']}-#{hash['time2i']}-#{hash['time3i']} #{hash['time4i']}:#{hash['time5i']}")
end

You can then call the method from the controller action as follows

time_object = YourModel.parse_calculator_time(params[:calculator])

It may not be the best solution, but it is simple to use.

Cheers :)

SamChandra