Phoenix.HTML.Form date_select/3 for optional date - phoenix-framework

The problem
I have a form where I have a field for an application date. This value is optional, as it can be provided at a later time (i.e. it is not necessarily present when the form is saved).
Using date_select/3, I'm unable to find a simple way to have this value be optional. Even if default: nil is provided as an option, the current date is filled in the fields. This is not the desired behavior, as when the user saves the form the value would be updated also.
What I'd like
A field to enter a date, with the possibility of leaving it blank (which would be the default behavior).
What I've got so far
You can get a date field for an optional value using the builder option and using empty prompts:
<%= date_select f, :applied_on, builder: fn b -> %>
Date: <%= b.(:day, [prompt: ""]) %>.<%= b.(:month, [prompt: ""]) %>.<%= b.(:year, [prompt: ""]) %>
<% end %>
Isn't there a better, more elegant way to handle optional dates?

If the field is required or not should handled by your validating, default in model part by ecto.
From Phoenix.HTML.Form.datetime_select/3:
:year, :month, :day, :hour, :minute, :second - options passed to the underlying select. See select/4 for more information. The available values can be given in :options.
From Phoenix.HTML.Form.select/4:
:prompt - an option to include at the top of the options with the given prompt text
You need only to set the prompt (or other select-specific options) to the field option (:year, :month, :day, :hour, :minute and :second) of date_select. This should work:
<%= date_select f, :applied_on, year: [prompt: ""], month: [prompt: ""], day: [prompt: ""] %>
This will work for datetime_select/3, date_select/3 and time_select/3.
Hope this helps.

Related

optional date field with simple_form

I am using simple_form to generate date input like so:
= f.input :date_of_death
However, it always pre-populates with the current date.
How can I have it come up "blank" and allow the user to easily NOT enter a date?
Thanks!
There are a couple of ways to do this while still keeping the form split into dropdowns for Y/M/D.
= f.input :date_of_death, include_blank: true
Or if you want the first option to have text use prompt.
= f.input :date_of_death, prompt: "Choose Wisely"
Simplest way that I have found
f.input :date_of_death, as: :string
It will turn the input into a blank input field. You will have to parse the string as a date in your controller.
Use include_blank
= f.input :fecha_at, include_blank: true, start_year: Date.today.year - 90, end_year: Date.today.year

Rails 3 how to deal with constants

I have a constant called PAYMENT_METHODS in venue.rb.
PAYMENT_METHODS = ['Visa', 'MasterCard', 'American Express', 'Diners', 'JCB', 'Bankomat', 'sodexo', 'MA-Gutscheine']
You can check/uncheck the payment types in a form (payment_options is an integer):
<%= hidden_field_tag "venue[payment_options][]", nil %>
<% Venue::PAYMENT_METHODS.each do |category| %>
<%= check_box_tag "venue[payment_options][]", category %>
<%= label_tag category %>
<% end %>
Now I want to save the selection, but the value of each check box is the name of the payment option. I think I have to somehow add a key an store only the keys.
How do I set keys and save the collection to the database?
Thanks in advance
Make the constant a hash or an array, e.g.
PAYMENT_METHODS = {'Visa' => 1, 'MasterCard' => 2, 'American Express' => 3, 'Diners' => 4, 'JCB' => 5, 'Bankomat' => 6, 'sodexo' => 7, 'MA-Gutscheine' => 8 }
These will now be in a format that you can pass to options_for_select http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select.
If you (really) want checkboxes, an array is fine, just loop over using PAYMENT_MTHODS.each_index do |index| to get an iterator that's the value, and then use PAYMENT_METHODS[index].
I have always found it odd that the hash key is the part displayed in the list, but I guess it makes sense that the value is what is associated with the option's value :-).
Save the string value itself nothing wrong with that.
Its better to create a model like PaymentType and just keep id,name and in view render all payment types.This way you can better manipulate all available payment options in future from an admin panel (if needed) rather than going to a code level and changing at the constant.
You can use an element's index as a key. Use Array#index to your advantage.
PAYMENT_METHODS.index("Visa") #=> 0
PAYMENT_METHODS[0] #=> "Visa"
PAYMENT_METHODS.index("Diners") #=> 3
PAYMENT_METHODS[3] #=> "Diners"
A word of caution: This will break if you reorder PAYMENT_METHODS. You are keying an element to it's relative position in the array. Change the array and you change the keys. Avoid trouble by keeping your constants constant.
In regards to
I have always found it odd that the hash key is the part displayed in the list, but I guess it makes sense that the value is what is associated with the option's value :-).
you can get that done by (it was bugging me a bit as well)
<% Post::TECH_CATEGORY.each do |category| %>
<%= label_tag 'name', category[0] %>
<%= check_box_tag 'tech_cat', category[1] %>
<% end %>
It makes sense now that I can see it on the screen. Each object has two values, so...
category[0]
will always be the key you supplied for that specific object you are currently enumerating over
category[1]
will be the value of that same object. Looks way better on the screen.
which looks like in your example above
<label for="name"> Visa </label>
<input id="tech_cat" name="tech_cat" type="checkbox" value="1" />
Cheers,

text_field_tag with pre-filled text and custom params

I'm trying to get this to work in one of my views:
<%= text_field_tag :sources, "Test", params[:sources] %>
but I get undefined method 'stringify_keys' for nil:NilClass. The code
<%= text_field_tag :sources, "Test" %>
works fine and pre-fills the box with "Test" (but doesn't pass params properly), while the the code
<%= text_field_tag :sources, params[:sources] %>
passes params properly but doesn't have the text "Test" where I need it.
Does anyone know the syntax or a workaround?
The syntax you're looking for is documented:
text_area_tag(name, content = nil, options = {})
The problem with your code is that given three arguments text_field_tag expects the third to be a Hash, but params[:sources] is giving nil. Are you expecting it to hold a different value? Where is params set, and what does it contain?
If you know that params[:sources] will sometimes contain a Hash and other times be nil (i.e. not set) then you could use e.g.:
<%= text_field_tag :sources, "Test", params[:sources] || {} %>
params[:sources] || {} will evaluate to an empty Hash ({}) whenever params[:sources] is falsy (e.g. nil), which will avoid the error.

Rails 3.0 - Where to put this logic?

I've got a Model Task with a member due_date. I'm using Chronic to take natural language input from the user and convert it to a Time, which then gets saved to the model.
I'm just not sure the best Rails, MVC-ish way to handle these use cases:
Display a formatted string (with some logic involved) to the user every time I show Task.due_date
Allow the user to input plaintext and have it parsed automagically everywhere they can edit Task.due_date
A helper method to format time was my first idea, like this:
<%= format_time task.due_date %>
combined with an overloaded setter on an accessor in my Task model, like this:
attr_accessor :due_date_string
def due_date_string=(string)
self.due_date = Chronic.parse(string)
end
This works everywhere I want it to except in my forms for editing:
<div class="field">
<%= f.label :due_date %>
<%= f.text_field :due_date_string %>
</div>
I don't know how to make the f.text_field element 'wire up' properly so that it saves to :due_date_string, but uses the helper method to display the string.
I don't necessarily need specific code examples, just looking for the kind of pattern that pro Rails-ers would use here.
Thanks!
With according to MVC conventions, data handle is about Model layer responsibility.
So you are going in right direction to do a setter (wrapper for due_date attribute):
You need to check that is attr_acessible that is access to get a data from params
def due_date_string=(string)
self.due_date = Chronic.parse(string) || Date.today
end
The representation logic to show the parsed date is Helper layer responsibility
In order to use:
f.text_field :due_date_string
Don't you also need a getter for the new attribute? e.g.,
def due_date_string
format_time self.due_date
end
Perhaps share what error or failure occurs when you use the custom text field. :)

Iterate Form fields

I have build a module to add translations for each standard topic. Theses topic got many standard options and you can translate it directly in page.
I got an issue with my form about the edit view.
When i display a translation it's repeat all value of the f.input :value each time he have one and i want it to display with the each of standard value.
The question is how i can iterate my input field :value in the form to display only once per standard value and not repeat all value translated by standard value.
when i want create a new one all workings fine. It's just about the iterate field who is repeated how many times he got a field in the table.
the gist for my code :
https://gist.github.com/266562670cd8dab28548
Change:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first, option do |translate_form| %>
to:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first || option.preference_topic_option_translations.build, option do |translate_form| %>

Resources