Ruby on Rails 4 - bootstrap3+simple_form+datetimepicker



**simple_form と bootstrap3は導入されているという前提で進めます。**


#Gemの追加

Bootstrap 3 Datepickerのマニュアルの通り

```rb:Gemfile
gem 'momentjs-rails', '>= 2.9.0'
gem 'bootstrap3-datetimepicker-rails', '~> 4.14.30'
```
を追加します。

追記したあと、``bundle install``をしましょう。


#inilinitializers設定



まず、``/config/inilinitializers/``に下記の設定ファイルを作ります

``date_time_picker_input.rb``を作成。


* **サンプルソース1**

```rb:/config/inilinitializers/date_time_picker_input.rb
class DateTimePickerInput < SimpleForm::Inputs::Base
  def input
    # classにform_datetimeを指定することで、coffee scriptの方で要素指定に使用されています。（見た目は変わりません）
    template.content_tag(:div, class: 'input-group date form_datetime') do
      template.concat @builder.text_field(attribute_name, input_html_options)
      template.concat span_table
    end
  end

  def input_html_options
    # classには配列で複数の設定が入ってくるので、それに'form-control'を追加してあげる
    # 単純にmergeしてしまうと、前のものが消えて'form-control'のみになってしまいバグる
    classes = (super[:class] || [])
    classes << :'form-control'
    # viewで指定された'readonly'がある場合は上書きしないようにする
    # カレンダーからの入力のみを許可したい場合は readonly: true を設定
    options = super
    options.merge({class: classes})
    options.merge({readonly: false}) unless options[:readonly]
    options
  end


  def span_table
    template.content_tag(:span, class: 'input-group-addon') do
      template.concat icon_table
    end
  end

  def icon_table
    "<span class='glyphicon glyphicon-calendar'></span>".html_safe
  end

end
```

* ``input_html_options``メソッドでは**``readonly: false``**を指定していますが、カレンダーからの入力のみを許可したい場合は**``readonly: true``**を設定してください。
* ``input``メソッドの最初で``class``に**``form_datetime``**を設定していますが、これを使用して``coffee script``側で要素指定しています。

---

参考サイトの[**simple_form Wiki - Custom inputs examples**][link-2]では、下記のようになっています。


```rb:app/inputs/date_time_picker_input.rb
class DateTimePickerInput < SimpleForm::Inputs::Base
  def input
    template.content_tag(:div, class: 'input-group date form_datetime') do
      template.concat @builder.text_field(attribute_name, input_html_options)
      template.concat span_remove  # サンプルソース1では削除
      template.concat span_table
    end
  end

  def input_html_options
    super.merge({class: 'form-control', readonly: true})  # サンプルソース1では readonly: false に設定
  end

  # サンプルソース1では削除
  def span_remove
    template.content_tag(:span, class: 'input-group-addon') do
      template.concat icon_remove
    end
  end

  def span_table
    template.content_tag(:span, class: 'input-group-addon') do
      template.concat icon_table
    end
  end

  # サンプルソース1では削除
  def icon_remove
    "<i class='glyphicon glyphicon-remove'></i>".html_safe
  end

  def icon_table
    "<i class='glyphicon glyphicon-th'></i>".html_safe # サンプルソース1では<span>タグに変更
  end

end
```

* 上記で紹介した**サンプルソース1**では``span_remove``と``icon_remove``を削除。
* ``icon_table``メソッドで追加しているHTMLタグを``<i>``から``<span>``へ変更。
* アイコンのクラス指定を``glyphicon-th``から``glyphicon-calendar``に変更

これは、[**Bootstrap 3 Datepicker v4 Docs**][link-1]にあるサンプルソースに合わせるためです。

また、``/app/inputs/``配下に``date_time_picker_input.rb``を作成していますが、**サンプルソース1**では、``/config/inilinitializers/``配下に作成しています。 初期設定で行うべき処理に思うので``/config/inilinitializers/``に移動しました。


#coffee scriptサンプル


**24時間表記で日本にロケールを合わせる場合は下記のようにします。**

```coffee
init_datetimepciker = ->
  (->
    $(".form_datetime").datetimepicker
      locale: "ja"
      format: "YYYY/MM/DD HH:mm"
      sideBySide: true
  )

$(document).ready ->
  init_datetimepciker()

$(document).on "ready page:load", init_datetimepciker()
```

* ``sideBySide: true``を指定するのは見た目が私はこちらのほうが好きなので、指定しています。
ポップアップのカレンダーの見た目が変わるだけです。

* ``turbolinks``を使用していると、ページ遷移時に``coffee script``が動作しない（リロードすれば動作する状態）なので``"ready page:load"``時も実行するよう設定しています。

* ``$(".form_datetime")``で要素を選択しています。``class``に``form_datetime``が指定されている要素全てが対象になるので、``css``の方で重ならないよう注意してください。``class``名変更などカスタマイズしたい場合は``/config/inilinitializers/date_time_picker_input.rb``（rubyコード）と合わせて調整する必要があります。

---


参考サイトの[**simple_form Wiki - Custom inputs examples**][link-2]では、下記のようになっています。


```coffee
$(document).ready ->
  $('.form_datetime').datetimepicker({
    autoclose: true,
    todayBtn: true,
    pickerPosition: "bottom-left",
    format: 'mm-dd-yyyy hh:ii'
  });
```


#view側の呼び出し

```rb
f.input :my_date, as: :date_time_picker
```


#参考URL

[**Bootstrap 3 Datepicker v4 Docs**][link-1]

[**simple_form Wiki - Custom inputs examples**][link-2]

[link-1]:http://eonasdan.github.io/bootstrap-datetimepicker/
[link-2]:https://github.com/plataformatec/simple_form/wiki/Custom-inputs-examples


#まとめ（忙しい人のためのやること一覧）

**1. Install**

```rb:Gemfile
gem 'momentjs-rails', '>= 2.9.0'
gem 'bootstrap3-datetimepicker-rails', '~> 4.14.30'
```
を追加します。

追記したあと、``bundle install``

---

**2. ``DateTimePickerInput``クラス追加**

```rb:/config/inilinitializers/date_time_picker_input.rb
class DateTimePickerInput < SimpleForm::Inputs::Base
  def input
    template.content_tag(:div, class: 'input-group date form_datetime') do
      template.concat @builder.text_field(attribute_name, input_html_options)
      template.concat span_table
    end
  end

  def input_html_options
    # classには配列で複数の設定が入ってくるので、それに'form-control'を追加してあげる
    # 単純にmergeしてしまうと、前のものが消えて'form-control'のみになってしまいバグる
    classes = (super[:class] || [])
    classes << :'form-control'
    # viewで指定された'readonly'がある場合は上書きしないようにする
    # カレンダーからの入力のみを許可したい場合は readonly: true を設定
    options = super
    options.merge({class: classes})
    options.merge({readonly: false}) unless options[:readonly]
    options
  end


  def span_table
    template.content_tag(:span, class: 'input-group-addon') do
      template.concat icon_table
    end
  end

  def icon_table
    "<span class='glyphicon glyphicon-calendar'></span>".html_safe
  end

end
```
を追加。

---

**3. coffeeスクリプトを追加**

```coffee
init_datetimepciker = ->
  (->
    $(".form_datetime").datetimepicker
      locale: "ja"
      format: "YYYY/MM/DD HH:mm"
      sideBySide: true
  )

$(document).ready ->
  init_datetimepciker()

$(document).on "ready page:load", init_datetimepciker()
```
を追加。

---
**※補足**
``javascript``で指定したい場合は``coffee script``と``javascript``の相互変換は下記サイトでできます。
http://js2coffee.thomaskalka.de/

---

**4. ``view``側の呼び出し**

``as: :date_time_picker``を指定して呼び出し。

```rb
f.input :my_date, as: :date_time_picker
```