0

I have a field in my model, :birth_time, that I'm trying to build from 3 form fields but am having a heck of a time. I've tried two different approaches. Here is a snippet from my form in my first approach:

    <input type="text" class="span1" name="birth_time_hour" id="birth_time_hour" placeholder="hour">
    <input type="text" class="span1" name="birth_time_minute" id="birth_time_minute" placeholder="minute">
    <select name="birth_time_meridiem" id="birth_time_meridiem" class="span1">
      <option value="am">AM</option>
      <option value="pm">PM</option>
    </select>

And my model:

attr_accessible :birth_time

What I want to do in my controller is grab those three form values, create a Time object, and set it to Pick.birth_time before saving. I'm having a problem doing any arithmetic on params["birth_time_hour"]. If it's PM I want to add 12 to it before creating the Time object.

params["birth_time_hour"] + 12 results in can't convert Fixnum into String params["birth_time_hour"].to_i results in exception class/object expected.

Do I need to create an object from the form value first?

My second approach was to add attr_accessible values to the model, even though they aren't actually stored in the database.

attr_accessible :birth_time_hour, :birth_time_minute, :birth_time_meridien, :birth_time

And then in my form (using simple_form):

<%= f.input :birth_time, :label => "Birth time:", :as => :tel, :input_html => { :class => 'span2' }, :placeholder => 'hour' %>

But that just bombs out when trying to render the form:

undefined method `birth_time_hour' for #<Pick:0x0000010657c248>

I'm not really sure why I can't have an attr_accessible for it. I've used it with password fields before that exist only on the form but not in the database.

EDIT: It seems to work better when I use attr_accessible and attr_accessor for birth_time_hour. It can at least build the form but I still don't see it as part of the Pick object in the controller. I have very little knowledge of attr_accessor and what it's used for, that is clear I'm sure.

Any ideas on how to solve a seemingly simple problem? I've read other SO threads that suggest storing all 3 values in the database, which seems stupid as all get out to me. I really hope that's not the case.

Ryan Arneson
  • 1,323
  • 3
  • 14
  • 25

2 Answers2

0

Why not use the time_select? It does all this automatically for you. http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_select

attr_accessible :birth_time 

is all you need in your model.

In your form use

 <%= f.time_select :birth_time %>

time_select has a few options. Refer the manual.


You could use composed_of composed_of in Rails - when to use it?


If that's not good enough, then... I guess you can just create your own setter method. (To answer your question)

def birth_time=(birth_time)
  # create the time object from birth_time

end

In your form

= text_field_tag "model_name[birth_time][hr]"
= text_field_tag "model_name[birth_time][min]"
= text_field_tag "model_name[birth_time][sec]"

(you could also use f.fields_for :birth_time if you would prefer that method of generating the names)

= form_for @model do |f|
    = f.fields_for :birth_time do |btf|
        - [:hr, :min, :sec].each do |n|
            = btf.text_field n

Now, In your setter method, you will get a hash that looks like this:

{ 'hr' => '12', 'min' => '16', 'sec' => '26' }

With that, you can construct your value from the hash and set it to:

self[:birth_time] = 

I hope that helps. There might be other ways to do it, but this, I think is the simplest.

Community
  • 1
  • 1
SMathew
  • 3,993
  • 1
  • 18
  • 10
  • I've played around with that and don't like two huge drop downs. Plus I want to let my users type in using a 12 hour clock with AM/PM. Even if I went that route I'd still like to know the answer to my questions. – Ryan Arneson Jul 11 '12 at 00:46
  • Thanks for the update, it was just what I needed. I used the solution of the setter in my model and it worked like a charm. – Ryan Arneson Jul 13 '12 at 04:53
0

It seemds that you're confused about what attr_accessible means.

attr_acessible means that you could do mass-assignment of the attribute like this model.update_attributes({:birth_time_hour => '1'})

But you obviously don't need this because you don't have the field birth_time_hour in your model.

As for what attr_accessor does, it defines a reader and writer for your class in this way

attr_accessor :my_var

#is the same as

def my_var
  @my_var
end

def my_var=(value)
  @my_var = value
end

As for your problem you should do something like this in your model:

def birth_time_minute
  self.birth_time.min
end

def birth_time_hour
  self.birth_time.hour
end

Assuming that birth_time is a time object(which would make sense)