1

I have a model which has start_at and end_at attributes. In the form for the end-user, I am displaying start_at using the standard datetime_select, but I'd rather not have a second datetime select presented to the user. I'm hoping I can create two fields that represent a duration; one for hours, the other for minutes. My question is, how in my view do I use form helpers to automatically fill in the fields when editing an existing entry. Furthermore, how would I connect that to the model and subsequently save the recording using the real attribute, end_at?

Thanks in advance for any advice you can give!

2 Answers 2

1

I have to do this a bunch and i've been doing the following:

  1. Use the FormTagHelper versions of the calls for the field to be handled specially.
  2. In the controller, read the form_tag values out of the params object.
  3. delete the extra values:
    
    params[:examplemodelname].delete :distance if params[:examplemodelname].has_key? :distance
  1. put the 'real' values into the params object (in your example, ends_at)
  2. call ExampleModelName.new(params[:examplemodelname]) or @examplemodelname.update_attributes(params[:examplemodelname]) as per usual.
Sign up to request clarification or add additional context in comments.

2 Comments

Wouldn't logic like this be better suited for the model? Fat model, skinny controller?
My general rule on such things is that messing with the params object should happen in the controller and not the model. Displaying a date as a duration rather than an end value also seems like a view/controller issue rather than a model issue to me. If you cared about this duration in the code in places other than that form, it might be worth putting it the model but for just the use cases stated it seems like a natural for code here or maybe a helper for the form bits.
0

Wouldn't logic like this be better suited for the model? Fat model, skinny controller?

I think this is absolutely right. I despise using a controller for stuff like this. In my opinion, controllers are best used for a few things:

  1. Shuffling data between views and models, ala CRUD operations
  2. Access control (usually with before_filters)
  3. Support to fancy UI actions (multiple select, wizards, etc)

Of course everyone has to find their own balance, but I find "making an exception" for something like this tends to lead to exceptions everywhere. Not to mention the controller logic is harder to test.

To answer your question: you should simply define virtual attributes in your model that help you convert between start_at and a duration. Something like:

# Return the duration in seconds. Will look different if you want to use
# multiparameter assignment (which you definitely should consider)
def duration
  (end_at - start_at).seconds
end

# Store the duration as an instance variable. Might need to use multiparameter
# assignment if you use a time_select() in the view.
def duration=(arg)
  @duration = arg
end

before_save :set_end_at
def set_end_at
  end_at = start_at + @duration.seconds
end

I'd usually set the actual attribute in a before_save to avoid any race conditions from the form assignment. You have no guarantee that start_at will get assigned before or after duration, and that can introduce bugs in your otherwise good logic.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.