Rails のルーティング
ルーティングを追加するとき、毎回調べているので少しずつまとめていこうかと思います。 等価な書き方が色々あるので絶対これというわけではありません。
scope
URI Pattern にのみ追加されます。
Rails.application.routes.draw do scope :user do resources :profile end end
➜ sample git:(master) ✗ be rake routes Prefix Verb URI Pattern Controller#Action profile_index GET /user/profile(.:format) profile#index POST /user/profile(.:format) profile#create new_profile GET /user/profile/new(.:format) profile#new edit_profile GET /user/profile/:id/edit(.:format) profile#edit profile GET /user/profile/:id(.:format) profile#show PATCH /user/profile/:id(.:format) profile#update PUT /user/profile/:id(.:format) profile#update DELETE /user/profile/:id(.:format) profile#destroy
scope module:
Controller#Action にのみ追加されます。
Rails.application.routes.draw do scope module: :user do resources :profile end end
➜ sample git:(master) ✗ be rake routes Prefix Verb URI Pattern Controller#Action profile_index GET /profile(.:format) user/profile#index POST /profile(.:format) user/profile#create new_profile GET /profile/new(.:format) user/profile#new edit_profile GET /profile/:id/edit(.:format) user/profile#edit profile GET /profile/:id(.:format) user/profile#show PATCH /profile/:id(.:format) user/profile#update PUT /profile/:id(.:format) user/profile#update DELETE /profile/:id(.:format) user/profile#destroy
scope as:
Prefix にのみ追加されます。
Rails.application.routes.draw do scope as: :user do resources :profile end end
➜ sample git:(master) ✗ be rake routes Prefix Verb URI Pattern Controller#Action user_profile_index GET /profile(.:format) profile#index POST /profile(.:format) profile#create new_user_profile GET /profile/new(.:format) profile#new edit_user_profile GET /profile/:id/edit(.:format) profile#edit user_profile GET /profile/:id(.:format) profile#show PATCH /profile/:id(.:format) profile#update PUT /profile/:id(.:format) profile#update DELETE /profile/:id(.:format) profile#destroy
scope と module: と as:
Prefix と URI Pattern と Controller#Action 全てに追加されます。
Rails.application.routes.draw do scope :user, module: :user, as: :user do resources :profile end end
➜ sample git:(master) ✗ be rake routes Prefix Verb URI Pattern Controller#Action user_profile_index GET /user/profile(.:format) user/profile#index POST /user/profile(.:format) user/profile#create new_user_profile GET /user/profile/new(.:format) user/profile#new edit_user_profile GET /user/profile/:id/edit(.:format) user/profile#edit user_profile GET /user/profile/:id(.:format) user/profile#show PATCH /user/profile/:id(.:format) user/profile#update PUT /user/profile/:id(.:format) user/profile#update DELETE /user/profile/:id(.:format) user/profile#destroy
namespace
Prefix と URI Pattern と Controller#Action 全てに追加されます。
( scope と module: と as: ) と同じ結果になります。
Rails.application.routes.draw do namespace :user do resources :profile end end
➜ sample git:(master) ✗ be rake routes Prefix Verb URI Pattern Controller#Action user_profile_index GET /user/profile(.:format) user/profile#index POST /user/profile(.:format) user/profile#create new_user_profile GET /user/profile/new(.:format) user/profile#new edit_user_profile GET /user/profile/:id/edit(.:format) user/profile#edit user_profile GET /user/profile/:id(.:format) user/profile#show PATCH /user/profile/:id(.:format) user/profile#update PUT /user/profile/:id(.:format) user/profile#update DELETE /user/profile/:id(.:format) user/profile#destroy
Git で 変更を一時的によける
あるブランチで色々変更をしていて、中途半端だけど、急遽他のブランチで作業をしなければならなくなった時に、 git stash
というコマンドが便利です。
変更を加える
➜ sample git:(hoge) touch hoge.txt ➜ sample git:(hoge) ✗ git add . ➜ sample git:(hoge) ✗ git commit -m "hoge.txt の作成" ➜ sample git:(hoge) hoge.txt の編集 ➜ sample git:(hoge) ✗ git status On branch hoge Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: hoge.txt no changes added to commit (use "git add" and/or "git commit -a")
hoge.txt が作成されている hoge ブランチで hoge.txt を編集します。
git status
でワークツリーに変更が加わっていることが確認できています。
変更をよける
ここで git stash
を実行して、変更を一時的によけてみます。
➜ sample git:(hoge) ✗ git stash Saved working directory and index state WIP on hoge: 2e894e0 hoge.txt の作成 HEAD is now at 2e894e0 hoge.txt の作成 ➜ sample git:(hoge) git status On branch hoge nothing to commit, working directory clean
すると、git status
を実行しても先ほどの hoge.txt の変更は表示されません。
一時的によけた変更は、 git stash show
で確認できます。
➜ sample git:(hoge) git stash show hoge.txt | 1 + 1 file changed, 1 insertion(+)
他のブランチで変更を加える
そして、fuga ブランチへ checkout して fuga.txt を作成し、これをコミットします。
➜ sample git:(hoge) git checkout fuga Switched to branch 'fuga' ➜ sample git:(fuga) touch fuga.txt ➜ sample git:(fuga) ✗ git add . ➜ sample git:(fuga) ✗ git commit -m "fuga.txt の作成" [fuga 199f6b5] fuga.txt の作成 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 fuga.txt
git show
でコミット内容を確認してみても、hoge ブランチで行った作業の内容はコミットされていないことが確認できます。
➜ sample git:(fuga) git show commit 199f6b526fc2b6612e31b8e913df2fe2ae4f0d42 Author: fuga <fuga@fuga.fuga> Date: Mon May 23 23:11:46 2016 +0900 fuga.txt の作成 diff --git a/fuga.txt b/fuga.txt new file mode 100644 index 0000000..e69de29
変更を戻す
次に、再び hoge ブランチへ checkout します。
先ほど一時的によけた変更を元に戻すには git stash pop を実行します。
➜ sample git:(fuga) git checkout hoge Switched to branch 'hoge' ➜ sample git:(hoge) git stash pop On branch hoge Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: hoge.txt no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (8e370d4ff891b72ee304fca8bca60b7371663fff)
念のため git status を実行してみると、変更が元に戻っていることが確認できます。
➜ sample git:(hoge) ✗ git status On branch hoge Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: hoge.txt no changes added to commit (use "git add" and/or "git commit -a")
TableViewController と Storyboard でテーブルをつくる (Swift)
ViewController でテーブルを作成する記事はよく見かけたのですが、 TableViewController を使う方法はあまりなかったのでメモ。
まだまだ学び始めたばかりでよくわかっていないことだらけなので、手順だけ。
ざっくり書くと、
- storyboard で TableViewController を追加
- 追加した TableViewController の cell に要素を追加
- TableViewController に対応させるファイル ( TableViewController.swift ) を作成
- cell に対応させるファイル ( TableViewCell.swift ) を作成
- cell と TableViewCell.swift を対応させる
- TableViewController と TableViewController.swift を対応させる
- TableViewController.swift を実装する
という流れです。
storyboard で TableViewController を追加
storyboard を選択し、右下のライブラリの検索窓に tableviewcontroller
等と入力して、 TableViewController をドラッグアンドドロップ。
追加した TableViewController の cell に要素を追加
先ほどと同様に、cell に追加したい要素をライブラリで検索します。
要素を cell の上にドラッグアンドドロップで配置します。
TableViewController に対応するファイル ( TableViewController.swift ) を作成
command + N 等でファイル作成画面を開きます。
Cocoa Touch Class を選択します。
次画面で、 Subclass of を UITableViewController にします。
Class 名は自由に変更して構いません。
そのままファイルを作成します。
cell に対応させるファイル ( TableViewCell.swift ) を作成
先ほどと同様に、 Cocoa Touch Class を選択します。
次画面で、 Subclass of を UITableViewCell にします。
Class 名は自由に変更して構いません。
そのままファイルを作成します。
cell と TableViewCell.swift を対応させる
アイデンティティインスペクタから Custom Class の Class を TableViewCell にします。
次に、属性インスペクタ から Identifier を任意の値に設定します。この値はファイル名と対応していなくて構いません。
TableViewController と TableViewController.swift を対応させる
先ほどと同様に、 アイデンティティインスペクタから Custom Class の Class を TableViewController にします。
ちなみに、ここまでの作業だけで storyboard で cell に追加した要素が表示されるようになるかと思うかもしれませんが、まだ不十分です。
Build には成功しますが、以下のよう cell には何も表示されないので、後述の実装が必須となります。
UITableViewController.swift を実装する
たくさんコードが書いてありますが、変更する箇所は以下の関数 3 つです。
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 0 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return 0 } /* override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) // Configure the cell... return cell } /*
この 3 つを以下のように書き換えるだけです。
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 5 // 任意の値に変更する ( 1 セクションあたりの行数 ) } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return 1 // 任意の値に変更する ( セクション数 ) } // コメントアウトを外す override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("TableViewCell", forIndexPath: indexPath) // reuseIdentifier を cell に設定した Identifier に書き換える // Configure the cell... return cell }
以上で作業は終わりです。
確認する
Build すると追加した要素が表示されていることを確認できます。
レイアウトは調整していないので汚いです。
モデルの属性に自作のバリデーションを追加する
モデルの属性のバリデーションをしたいときに、バリデーションヘルパーの既存バリデーションだけでは足りないことがあると思います。
そのため、Rails ではバリデーションを自作することができます。
その一つの方法としてバリデーションメソッドがあります。
バリデーションメソッド
バリデーション用のメソッドを定義して、オブジェクトの保存時にそのメソッドによりバリデーションする方法です。
例えば、 name 属性を持つ Account モデルに対して、 name の prefix として hoge_
があるというバリデーションをしたい (?) 場合には、以下のようにします。
class Account < ActiveRecord::Base validate :prefix_hoge # 保存時に prefix_hoge によりバリデーションをする # バリデーションメソッド def prefix_hoge if name !~ /^hoge\_/ # バリデーションの条件 errors.add(:name, " は hoge_ から始まるようにしましょう!") # エラーメッセージ end end end
これにより、 prefix として hoge_
のない name を持つ Account のオブジェクトを保存しようとするとエラーになります。
# hoge_ あり irb(main):001:0> Account.first.update(name: 'hoge_test') Account Load (0.3ms) SELECT `accounts`.* FROM `accounts` ORDER BY `accounts`.`id` ASC LIMIT 1 (0.2ms) BEGIN SQL (0.3ms) UPDATE `accounts` SET `name` = 'hoge_test', `updated_at` = '2016-05-13 14:59:13' WHERE `accounts`.`id` = 1 (0.6ms) COMMIT => true # hoge_ なし irb(main):002:0> Account.first.update(name: 'test') Account Load (0.3ms) SELECT `accounts`.* FROM `accounts` ORDER BY `accounts`.`id` ASC LIMIT 1 (0.1ms) BEGIN (0.2ms) ROLLBACK => false
ですが、 複数の属性に対してバリデーションヘルパーとバリデーションメソッドの両方を利用すると、以下のように同一の属性のバリデーションの記述が分散してしまうことがあります。
class Account < ActiveRecord::Base validates :name, presence: true, length: { maximum: 10 } validates :email, presence: true validate :prefix_hoge validate :email_validation
バリデーションを自作する他の方法として、カスタムバリデータがあります。 こちらを使えば上記の点を防ぐことができます。
カスタムバリデータ
先ほどと同様のバリデーションを追加します。
カスタムバリデータは、 バリデーションを自作するためのクラスを継承したクラスを作ります。
クラスには ActiveModel::Validator と ActiveModel::EachValidator の二種類があるのですが、後者の方が使いやすいと思うのでそちらについてのみ書きます。
クラスをパスの通っている場所に作成します。
# lib/validators/prefix_hoge_validator.rb class PrefixHogeValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) # バリデーションメソッド if value !~ /^hoge\_/ record.errors.add(attribute, " は hoge_ から始まるようにしましょう!") end end end
バリデーションメソッドは必ず validate_each
とします。
validate_each
の引数の record
に保存対象のオブジェクトが、 attribute
にバリデーション対象の属性が、 value
に保存する値
が渡ってきます。
これを Account モデルで利用する際には、バリデーションヘルパーのように記述することができます。
class Account < ActiveRecord::Base validates :name, prefix_hoge: true
これで先ほどと同様のバリデーションをすることができます。
カスタムバリデータであれば、複数の属性に対してバリデーションヘルパーとバリデーションメソッドの両方を利用したとしても、以下のように対象の属性の記述が一箇所にまとまり見やすくなります。
class Account < ActiveRecord::Base validates :name, presence: true, length: { maximum: 10 }, prefix_hoge: true validates :email, presence: true email_validation: true
とはいえ、毎回カスタムバリデータを使うのではなく、それぞれのメリットデメリットを見極めて使うと良さそうです。
Xcode で info.plist のプロパティを追加する
プロパティの追加方法がわかりづらかったからメモ。
上記の手順をふむとプロパティが追加されるので、以下のようにプロパティ名や型を目的の値に変更して完了です。
ちなみに、、、
③で一番下のプロパティと書きましたが、どのプロパティでも構いません。
当該プロパティの下の欄にプロパティが追加されます。
また、 プロパティ横の ▶︎ が ▼ の状態で + をクリックすると、 当該プロパティの子プロパティとして追加されます。
Rails の Time と DateTime
日時を扱うクラスには DateTime と Time の二つがあり、どちらを使えば良いのかを知ることもなく過ごしてきてしまっていたのですが、ざっくりと知ることができたのでメモ。
基本的には Time ( ActiveSupport::TimeWithZone ) を使う
Rails 環境においては、特に理由がないときは Time クラスを使うと良いそうです。
正確に言うと、ActiveSupport::TimeWithZone クラスです。
現在時刻を取得する場合で言うと、DateTime.now
ではなく、 Time.now
でもなく Time.current
を用いるのが良いです。
Time.current
を用いることで、Time クラスではなく ActiveSupport::TimeWithZone クラスの時刻を取得することができるからです。
(内部的には Time.zone.now
が実行されています。)
なんで?
ActiveSupport::TimeWithZone クラスは application.rb のタイムゾーンを使い、また、DB のタイムスタンプは Time.current
で更新されます。
そのため、設定したタイムゾーンが反映されていないぞ!ということがなくなり、DBとも統一されるので、安心感もあります。
これらのことから、 ActiveSupport::TimeWithZone クラスの時刻を取得することができる Time クラスを使うと良いとのことでした。
ローカル環境の Ruboty を slack で動かす
ローカル環境の Ruboty を slack で動かしてみたときのメモです。
Ruboty の使い方は、先日投稿したエントリにざっくり書いてあります。
slack team を用意する
作っていない場合はこちらから。 Slack: Be less busy
slack 用アダプタのインストール
Gemfile に gem 'ruboty-slack_rtm'
を追記して bundle install
します。
bot アカウントの追加
こちらから、 Ruboty を動かしたい team に Bots をインストールします。
Username を聞かれるので、好きな名前を入力して Add bot integration をクリック。 これが bot アカウントの名前になります。後から変更することもできます。
クリックした後の画面で表示される Integration Settings の API Token をメモしておきます。
slack を確認すると bot アカウントが追加されていると思います。
環境変数の設定
ターミナルで環境変数 SLACK_TOKEN を設定します。 この値を先ほどメモした API Token にします。
export=<API Token>
以上で準備完了です。
slack で動かしてみる
bundle exec ruboty
で Ruboty を起動します。 アダプタが設定されているので、 シェル上では何も表示されません。
slack を確認すると、 先ほど追加した bot アカウントがオンラインになっています。 この状態で、 bot アカウントのいる CHANNEL でコマンドを入力すると正しく動作するはずです。
ruboty ping
を入力してみると pong
が返ってくると思います!