Rails4で2つの日時情報を開始日時
と終了日時
という範囲指定をおこなうように実装した時の備忘録です。
bootstrap-datetimepicker-railsのインストール
日時を指定するためのカレンダーをbootstrap3で実装しようと思い、調べたらTrevorS/bootstrap3-datetimepicker-rails というgemライブラリが存在しました。
Gemライブラリのインストール
TrevorS/bootstrap3-datetimepicker-rails をインストールします。
Gemfile 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# jQuery plugin for drop-in fix binded events problem caused by Turbolinks
gem 'jquery-turbolinks'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer' , platforms : :ruby
# Install Twitter Bootstrap3
# https://github.com/twbs/bootstrap-sass
gem 'bootstrap-sass' , '~> 3.2.0'
# -webkit-border-radius みたいなブラウザベンダープレフィックスをよしなに管理してくれる
# Parse CSS and add vendor prefixes to rules by Can I Use
# https://twitter.com/autoprefixer
gem 'autoprefixer-rails'
# Istall of bootstrap3-datetimepicker-rails
# See https://github.com/TrevorS/bootstrap3-datetimepicker-rails
gem 'momentjs-rails' , '>= 2.8.1'
gem 'bootstrap3-datetimepicker-rails' , '~> 3.1.3'
ライブラリをインストールします。
javascriptライブラリのinclude
app/assets/javascripts/application.js
に以下を追記します。
app/assets/javascripts/application.js 1
2
3
4
5
6
7
8
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require bootstrap-sprockets
//= require moment
//= require bootstrap-datetimepicker
//= require turbolinks
//= require_tree .
スタイルシートの読み込み
app/assets/stylesheets/application.css.scss
に以下を追記します。
app/assets/stylesheets/application.css.scss 1
2
3
@import "bootstrap-sprockets" ;
@import "bootstrap" ;
@import ' bootstrap-datetimepicker' ;
2つの期間を指定するdatetimepickerを実装
Entryリソースの生成
今回は2つの期間を指定したエントリを保存するためのEntryリソースをscaffoldで生成します。
開始日時をdatetime型
のstart_at
アトリビュート、終了日時をdatetime型
のend_at
アトリビュートとして定義しています。
1
2
3
4
5
6
7
8
9
bundle exec rails g scaffold Entry name:string start_at:datetime end_at:datetime description:string
bundle exec rake db:migrate
cat << EOT > config/routes.rb
Rails.application.routes.draw do
root 'entries#index'
resources :entries
end
EOT
javascriptの記述
http://eonasdan.github.io/bootstrap-datetimepicker/#example9 を参考にしました。
app/views/entries/_form.html.erb 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
< script type = "text/javascript" >
$ ( function (){
// bootstrap-datetimepicker-rails configurations
// - references
// 1. http://eonasdan.github.io/bootstrap-datetimepicker/#options
// 2. http://shibuso.github.io/datetimepicker_test/datetimepicker_02.html
// .datepicker_start へのdatetimepicker設定
$ ( '.datepicker_start' ). datetimepicker ({
// カレンダー表示言語
// bootstrap-datetimepicker.ja.js が必要
//language: 'ja',
// 月日ピッカーと時間ピッカーを隣に表示する
//sideBySide: true,
// 日時フォーマット
format : 'YYYY-MM-DD HH:mm' ,
// 分の選択可能間隔
minuteStepping : 5 ,
});
// .datepicker_end へのdatetimepicker設定
$ ( '.datepicker_end' ). datetimepicker ({
// カレンダー表示言語
// bootstrap-datetimepicker.ja.js が必要
//language: 'ja',
// 月日ピッカーと時間ピッカーを隣に表示する
//sideBySide: true,
// 日時フォーマット
format : 'YYYY-MM-DD HH:mm' ,
// 分の選択可能間隔
minuteStepping : 5 ,
});
// set a minimum date of start_at
$ ( '.datepicker_start' ). on ( "dp.change" , function ( e ) {
$ ( '.datepicker_end' ). data ( "DateTimePicker" ). setMinDate ( e . date );
});
// set a maximum date of end_at
$ ( '.datepicker_end' ). on ( "dp.change" , function ( e ) {
$ ( '.datepicker_start' ). data ( "DateTimePicker" ). setMaxDate ( e . date );
});
});
< /script>
viewの記述(ERB)
app/views/entries/_form.html.erb 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<%= form_for ( @entry ) do | f | %>
<% if @entry . errors . any? %>
<div id="error_explanation">
<h2> <%= pluralize ( @entry . errors . count , "error" ) %> prohibited this entry from being saved:</h2>
<ul>
<% @entry . errors . full_messages . each do | message | %>
<li> <%= message %> </li>
<% end %>
</ul>
</div>
<% end %>
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :name , '名前' %> <br>
<%= f . text_field :name , :class => 'form-control' , :placeholder => "エントリーの名前を入力してください..." %>
</div>
</div>
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :start_at , '開始日時' %> <br>
<div class='input-group datepicker_start'>
<%= f . text_field :start_at , :class => 'form-control' , :readonly => 'true' , :placeholder => "開始日時を選択してください..." %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :end_at , '終了日時' %> <br>
<div class='input-group datepicker_end'>
<%= f . text_field :end_at , :class => 'form-control' , :readonly => 'true' , :placeholder => "終了日時を選択してください..." %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :description , '説明' %> <br>
<%= f . text_field :description , :class => 'form-control' , :placeholder => "エントリーの説明を入力してください..." %>
</div>
</div>
<div class="col-sm-8 col-md-8">
<div class="actions">
<%= f . submit 'エントリーを作成' , :class => 'btn btn-primary' %>
</div>
</div>
<% end %>
参考にさせて頂いた情報
http://qiita.com/kidachi_/items/9f76a27890d96b9f5838
http://www.workabroad.jp/posts/974
http://eonasdan.github.io/bootstrap-datetimepicker/#example9
エントリー期間内に複数のイベントを定義できるように実装する
定義したエントリーの中には複数のイベントを持つことができるようにEventリソースを生成します。イベントは食事
などのカテゴリーを持つようにしたいのでCategoryリソースを先に生成します。
イベントに付けるカテゴリーのリストを生成する
1
bundle exec rails g scaffold category name:string icon_name:string
イベント用のEventリソースを生成する
1
bundle exec rails g scaffold event entry:references name:string start_at:datetime end_at:datetime description:string category:references
1
bundle exec rake db:migrate
モデルのアソシエーションを記述する
app/models/entry.rb 1
2
3
class Entry < ActiveRecord :: Base
has_many :events
end
app/models/event.rb 1
2
3
4
class Event < ActiveRecord :: Base
belongs_to :entry
belongs_to :category
end
app/models/category.rb 1
2
3
class Category < ActiveRecord :: Base
has_many :events
end
エントリーの編集ページにイベント作成ページへのリンクを設置
イベントは特定のエントリーに属するのでエントリーの編集画面から追加できるようにします。
1
<%= link_to " #{ @entry . name } にイベントを追加" , "/events/ #{ @entry . id } /new" %>
リンクURLがRESTFulなルーティングリソースではないのでconfig/routes.rb
にルーティングを追記します。
config/routes.rb 1
2
resources :events
get 'events/:entry_id/new' => 'events#new'
イベント作成ページの`Entry_id`のテキストフィールドにエントリーIDを表示
app/controllers/events_controller.rb 1
2
3
4
5
# GET /events/:entry_id/new
def new
entry_id = params . require ( :entry_id )
@event = Event . new ( :entry_id => entry_id )
end
app/views/events/_form.html.erb 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<script type="text/javascript">
$(function(){
// bootstrap-datetimepicker-rails configurations
// - references
// 1. http://eonasdan.github.io/bootstrap-datetimepicker/#options
// 2. http://shibuso.github.io/datetimepicker_test/datetimepicker_02.html
var start_at = new Date( <%= DateTime . parse ( @entry . start_at . to_s ) . utc . to_i * 1000 %> );
var end_at = new Date( <%= DateTime . parse ( @entry . end_at . to_s ) . utc . to_i * 1000 %> );
// define datepicker of start_at
$('.datepicker_start').datetimepicker({
// カレンダー表示言語
// bootstrap-datetimepicker.ja.js が必要
//language: 'ja',
// 月日ピッカーと時間ピッカーを隣に表示する
//sideBySide: true,
// 日時フォーマット
format: 'YYYY-MM-DD HH:mm',
// 分の選択可能間隔
minuteStepping: 5,
// 選択可能な最小日
minDate: start_at,
// 選択可能な最大日
maxDate: end_at,
});
// define datepicker of end_at
$('.datepicker_end').datetimepicker({
// カレンダー表示言語
// bootstrap-datetimepicker.ja.js が必要
//language: 'ja',
// 月日ピッカーと時間ピッカーを隣に表示する
//sideBySide: true,
// 日時フォーマット
format: 'YYYY-MM-DD HH:mm',
// 分の選択可能間隔
minuteStepping: 5,
// 選択可能な最小日
minDate: start_at,
// 選択可能な最大日
maxDate: end_at,
});
});
</script>
iv class="field">
|f| %>
<% if @event . errors . any? %>
<div id="error_explanation">
<h2> <%= pluralize ( @event . errors . count , "error" ) %> prohibited this event from being saved:</h2>
<ul>
<% @event . errors . full_messages . each do | message | %>
<li> <%= message %> </li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f . label :entry_id %> <br>
<%= f . text_field :entry_id , :readonly => true %>
</div>
<div class="field">
<%= f . label :name %> <br>
<%= f . text_field :name %>
</div>
<!-- 開始日時カレンダー -->
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :start_at , '開始日時' %> <br>
<div class='input-group datepicker_start'>
<%= f . text_field :start_at ,
:value => @entry . start_at ,
:class => 'form-control' ,
:readonly => 'true' ,
:placeholder => "開始日時を選択してください..." %>
<!-- glyphicon -->
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div><!-- /.input-group datepicker_start -->
</div><!-- /.form-group -->
</div><!-- /.col-sm .col-md -->
<!-- 終了日時カレンダー -->
<div class="col-sm-8 col-md-8">
<div class="form-group">
<%= f . label :end_at , '終了日時' %> <br>
<div class='input-group datepicker_end'>
<%= f . text_field :end_at ,
:value => @entry . end_at ,
:class => 'form-control' ,
:readonly => 'true' ,
:placeholder => "終了日時を選択してください..." %>
<!-- glyphicon -->
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div><!-- /.input-group datepicker_start -->
</div><!-- /.form-group -->
</div><!-- /.col-sm .col-md -->
<div class="field">
<%= f . label :description %> <br>
<%= f . text_field :description %>
</div>
<div class="actions">
<%= f . submit %>
</div>
<% end %>
<%= f.label :entry_id %><br>
<%= f.text_field :entry_id, :readonly => true %>
“`