diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 5386f506dc..21af906bcc 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Add `:day_format` option to `date_select`
+
+ date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
+ # generates day options like \n...
+
+ *Shunichi Ikegami*
+
* Allow `link_to` helper to infer link name from `Model#to_s` when it
is used with a single argument:
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 24a0784353..1a416c109d 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -206,6 +206,7 @@ module ActionView
# you are creating new record. While editing existing record, :end_year defaults to
# the current selected year plus 5.
# * :year_format - Set format of years for year select. Lambda should be passed.
+ # * :day_format - Set format of days for day select. Lambda should be passed.
# * :discard_day - Set to true if you don't want to show a day select. This includes the day
# as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
# first of the given month in order to not create invalid dates like 31 February.
@@ -279,6 +280,9 @@ module ActionView
# # Generates a date select with custom year format.
# date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
#
+ # # Generates a date select with custom day format.
+ # date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
+ #
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -811,7 +815,7 @@ module ActionView
if @options[:use_hidden] || @options[:discard_day]
build_hidden(:day, day || 1)
else
- build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers])
+ build_select(:day, build_day_options(day))
end
end
@@ -899,6 +903,27 @@ module ActionView
I18n.translate(key, locale: @options[:locale])
end
+ # Looks up day names by number.
+ #
+ # day_name(1) # => 1
+ #
+ # If the use_two_digit_numbers: true option is passed to DateTimeSelector:
+ #
+ # day_name(1) # => "01"
+ #
+ # If the day_format: ->(day) { day.ordinalize } option is passed to DateTimeSelector:
+ #
+ # day_name(1) # => "1st"
+ def day_name(number)
+ if day_format_lambda = @options[:day_format]
+ day_format_lambda.call(number)
+ elsif @options[:use_two_digit_numbers]
+ "%02d" % number
+ else
+ number
+ end
+ end
+
# Looks up month names by number (1-based):
#
# month_name(1) # => "January"
@@ -1011,6 +1036,35 @@ module ActionView
(select_options.join("\n") + "\n").html_safe
end
+ # Build select option HTML for day.
+ # build_day_options(2)
+ # => "
+ #
+ # ..."
+ #
+ # If day_format: ->(day) { day.ordinalize } option is passed to DateTimeSelector
+ # build_day_options(2)
+ # => "
+ #
+ # ..."
+ #
+ # If use_two_digit_numbers: true option is passed to DateTimeSelector
+ # build_day_options(2)
+ # => "
+ #
+ # ..."
+ def build_day_options(selected)
+ select_options = []
+ (1..31).each do |value|
+ tag_options = { value: value }
+ tag_options[:selected] = "selected" if selected == value
+ text = day_name(value)
+ select_options << content_tag("option", text, tag_options)
+ end
+
+ (select_options.join("\n") + "\n").html_safe
+ end
+
# Build select option HTML for year.
# If year_format option is not passed
# build_year_options(1998, start: 1998, end: 2000)
diff --git a/actionview/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb
index bef10e6c54..10e4077771 100644
--- a/actionview/test/template/date_helper_test.rb
+++ b/actionview/test/template/date_helper_test.rb
@@ -251,6 +251,16 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, select_day(2, use_two_digit_numbers: true)
end
+ def test_select_day_with_day_fomat
+ expected = +%(\n"
+
+ day_format = ->(day) { ActiveSupport::Inflector.ordinalize(day) }
+ assert_dom_equal expected, select_day(Time.mktime(2011, 8, 2), day_format: day_format)
+ assert_dom_equal expected, select_day(2, day_format: day_format)
+ end
+
def test_select_day_with_html_options
expected = +%(