このエントリーをはてなブックマークに追加
ラベル はじめの一歩 の投稿を表示しています。 すべての投稿を表示
ラベル はじめの一歩 の投稿を表示しています。 すべての投稿を表示

2017年2月9日木曜日

はじめの一歩 -Rails ActiveRecord編- UPDATE2


どうも、はじめです。
前回はUPDATEについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- UPDATE
今回はUPDATEの際readonlyやvalidationで更新ができなかった場合に関して書いていこうと思います。


はじめに


今回も前回と同じテーブルを使用しようと思います。
usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']

itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']

user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]

関連性
user : user_item => 1 : n
item : user_item => 1 : n


ではまず【readonly】で更新できなかった場合の対処法を書いてみます。

readonly


下のように更新をしてみます。
[id: 2, user_id: 1, item_id: 2]
↓
[id: 2, user_id: 1, item_id: 3]
手元でなかなかreadonlyになる状況を再現できなかったため
以下の方法でreadonlyにしました。
user_item = UserItem.readonly(true)

この状態で変更しようとしても更新できません。
user_item.find(2).update(item_id: 3)
# ActiveRecord::ReadOnlyRecord: UserItem is marked as readonly

これだとreadonlyでrollbackされてしまいます。

モデルからインスタンスを取得する際にreadonlyをfalseにしてあげれば更新が可能になります。
user_item = UserItem.readonly(false)
user_item.find(2).update(item_id: 3)


次に【validation】でエラーになった場合です。

validation


ユーザーの登録の際、user_nameを入力必須にしていたとします。
入力必須のバリデーションを定義するにはUserモデルに対し以下のように定義します。

# app/models/user.rb
class User < ApplicationRecord
 validates :user_name, presence: true
end

この状態でユーザー名を空で登録しようとするとエラーになります。
user = User.new
user.save

次のように記述することで一時的にバリデーションを無効にすることができます。
user = User.new
user.save(:validate => false)


最後に


validationを一時的に無効にすることは可能ですが、
今回例としてあげたのケースの場合、
DBでuser_nameにnot null制約がかかっているとバリデーションを無視することができても、
DBへの登録時にエラーになってしまいますので気をつけましょう。

次回はupdate_attributeとupdate_attributesを使ってみようと思います。

2017年2月2日木曜日

はじめの一歩 -Rails ActiveRecord編- UPDATE


どうも、はじめです。
前回はJOINについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT4
今回はUPDATEに関して書いていこうと思います。


はじめに


今回も前回と同じテーブルを使用しようと思います。
usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']

itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']

user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]

関連性
user : user_item => 1 : n
item : user_item => 1 : n


UPDATEを行うには主に以下の二つの方法があります。
・saveメソッドを使用する。
・updateメソッドを使用する。

でははじめに【saveメソッド】を使用した方法から書いていきます。


save


user_itemsを以下のように変更したいと思います。
[id: 3, user_id: 2, item_id: 3]
↓
[id: 3, user_id: 3, item_id: 3]

1.変更したいモデルインスタンスを取得
user_item = UserItem.find(3)

2.変更したい値を代入
user_item.user_id = 3

3.代入が完了したら登録
user_item.save

以上の手順でupdateが完了します。
2で複数のカラムを変更することも可能です。


次に【updateメソッド】を使用した方法を書いてみます。

update


updateでも同様にuser_itemsを以下のように変更したいと思います。
[id: 3, user_id: 2, item_id: 3]
↓
[id: 3, user_id: 3, item_id: 3]

updateメソッドを使用する際も2つの方法があります。
一つはsaveメソッドと同じように変更したいモデルインスタンスを取得し、
updateという流れになります。

user_item = UserItem.find(3)
user_item.update(user_id: 3)

もう一つは一度変数にインスタンスを取得するという工程を飛ばす方法です。

UserItem.find(3).update(user_id: 3)

どれも結果は同じになります。


まとめ


updateをする際変更したいレコードがreadonlyになっていた場合や、
validation等の関係で更新が失敗する場合があります。
その場合の対処法等を次回書いてみようと思います。

2017年1月26日木曜日

はじめの一歩 -Rails ActiveRecord編- SELECT4


どうも、はじめです。
前回はJOINについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT3
今回も引き続きJOINに関する内容ですが、JOINでも3つ以上のテーブルの結合について書いていこうと思います。


はじめに


3つ以上のテーブルの結合なので、結合できるテーブルを3つ用意します。

usersテーブル
[id: 1, user_name: 'Aさん'],
[id: 2, user_name: 'Bさん'],
[Id: 3, user_name: 'Cさん']

itemsテーブル
[id: 1, item_name: 'Rubyの本'],
[id: 2, item_name: 'Railsの本'],
[id: 3, item_name: 'PHPの本']

user_itemsテーブル(userが持っているitemを管理するテーブル)
[id: 1, user_id: 1, item_id: 1],
[id: 2, user_id: 1, item_id: 2],
[id: 3, user_id: 2, item_id: 3]

関連を説明すると以下のようになります。
user : user_item => 1 : n
item : user_item => 1 : n

それでは前回使用したincludesを使用して書いていこうと思います。


取得


・Aさんが持っているアイテムを全て取得したい場合
user_items = User.includes(user_items: :item).find(1)

上記のように記述することで以下のようなSQLが実行されます。
SELECT `users`.* FROM `users` WHERE `users`.`id` = 1;
SELECT `user_items`.* FROM `user_items` WHERE `user_items`.`id` in (1,2);
SELECT `items`.* FROM `items` WHERE `items`.`id` in (1,2);

joinsの場合も同様の書き方となります。


表示


アイテム名を表示したい場合は以下のようにします。
user_items.user_items.each do |user_item|
  p user_item.item.item_name
end
# => 'Rubyの本'
# => 'Railsの本'


さらにテーブルが増えた場合


itemsにcategoryテーブルを関連付けして色々なパターンで取得をしてみたいと思います。
以下のような関連性でitemsに対し、categoriesテーブルを作成します。
items : category => n : 1

itemsテーブル
[id: 1, item_name: 'Rubyの本', category_id: 1],
[id: 2, item_name: 'Railsの本', category_id: 1],
[id: 3, item_name: 'PHPの本', category_id: 2]

categoriesテーブル
[id: 1, category_name: 'Ruby'],
[id: 2, category_name: 'PHP']

パターン1
・Aさんが持っているアイテムのカテゴリーまで取得したい場合
User.includes(user_items: {item: :category}).find(1)

パターン2
・"Rubyの本"のカテゴリーと持っているユーザーを取得したい場合
Item.includes(:category, {user_items: :user}).find(1)


まとめ


以下のような関連性だった場合
a:b:c => 1:n:1
c:d =>n:1

隣接しているテーブルを複数結合したい場合はのように「,」でつなげることができます。
B.includes(:a, :c)
二つ隣のテーブルの情報を取得する場合は「:」を向かい合わせに記述をします。
A.includes(b: :c)
さらに深いテーブルの情報を取得する場合は{}を使用します
A.includes(b: {c: :d})

前回も記述をしたように
3つ以上のテーブルを結合する場合でもテーブル名は
複数系、単数系を意識しなければいけませんので注意してください。

以上でSELECT系(JOIN系)を終了し、
次回からはUPDATEに入ろうと思います。

2017年1月19日木曜日

はじめの一歩 -Rails ActiveRecord編- SELECT3


どうも、はじめです。
前回はActiveRecordのSELECTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT2
今回はActiveRecordのデータの取得(SELECT)の中でもJOIN系に関して書いていこうと思います。


はじめに


booksテーブルに以下のデータが登録済みであることを前提とします。
[id: 1, title: ‘Rubyの本’, publisher_id: 1],
[id: 2, title: ‘Railsの本’, publisher_id: 1],
[Id: 3, title: ‘PHPの本’, publisher_id: 2]

今回はJoin系のメソッドについて書いていくので、
booksに対し多対1で紐づくpublishersテーブルを以下のように用意します。
[id: 1, publisher_name: '出版社1'],
[id: 2, publisher_name: '出版社2']


joins


joinsはinner joinでの結合を行います。
Books.joins(:publisher)
# SELECT `books`.* FROM `books` INNER JOIN `publishers` ON `publishers`.`id` = `books`.`publisher_id`

出版社名を表示したい場合は以下のように表示をすることができます。
例としてbooksテーブルのID:1のレコードで取得してみます。
book = Book.joins(:publisher).find(1)
p book.publisher.publisher_name
# '出版社1'

※joinsを使用するとreadonlyとなるため更新ができないと
いろいろなところで目にしましたが、手元で確認をしたところreadonlyはfalseとなっていました。
ちなみにRailsのバージョンは5.0.0.1です。
バージョンによるものか環境によるものかはわかりませんが、
実際に使用する場合は一度確認をしてみるべきだと思います。

joinsを使用した状態でwhereを使用したい場合は以下のように書くことができます。
# Bookの情報で検索を行いたい場合
Book.joins(:publisher).where(title: ‘Railsの本’)

# Publisherの情報で検索を行いたい場合(以下の二つは同じ内容が実行されます)
Book.joins(:publisher).where(publishers: {publisher_name: '出版社1'})
Book.joins(:publisher).where("publishers.publisher_name = '出版社1'")
mergeを使用するとActiveRecord::Relationを使用して検索することもできます。
Book.joins(:publisher).merge(Publisher.where(publisher_name: '出版社1'))
※後で記述するincludesでは使用できませんでした。
使用できない理由はこの後書かせていただきます。


includes


includesは結合先のテーブルと結合元のテーブルに対し
別々にクエリを実行してデータを取得します。
Book.includes(:publisher)
# SELECT `books`.* FROM `books`
# SELECT `publishers`.* FROM `publishers` WHERE `publishers`.`id` IN (1, 2)

表示の仕方はjoinsと同じです。
book = Book.joins(:publisher).find(1)
p book.publisher.publisher_name
# '出版社1'

それぞれに対して別々にクエリを実行していることから、
指定したデータがBookに存在していない場合はPublisherに対するクエリは実行されません。
Book.joins(:publisher).find(4)
# SELECT `books`.* FROM `books` WHEHE `books`.`id` = 4

includesを使用した状態でwhereを使用したい場合は、
どのカラムで検索するかによって実行されるSQLの内容が変わってくるので注意が必要です。


実際に違いを見てみます。
検索条件のパターンとして以下の2つをあげます。
1.Book内の情報で検索をする
2.Publish内の情報で検索をする
実際に試してみます。

1.Book内の情報で検索をする
Book.includes(:publisher)where(title: ‘Railsの本’)
# SELECT `books`.* FROM `books` WHERE `books`.`title` = "Railsの本"
# SELECT `publishers`.* FROM `publishers` WHERE `publishers`.`id` = 1
こちらは条件指定をしない場合と変わりません。

2.Publish内の情報で検索をする
Book.includes(:publisher)where(publishers: {publisher_name: '出版社1'})
# SELECT `books`.`id, `books`.`title`, `books`.`publisher_id`, `publishers`.`id`, `publishers`.`publisher_name`
# FROM `books` LEFT OUTER JOIN `publishers` ON ``publishers`.`id` = `books`.`publisher_id`
# WHERE `publishers`.`publisher_name` = "出版社1"
このように結合先のテーブル情報で検索を行うと"LEFT OUTER JOIN"を使った結合が行われます。

includesでmergeを使用した場合以下のようなSQLが実行されます。
Book.includes(:publisher).merge(Publisher.where(publisher_name: '出版社1'))
# SELECT `books`.* FROM `books` WHERE `publishers`.`publisher_name` = "出版社1"
クエリが各テーブル毎に発行されているためこのようなクエリが生成されるのだと思います。


最後に


今回のJOIN系に関して個人的に大変だと思ったのはテーブル名の記述です。
joinsやincludesで指定するテーブル名ですが、
自分から見て結合するテーブルがどのような関連性を持っているかによって
記述するテーブル名が変わってきます。

・自分から見て結合先のテーブルが一つしか存在しない場合(Bookから見たPublishのような関係)
単数系のテーブル名で指定する。
・自分から見て結合するテーブルのデータが複数存在する場合(Publishから見たBookのような関係)
複数形のテーブル名で指定する。

また、結合先のテーブル情報でwhereを使用する場合は
複数形のテーブル名で指定をします。

今回書ききれなかったこともあるので、次回もJOIN系の続きを書きます。

2017年1月10日火曜日

はじめの一歩 -Rails ActiveRecord編- SELECT2


どうも、はじめです。

前回はActiveRecordのSELECTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- SELECT
今回も引き続きActiveRecordのデータの取得(SELECT)に関して書いていこうと思います。


はじめに、


前回と同様に以下のデータが登録済みであることを前提とします。
[id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
[id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
[Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]

前回記述したallやwhereを使用してデータの取得をした場合、
ActiveRecord::Relationというクラスのオブジェクトが返却されます。
取得したレコードが1件だけであったとしても使用する際は以下のように記述する必要があります。
user = User.where(id: 1)
p user[0][:name]
# => '名前1'
上記のように1件のみの取得と確定している場合でも[0]をつけなくてはなりません。
今回は1件のみを取得する方法を書いていきたいと思います。


find


findはIDの直指定でレコードを取得することができます。
実行文と実行結果は以下のようになります。
user = User.find(2)
p user.mail
# => ‘222@xxx.xxx’
findでもし存在しないIDを指定した場合は例外が発生します。

ちなみにIDの複数指定も可能です。
複数のIDを指定する際は以下のように配列で複数のIDを指定します。
user = User.find([2,3])
p user[0][:name]
# => '名前2'
p user[1][:name]
# => '名前3'
こちらは以下のようにwhereで取得した場合と同じ結果になります。
user = User.where(id: [2,3])


find_by


findの場合はIDしか指定できませんでしたが、
他のカラムでの検索で1件のみ取得したい場合はfind_byを使用します。
user = User.find_by(name: '名前1', mail: ‘111@xxx.xxx’)
p user.id
# => 1
find_byでの検索はSQLの末尾に[limit 1]を追加して検索をしてくれるので、
検索結果が複数あった場合でもヒットした中の一番最初のレコード1件のみを取得してくれます。
上記のように複数条件を指定することもできますが、すべてAND条件での検索となります。

find_byでIDを指定することもできますが、
findとの違いとしましては、検索結果が0件だった場合に例外ではなくnilを返します。


first


firstはを実行した場合は[order by `id` asc limit 1]が実行されます。
引数で数値を渡してlimitの数を指定することもできます。
user = User.first
user.id
# => 1
user = User.first(2)
user[1][:name]
# => '名前2'


最後に、


今後もしばらくデータの取得に関して書いていこうと思っております。
次回はjoin系を書いてみようと思っております。

2017年1月7日土曜日

はじめの一歩 -Rails ActiveRecord編- SELECT


どうも、はじめです。

あけましておめでとうございます。
今年もよろしくお願いいたします。

さて前回はActiveRecordのINSERTについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- INSERT
今回はActiveRecordのデータの更新(update)について書こうと思っていましたが、
先にデータの取得(select)について書いてみようと思います。


データの取得をしたい場合


モデルに登録されているすべてのデータを取得したい場合はallを、
検索をしたい場合はwhereを使用します。

Userモデルに以下でデータを登録したとします。
[id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
[id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
[Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]

all
User.all
# [Id: 1, name: ‘名前1’, mail: ‘111@xxx.xxx’],
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
# [Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]

where
User.where(id: 2)
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’]
allの場合は指定したモデルに登録されているデータをすべて取得することができます。
whereの場合はwhere()内に「カラム名: 検索したい値」を指定することで、
指定した値で検索した結果を取得することができます。


複数条件で検索をしたい場合


複数の条件でデータの取得を行いたい場合はwhereにて条件を複数指定します。
Idが2と3のレコードを取得したい場合は以下のようにidに対し配列で条件を指定します。

User.where(id: [2, 3])
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’],
# [Id: 3, name: ‘名前3’, mail: ‘333@xxx.xxx’]

複数カラムを指定したい場合は以下のように指定します。
User.where(id: 2, name: ‘名前2’)
# [Id: 2, name: ‘名前2’, mail: ‘222@xxx.xxx’]
このように指定した場合はAND条件で検索されるので注意が必要です。


最後に、


OR条件での検索や、AND条件でも他の記述方法があったりと
他にもデータの抽出には種類があるため、
次回も引き続きSELECT関連を書いていこうと思います。

2016年12月29日木曜日

はじめの一歩 -Rails ActiveRecord編- INSERT


どうも、はじめです。

前回はActiveRecordについて書いてみました。
はじめの一歩 -Rails ActiveRecord編- 序章
今回はActiveRecordのデータの保存(create,new)について
描いてみようと思います。


データを保存したい場合


ActiveRecordにてDBにデータを保存する場合は
createまたは、newを使用します。
それぞれの記述方法は以下のようになります。

create
User.create(name: '山田', mail: 'xxx@xxx.xxx')
new
user = User.new(name: '山田', mail: 'xxx@xxx.xxx')
user.save()

#  または
user = User.new()
user.name = '山田'
user.mail = 'xxx@xxx.xxx'
user.save()
上記のように記述することでusersテーブルに対し、
name: 山田
mail: xxx@xxx.xxx
というレコードがinsertされます。


例外を発生させたい場合


create,new共に「!」をつけるだけでinsertに失敗した際に例外を発生させてくれます。

create

User.create!(...)

new

user = User.new(...)
・
・
user.save!


createとnewの違い


違いとしてあげられるものはDBにinsertをするタイミングです。
それぞれ以下のタイミングでDBへinsertされます。
create -> createメソッドの実行時
new -> saveメソッドの実行時

ちなみに、
以下のようにsaveメソッドを複数回記述しても
insertされるのは最初の一度のみとなります。
user = User.new(...)
・
・
user.save # ←ここでのみinsertされる
user.save # 何もinsertされない
user.save # 何もinsertされない
試してみたところ2回目以降のinsertは何もinsertされませんが、
返り値はtrueが返却されました。


最後に


createを実行した際は裏でnewとsaveを順番に行なっているだけなので、
結果やっていることは変わりません。
なので、インスタンスを生成するタイミングで登録に必要な値が全て揃っている場合はcreate。
それ以外の場合。
例として、
・任意のタイミングでsaveしたい。
・インスタンスの生成後に何かの処理をしたい。
・特定の条件でのみ登録するカラムが存在する。
等の理由がある場合はnewを使用するといった形になるのではないかと思いました。


次回


次回は更新(update)について書いていきたいと思います。

2016年12月25日日曜日

はじめの一歩 -Rails ActiveRecord編- 序章


どうも、はじめです。

前回はおまけとしてapplication.rbでのタイムゾーンの設定の仕方を紹介しました 。
「はじめの一歩 -Rails 時間・タイムゾーン編- おまけ」
今回から「ActiveRecord編」に入っていこうと思います。


ActiveRecordとは


「Ruby on Rails」にて用意されているORMになります。
AcriveRecordを使用することでSQLを記述しなくても
わずかなアクセスコードでBDへのデータの保存や取得を行うことができます。


AcriveRecordのルール


AcriveRecordを使用する上でのルールとして以下の命名規則があります。
・モデル名、クラス名には単数形のキャメルケース(語頭を大文字)を使用する
・テーブル名、カラム名には複数形で語の区切り文字として「_(アンダーバー)」を使用する。
・テーブルの外部キーは「テーブルの単数形_id」とする。
・主キーには「id」を使用する。

例としてユーザーテーブルとユーザー投稿テーブルを使用する際には以下のようになります。
usersテーブル           -> Userモデル
user_postsテーブル -> UserPostモデル
という形でテーブル名、モデル名が決まります。

両テーブルの主キーは「id」
user_postsテーブルが持つ外部キーは「user_id」となります。

他にも幾つか用意されているカラム名が存在しています。
 ・created_at - レコード作成時の日時が自動的に登録されます。
 ・updated_at - レコードが更新された時の日時が自動的に登録されます。
 ・lock_version - モデルにoptimistic lockingを追加します。
 ・type - モデルでSingle Table Inheritanceを使用する場合に指定します
 ・関連付け名_type - ポリモーフィック関連付けの種類を保持します。
 ・テーブル名_count - 関連付けにおいて、所属しているオブジェクトの数をキャッシュするのに使用されます。


ActiveRecordのモデルを作成


例としてUserモデルの作成を行います。
# app/models/user.rb
class User < ActiveRecord::Base
end

AcriveRecordの命名規則に反した名前になってしまった場合
以下のようにオーバーライドすることも可能です。
# app/models/user.rb
class User < ActiveRecord::Base
    self.table_name = ‘USER’
end
主キーとなるカラム名が「id」以外の場合は以下のように指定をすることも可能です。
# app/models/user.rb
class User < ActiveRecord::Base
    self.primary_key = ‘user_id'
end

このようにテーブルに対して紐づくモデルの作成が完了すれば
テーブルからのデータの呼び出し、登録等の操作が可能になります。


次回


モデルの作成が完了したので、次回は登録系について書いていこうと思います。

2016年12月23日金曜日

はじめの一歩 -Rails 時間・タイムゾーン編- おまけ

どうも、はじめです。

前回は月や年の最初や最後の取得をやってみました。
「はじめの一歩 -Rails 時間・タイムゾーン編- その5」
今回はapplication.rbでのタイムゾーンの設定方法を紹介したいと思います。

はじめに

application.rbでタイムゾーンを指定をしなかった場合はデフォルトでUTCが指定されます。
任意のタイムゾーンを設定するには以下のように指定をします。
# config/application.rb
config.time_zone = 'Tokyo'
ここで指定している’Tokyo’という文字列ですが何でも良いという訳ではありません。 RailsのActiveSupportにて予め用意されているものの中から任意の文字列を指定する事により、
該当するタイムゾーンを指定してくれるようになっています。

それではActiveSupportが用意している文字列を幾つか紹介したいと思います。

Asia/Tokyo

このタイムゾーンを指定したい場合は以下のように指定をします。
config.time_zone = 'Tokyo'
他にも’Osaka’や’Sapporo'と指定しても同様に”Asia/Tokyo”のタイムゾーンが指定されます。

America/New_York

アメリカのニューヨークのタイムゾーンを指定したい場合はこのように指定をします。
config.time_zone = 'Eastern Time (US & Canada)'

Asia/Seoul

こちらは韓国のソウルのタイムゾーンです。
config.time_zone = 'Seoul'

Asia/Taipei

こちらは中国の台北のタイムゾーンです。
config.time_zone = 'Taipei'

ちなみに、
Tokyoのように同じタイムゾーンを示す文字列が複数存在するものは他にもあります。

Pacific/Midway

こちらはアメリカのミッドウェイ島というところで、国際日付変更線も表しています。
以下の文字列で指定が可能です。
config.time_zone = 'International Date Line West'
config.time_zone = 'Midway Island'

America/Mexico_City

こちらはアメリカのメキシコのタイムゾーンです。
以下の文字列で指定が可能です。
config.time_zone = 'Guadalajara'
config.time_zone = 'Mexico City'

Europe/London

こちらはロンドンのタイムゾーンで、以下の文字列での指定が可能です。
config.time_zone = 'Edinburgh'
config.time_zone = 'London'

他にも幾つかあるので興味のある方は調べてみて下さい。

最後に、

ここで紹介した'Asia/Taipei’や'America/New_York’は
「はじめの一歩 -Rails 時間・タイムゾーン編- その4」
で紹介した、任意のタイムゾーンに変換して表示をする
time.in_time_zone('America/Chicago')
でも使用することができます。

次回

次は「時間・タイムゾーン編」のまとめをやりたいと思います。

2016年12月18日日曜日

はじめの一歩 -Rails 時間・タイムゾーン編- その5

どうも、はじめです。

前回は幾つかのタイムゾーンの紹介と、任意のタイムゾーンでの日時の取得について書いてみました。
「はじめの一歩 -Rails 時間・タイムゾーン編- その4」
今回は月や週などの最初と最後を取得する方法を書いていきます。

はじめに、

前提として今回はTimeWithZoneクラスを使用して、
タイムゾーンはJSTでの実行例を載せていきます。

それでは、年月週などそれぞれの最初と最後を取得する方法を書いていきます。

Time.zone.now.beginning_of_year
# => Fri, 01 Jan 2016 00:00:00 JST +09:00
Time.zone.now.end_of_year
=> Sat, 31 Dec 2016 23:59:59 JST +09:00

Time.zone.now.beginning_of_month
# => Thu, 01 Dec 2016 00:00:00 JST +09:00
Time.zone.now.end_of_month
# => Sat, 31 Dec 2016 23:59:59 JST +09:00

Time.zone.now.beginning_of_week
# => Mon, 12 Dec 2016 00:00:00 JST +09:00
Time.zone.now.end_of_week
# => Sun, 18 Dec 2016 23:59:59 JST +09:00
週の最初は月曜日、最後は日曜日と言うかたちで取得されます。

Time.zone.now.beginning_of_day
# => Sun, 18 Dec 2016 00:00:00 JST +09:00
Time.zone.now.end_of_day
# => Sun, 18 Dec 2016 23:59:59 JST +09:00
ちなみに、
Time.zone.now.beginning_of_day
は以下のようにも書くことができます。
Time.zone.now.midnight
# => Sun, 18 Dec 2016 00:00:00 JST +09:00

現在時刻を14時代だとした場合、
以下のように14時の0分0秒、59分59秒を取得してくれます。
Time.zone.now.beginning_of_hour
# => Sun, 18 Dec 2016 14:00:00 JST +09:00
Time.zone.now.end_of_hour
# => Sun, 18 Dec 2016 14:59:59 JST +09:00

時と同様に現在時刻を14時27分とした場合、
以下のように取得できます。
Time.zone.now.beginning_of_minute
# => Sun, 18 Dec 2016 14:27:00 JST +09:00
Time.zone.now.end_of_minute
# => Sun, 18 Dec 2016 14:27:59 JST +09:00

ちなみに、
以下のように書くことで、任意の曜日の最初を取得することもできます。
Time.zone.now.beginning_of_week(:tuesday)
# => Tue, 13 Dec 2016 00:00:00 JST +09:00
end_of_weekに曜日を指定すると以下のようになります。
Time.zone.now.end_of_week(:tuesday)
# => Mon, 19 Dec 2016 23:59:59 JST +09:00
来週の指定した曜日の最後ではなく、
その日の前日の最後を取得するようなので注意が必要です。


最後に、

曜日を表示する際は日曜日を0として取得をしますが、
beginning_of_weekやend_of_weekで取得する日時は
日曜日ではなく月曜日を最初として取得するので意外でした。
end_of_weekで曜日を指定した場合も含め週を扱う際は、
一度確認をしてから使用すると良いと思います。

次回

次はおまけでapplication.rbにて
タイムゾーンを設定する方法を書きたいと思います。

2016年12月15日木曜日

はじめの一歩 -Rails 時間・タイムゾーン編- その4

どうも、はじめです。

前回はさまざまな日時の取得方法について書いてみました。
「はじめの一歩 -Rails 時間・タイムゾーン編- その3」
今回はいくつかのタイムゾーンの紹介や
任意のタイムゾーンでの出力方法について書いてみます。

はじめに、

タイムゾーンの基準となる「UTC(協定世界時)」というものがあり、
タイムゾーンを表示した際に表示される「+0900」とは、
この「UTC」からの時差になります。

それではいくつかタイムゾーンを紹介していきます。

UTC (+0000)

こちらは先程も書いたとおり「協定世界時」と言って
世界の時間の基準となるものです。
スペインやポルトガルの時間を表示したい際にも用いられるそうです。
また、タイムゾーンを指定しなかった場合に
デフォルトで指定されているのも「UTC」になります。

JTC (+0900)

こちらは日本のタイムゾーンになります。
または、Asia/Tokyoと指定する事もできます。

KST (+0900)

こちらは韓国の標準時になります。
または、Asia/Seoulと指定する事もできます。

CST (+0600)

こちらはアメリカ・カナダ(中部標準時)になります。
または、America/Chicagoと指定する事もできます。

ちなみに、

中国の場合は文字列(UTCやJSTのようなもの)はなく、
+0800と指定するのが良さそうです。


任意のタイムゾーンでの取得

次に任意のタイムゾーンで時間を取得したい場合ですが、
文字列を指定する場合とUTCとの時差(+0900)を指定する場合があります。

文字列での指定はこのように行います。
Time.parse('2016-12-15 19:28:18 CST')
# => 2016-12-15 19:28:18 -0600

parseの場合はUTCからの時差で指定することもできます。
Time.parse('2016-12-15 19:28:18 -0600')
# => 2016-12-15 19:28:18 -0600

一時的にタイムゾーンを変更して取得を行いたい場合は、
以下のようにすることも可能です。
SYSTEM_TZ = ENV[‘TZ’]
ENV[’TZ’] => ‘CST’
Time.local('2016,12,15,19,28,18')
# => 2016-12-15 19:28:18 +0600
EVN[‘TZ’] = SYSTEM_TZ


任意のタイムゾーンでの表示

時刻の取得後に任意のタイムゾーンで表示をしたい場合は、
以下のように指定をすることで変更が可能となります。
time = Time.zone.now
# => Thu, 15 Dec 2016 19:28:18 JST +09:00
time.in_time_zone('UTC')
# => Thu, 15 Dec 2016 10:28:18 UTC +00:00

またはこのように指定することもできます。
time.in_time_zone('America/Chicago')
# => Thu, 15 Dec 2016 04:28:18 CST -06:00


最後に

UTCやJSTなどの文字列でタイムゾーンを指定する場合、
想定しているものとは違っていたり、
parseで指定したとしても反映されない場合等がありました。
明確に分かっているものならともかく確証がないものの場合は、
[Asia/Tkyo]のような文字列を使用するか[+0900]と時差指定の方が確実ではないかと思いました。

次回

月の始めや終わり、週の始めや終わりの取得方法を書いていきたいと思います。

2016年12月11日日曜日

はじめの一歩 -Rails 時間・タイムゾーン編- その3

どうもはじめです。

前回は時間に関するクラスである
「Time,Date,DateTime,TimeWithZone」の違い
について書いてみました。

はじめの一歩 -Rails 時間・タイムゾーン編- その2
今回は様々な日時の取得方法を見ていきます。
例としてTimeクラスとTimeWithZoneクラスを使用していきます。


Time

前回までも使用していますが、まずは現在時刻の取得から見ていきます。
Time.now
# => 2016-12-11 13:19:53 +0900

次に任意の時間を設定します。
Time.gmではUTCで時刻を設定し、
環境変数で設定しているタイムゾーンで時刻を設定したい場合は
Time.localを使用します。
Time.gm('2016,12,11,13,19,53')
# => 2016-12-11 13:19:53 UTC
Time.local('2016,12,11,13,19,53')
# => 2016-12-11 13:19:53 +0900

Timeクラスでは任意の秒数を加算減算して、
指定時刻からの数秒後、数秒前を取得することができます。
1日前、1日後を取得する場合
time = Time.now
# => 2016-12-11 13:19:53 +0900
time - 24 * 60 * 60
# => 2016-12-10 13:19:53 +0900
time + 24 * 60 * 60
# => 2016-12-12 13:19:53 +0900

文字列への変換は以下のように行います。
time = Time.now
time.to_s
# => "2016-12-11 13:19:53 +0900”

文字列からの変換を行うには
require 'time'
を記述する必要があります。
require 'time'
Time.parse('2016-12-11 13:19:53 JST')
# => 2016-12-11 13:19:53 +0900

unixtimeへの変換とunixtimeからの変換は以下のように行います。
time = Time.now
time.to_i
# => 1481429993
Time.at(1481429993)
# => 2016-12-11 13:19:53 +0900

Timeクラスには2038年問題がありましたが、
現在はすでに解消されているそうです。


TimeWithZone

現在時刻の取得は以下のように行います。
Time.zone.now
# => Sun, 11 Dec 2016 17:23:24 JST +09:00
Time.current
# => Sun, 11 Dec 2016 17:23:24 JST +09:00
Time.zone.nowまたはTime.currentで取得する時刻は
application.rbに設定したタイムゾーンを使用します。

任意の時間設定は以下のように行います。
Time.zone.parse('Sun, 11 Dec 2016 17:23:24 JST +09:00')
# => Sun, 11 Dec 2016 17:23:24 JST +09:00

次にさまざまの時刻を取得する方法です。
昨日明日
time = Time.zone.now
time.yesterday
# => Sat, 10 Dec 2016 17:23:24 JST +09:00
time.tomorrow
# => Mon, 12 Dec 2016 17:23:24 JST +09:00
先月来月
time = Time.zone.now
time.prev_month
# => Fri, 11 Nov 2016 17:23:24 JST +09:00
time.next_month
# => Wed, 11 Jan 2017 17:23:24 JST +09:00
去年来年
time = Time.zone.now
time.prev_year
# => Fri, 11 Dec 2015 17:23:24 JST +09:00
time.next_year
# => Mon, 11 Dec 2017 17:23:24 JST +09:00
その他にも以下のように表現することができます。
例として2日前と3年後を表示してみます。
time.ago(2.days)
# => Fri, 09 Dec 2016 17:23:24 JST +09:00
time.since(3.years)
# => Wed, 11 Dec 2019 17:23:24 JST +09:00

文字列への変換は以下のように行います。
time = Time.zone.now
time.to_s
# => "2016-12-11 17:23:24 +0900”

unixtimeへの変換とunixtimeからの変換
time = Time.zone.now
time.ti_s
# => 1481444604
Time.zone.parse(1481444604)
# => 2016-12-11 17:23:24 +0900

まとめ

TimeWithZoneではyesterdayやtomorrowなど 直感的に記述することができますが、
Timeクラスでも
require ‘active_support/all’
と記述することでTimeWithZoneと同様に
翌日や前日等の日時を表現することができます。

次回

次回はいくつかのタイムゾーンの紹介や
任意のタイムゾーンでの出力等ついて書いてみようと思います。

2016年12月8日木曜日

はじめの一歩 -Rails 時間・タイムゾーン編- その2

どうも、はじめです。

前回は指定したフォーマットで時刻を表示するstrftimeについて書いてみました。
「はじめの一歩 -Rails 時間・タイムゾーン編-」
今回は日付や時間に関するクラスである
こちらの4つについて書いていきます。
「Time、Date、DateTime、TimeWithZone」

はじめに、

現在時刻の取得をした後、strftime()で「年月日、時刻、曜日、タイムゾーン」を表示して
それぞれの違いを見ていきます。


Time

こちらはRubyで用意されている時刻を表すクラスです。
現在時刻の取得、表示はこのように行います。
time = Time.now
# => 2016-12-07 21:28:39 +0900
time.strftime('%Y * %m * %d * %w * %U * %X * %Z')
# => "2016 * 12 * 07 * 3 * 49 * 21:28:39 * JST"
年月日、時分秒、曜日、タイムゾーンなどの情報を表示することができました。


Date

こちらはRubyで用意されている日付を表すクラスです。
使用する際は
require ‘date’
と記述をする必要があります。
現在時刻の取得、表示はこのように行います。
require ‘date'
date = Date.today
date.strftime('%Y * %m * %d * %w * %U * %X * %Z')
# => "2016 * 12 * 07 * 3 * 49 * 00:00:00 * +00:00"
Timeとは違って年月日、曜日のみ表示されました。
その他の時分秒、タイムゾーンの情報は全て0で表示されています。


DateTime

こちらは日付と時刻を扱えるDateのサブクラスです。
DateTimeもDateクラスと同様に使用する際には
require ‘date’
と記述する必要があります。
現在時刻の取得、表示はこのように行います。
requrire ‘date’
datetime = DateTime.now
datetime.strftime('%Y * %m * %d * %w * %U * %X * %Z')
# => "2016 * 12 * 07 * 3 * 49 * 21:28:39 * +09:00”
Timeクラスと同じように年月日、時分秒、曜日の情報が表示されましたが、
タイムゾーンに関しては表示が違います。
Timeクラスでは”JST"と文字列で表示されていますが、
DateTimeクラスの場合は”+09:00”とUTC(協定世界時)からの時差が表示されています。


TimeWithZone

こちらはRailsで使用することができるActiveSupport::TimeWithZoneクラスです。
素のRubyでは使用することはできません。
TimeWithZoneクラスでの現在時刻の取得、表示は以下のようになります。
timewithzone = Time.zone.now
timewithzone.strftime('%Y * %m * %d * %w * %U * %X * %Z’)
# => "2016 * 12 * 07 * 3 * 49 * 21:28:39 * JST”
こちらはTimeクラスと全く同じ表示になりました。

まとめ

Time、DateTime、TimeWithZoneの3つに関しては、
大きな違いはないように見えます。

調べてみたところTime、DateTimeの違いとしては以下の点があげられるようです。

Timeの場合、
・require無しで使える
・タイムゾーンの指定なしでインスタンスの生成を行った時、システムまたは環境変数で設定しているタイムゾーンが使用される
(DateTimeの場合はUTCが使用される)
・うるう秒を使える
・サマータイムを使える

ということからDateTimeよりTimeを使用したほうが良いとのことです。

Timeに対してTimeWithZoneはシステムや環境変数ではなく、
application.rbに設定したタイムゾーンが使用されるようです。
また、"Time.current"でタイムゾーンを指定して時刻の取得を行うこともできます。


つまり。。。
Time、DateTime、TimeWithZoneの全てが使える環境であれば、
タイムゾーンを柔軟に扱えるTimeWithZoneを使用し、
そうでない環境である場合はTimeを使用する形になるのではないかと思います。


次回

前回から今回にかけて現在時刻を取得して比較をしていましたが、
次回は翌日や翌年、時刻の指定やUnixTimeの変換等について
書いてみようと思います。

2016年12月4日日曜日

はじめの一歩 -Rails 時間・タイムゾーン編-

どうも、はじめです。
本日から「はじめの一歩 -時間・タイムゾーン編」ということで、
何度かに分けてRailsの時間・タイムゾーンについての記事を連載していきます。

今回の内容は「strftime」についてです。

はじめに

strftimeとは、

Rubyの組み込みオブジェクトとして用意されており、
時刻を指定したフォーマットに沿って文字列へ変換してくれるものになります。


time = Time.now # Sun Dec 03 16:06:18 +0900 2016
time.strftime('%Y年%m月%d日 %H:%M:%S')
# => 2016年12月04日 16:06:18

それではフォーマットについて見ていきたいと思います。
今回は例としてTime型での実行結果をまとめてみました。

フォーマット


フォーマット説明実行結果
%Y西暦を表す数 2016
%y西暦の下2桁16
%m月を表す数字(01-12)12
%B月の名称(January,February,March,April,May,June,July,August,September,October,November,December)December
%b月の省略名(Jan,Feb,Mar,Aprl,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)Dec
%d日(01-31)04
%x日付 ('%m/%d/%y')と同じ意味になります12/04/16
%j年中の通算日(001-366)339
曜日
%A曜日の名称(Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday)Sunday
%a曜日の略称(Sun,Mon,Tue,Wed,Thu,Fri,Sat)Sun
%w曜日を表す数。日曜日が0(0-6)0
%U週を表す数。最初の日曜日が第1週の始まり(00-53)49
%W週を表す数。最初の月曜日が第1週の始まり(00-53)48
%H24時間制の時(00-23)16
%I12時間制の時(01-12)04
%M分(00-59)06
%S週秒(00-60)(60はうるう秒)18
その他
%c日付と時間"Sun Dec 4 16:06:18 2016"
%p午前または午後(AM,PM)PM
%X時刻"16:06:18"
%ZタイムゾーンJST
%%パーセント%

下記はオプション一覧です。


オプション
フォーマット説明
^大文字で出力
#小文字は大文字に、大文字は小文字に変換
-左寄せ
_空白埋め
00埋め
数値指定した表示桁数での表示

オプションを幾つか組み合わせて実行した結果がこちらになります。
桁数指定をしている状態で左寄せを行うと通常と同じ表示になるようです。

time.strftime('%^10A') # => "    SUNDAY"
time.strftime('%0#6Z') # => "000jst"
time.strftime('%Y/%-m/%-d %X') # => "2017/1/4 16:06:18"
ちなみに、、、
曜日を日本語で表示したいときは以下のように書きます。
Time.now.strftime("#{%w(日 月 火 水 木 金 土)[Time.now.wday]}")
# => 日

まとめ


年月日、曜日、週に関してはTime型、Date型、DateTime型、TimeWithZone型のどれであっても
表示される内容は同じでした。
ですが、時刻やその他のフォーマットに関してはデータ型によって出力内容が異なってきます。
実際に使用する際には、一度想定通りに表示されているかを確認してから使用する用にしましょう。
(今回の時刻、その他の項目に表示されている実行結果はTimeWithZone型となっております。)

次回


今回の最後に出てきましたデータ型について、
時刻だけでも幾つかのデータ型がありますのでそちらをやってみようと思います。