Skip to content

Instantly share code, notes, and snippets.

@aganov
Created October 4, 2011 13:48
Show Gist options
  • Save aganov/1261688 to your computer and use it in GitHub Desktop.
Save aganov/1261688 to your computer and use it in GitHub Desktop.
Formtastic jQuery UI date and time picker input
# http://jqueryui.com/demos/datepicker/
# http://fgelinas.com/code/timepicker/
class DatetimeUiInput
include Formtastic::Inputs::Base
DATE_FORMAT = "%Y-%m-%d"
TIME_FORMAT = "%H:%M"
def to_html
input_wrapping do
fragments_wrapping do
hidden_fragments <<
fragments_label <<
template.content_tag(:ol,
fragments.map do |fragment|
fragment_wrapping do
fragment_label_html(fragment) <<
fragment_input_html(fragment)
end
end.join.html_safe, # TODO is this safe?
{ :class => 'fragments-group' } # TODO refactor to fragments_group_wrapping
)
end
end
end
def fragments
[:date, :time]
end
def fragment_wrapping(&block)
template.content_tag(:li, template.capture(&block), fragment_wrapping_html_options)
end
def fragment_wrapping_html_options
{ :class => 'fragment' }
end
def fragment_label(fragment)
labels_from_options = options[:labels] || {}
if labels_from_options.key?(fragment)
labels_from_options[fragment]
else
::I18n.t(fragment.to_s, :default => fragment.to_s.humanize, :scope => [:datetime, :prompts])
end
end
def fragment_id(fragment)
"#{input_html_options[:id]}_#{position(fragment)}s"
end
def fragment_name(fragment)
"#{method}(#{position(fragment)}s)"
end
def fragment_label_html(fragment)
text = fragment_label(fragment)
text.blank? ? "".html_safe : template.content_tag(:label, text, :for => fragment_id(fragment))
end
def value(fragment)
object.send(method).strftime(class_eval("#{fragment.to_s.upcase}_FORMAT"))
end
def fragment_input_html(fragment)
opts = input_html_options.merge(:id => fragment_id(fragment), :value => value(fragment), :class => "#{fragment}picker", :readonly => "readonly")
template.send(:text_field, object_name, fragment_name(fragment), opts)
end
def positions
{ :date => 1, :time => 2 }
end
def position(fragment)
positions[fragment]
end
def i18n_date_fragments
order = ::I18n.t(:order, :scope => [:date])
order = nil unless order.is_a?(Array)
order
end
def fragments_wrapping(&block)
template.content_tag(:fieldset,
template.capture(&block).html_safe,
fragments_wrapping_html_options
)
end
def fragments_wrapping_html_options
{ :class => "fragments" }
end
def fragments_label
if render_label?
template.content_tag(:legend,
builder.label(method, label_text, :for => "#{input_html_options[:id]}_1s"),
:class => "label"
)
else
"".html_safe
end
end
def fragments_inner_wrapping(&block)
template.content_tag(:ol,
template.capture(&block)
)
end
def hidden_fragments
"".html_safe
end
end
@dmoulton
Copy link

Does this need formtastic 2, or will it work on 1.2?

@aganov
Copy link
Author

aganov commented Dec 16, 2011

formtastic 2

@sarkis
Copy link

sarkis commented Apr 9, 2012

I can't get this working with activeadmin, I am getting the following error:

Started GET "/admin/events/new" for 127.0.0.1 at 2012-04-09 11:09:09 -0700
Processing by Admin::EventsController#new as HTML
AdminUser Load (1.1ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = 1 LIMIT 1
Status Load (0.3ms) SELECT "statuses".* FROM "statuses"
Rendered /Users/sarkis/.rvm/gems/ruby-1.9.3-p125@statusboard/gems/activeadmin-0.4.3/app/views/active_admin/resource/new.html.arb (146.2ms)
Completed 500 Internal Server Error in 196ms

ActionView::Template::Error (undefined method strftime' for nil:NilClass): 1: render renderer_for(:new) app/inputs/datetime_ui_input.rb:59:invalue'
app/inputs/datetime_ui_input.rb:63:in fragment_input_html' app/inputs/datetime_ui_input.rb:15:inblock (4 levels) in to_html'
app/inputs/datetime_ui_input.rb:29:in fragment_wrapping' app/inputs/datetime_ui_input.rb:14:inblock (3 levels) in to_html'
app/inputs/datetime_ui_input.rb:13:in map' app/inputs/datetime_ui_input.rb:13:inblock (2 levels) in to_html'
app/inputs/datetime_ui_input.rb:83:in fragments_wrapping' app/inputs/datetime_ui_input.rb:12:inblock in to_html'
app/inputs/datetime_ui_input.rb:11:in to_html' app/admin/events.rb:22:inblock (3 levels) in <top (required)>'
app/admin/events.rb:19:in `block (2 levels) in <top (required)>'

Rendered /Users/sarkis/.rvm/gems/ruby-1.9.3-p125@statusboard/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/_trace.erb (4.5ms)
Rendered /Users/sarkis/.rvm/gems/ruby-1.9.3-p125@statusboard/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)
Rendered /Users/sarkis/.rvm/gems/ruby-1.9.3-p125@statusboard/gems/actionpack-3.2.1/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (
7.5ms)
^C[2012-04-09 11:12:20] INFO going to shutdown ...
[2012-04-09 11:12:20] INFO WEBrick::HTTPServer#start done.
Exiting

Any ideas on what I am doing wrong? I have included jquery-rails gem and have included jquery-ui in my application.js...

@sarkis
Copy link

sarkis commented Apr 9, 2012

Do I need to grab anything from here: http://fgelinas.com/code/timepicker/

@aganov
Copy link
Author

aganov commented Apr 10, 2012

@SarkisV maybe you did not have an attribute for the field you are trying to show DatetimeUiInput or the value of this field is nil (NULL)
another solution will be to replace value method with something like this (untested!)

  def value(fragment)
    val = object.send(method)
    return "" if val.blank?
    val.strftime(class_eval("#{fragment.to_s.upcase}_FORMAT"))
  end

@budu
Copy link

budu commented Mar 26, 2013

How is multiparameter assignement is done with this code?

@stereoscott
Copy link

@aganov thanks for this! It's working great. @budu I'm still trying to figure out how to use strong_paramaters with this... I'm getting an ActiveRecord::MultiparameterAssignmentErrors exception when I try to post the form. Will post back when I figure it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment