开发者

How do you use multiple form fields to interact with a single method in rails?

开发者 https://www.devze.com 2022-12-18 09:31 出处:网络
I have a mo开发者_运维问答del which has start_at and end_at attributes. In the form for the end-user, Iam displaying start_at using the standard datetime_select, but I\'d rather not have a second date

I have a mo开发者_运维问答del 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!


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号