ホーム ブログ ページ 41

Rack の話 | 初心者向け | DoRuby

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Rack はとてもシンプルな規約に基づいたインタフェースです。

Ruby on Rails や Sinatraは、Rackの上に実装され、UnicornやPumaなどのWebサーバに渡されます。

今回は、Rackの基礎をさっと説明します。

 せっかちなあなたへ

$ gem install rack
$ vi config.ru
run -> (env) { [200, {"Content-type" => "text/html"}, ["Hello, world"]]}
$ rackup config.ru

そして、 http://localhost:9292 にアクセスするだけ!

簡単に実装できました。

 改めて Rackとはなんぞや

http://rack.github.io にはこんな説明があります。

Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.

Web サーバと Rubyやフレームワークをつなぐ最小のインタフェースを提供している

rackの規約を満たしていれば、フレームワークやWebサーバを簡単に差し替えることができます。

rackには WEBrickというシンプルなWebサーバも搭載されており、rackの規約を満たすスクリプトを書くだけで簡単にWebアプリを作成することができます。

 Rackの規約

最低限以下を満たしていればOK

  1. アプリとなるオブジェクトを記述して run に渡します。 (上記の例だと、runに渡している Procオブジェクト)
  2. オブジェクトは次の規約を満たすものとします
    1. 引数を1つもつcallメソッドが定義されている(慣習的に仮引数名は env)
    2. callメソッドは [ステータスコード, ヘッダのハッシュ, 本文の配列] を返す

通常は設定ファイルに記述します。慣習的に拡張子が.ruのファイルに記述します。

中身の実体は Rubyなので .rb でも良さそうですが、run などのDSLとして拡張されるので変更されているみたい。

Ruby on Rails のアプリひな形だと app_path/config.ru になります。

 Rack Middleware

上記の規約を満たしていればOKなのですが、それだと 巨大な callメソッドになってしまいます。

Ruby が使えるのでクラスを切り出すことも可能ですが、そんな複雑なインタフェースをもつわけはありません。

use を使うことで、フィルタのように処理をつなげることができます。

たとえば、Basic認証を実装します。(このMiddlewareはRack標準に定義されています)

require 'rack/auth/basic'
use Rack::Auth::Basic, "input username" do |username, password| 
  username == "foo" && password == "secret"
end
run -> (env) { [200, {"Content-type" => "text/html"}, ["Hello, world"]]}

 Rack Middleware の規約

次を満たせば Rack Middlewareとなります

  1. 最初の引数に アプリとなるオブジェクトを受け取る initializeメソッドが定義されている
  2. Rackの規約を満たす call メソッドが定義されている

use を使って複数呼び出すことができますが、順番に注意してください。

次の場合は MiddleA -> MiddleB -> MiddleC と呼ばれます。

use MiddleA
use MiddleB
use MiddleC
run App

 Rails と Middleware

rack middleware コマンドで確認できます。

$ rack middleware

普段なかなか触らない Rackについて簡単に説明しました。

Railsのソースをながめると処理の流れをつかめるので、ぜひ追ってみてください。

抽象化しているので複雑ですが、実体は非常にシンプルです。

【Rails】特定のアクションだけ認証を外す方法【devise】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

管理画面等の特定のページをログインせずに閲覧したい時の方法を記述します。

とても簡単

自分がタイトルどうりの機能が必要になったのですが、方法がわからず結構苦労しました。

ですが、なんてことは無い単純なことでした。

authenticate_user!

認証が必要になるようにする場合controllerに

	    before_action :authenticate_user!
	

と記述するかと思います。(「user」の部分はdeviseに使っているクラス)

これを公開したいアクションの際に外すだけでした。

	    before_action :authenticate_user!, except: [:public_action]
	

なんですぐに気づかなかったんだろう…

Docker を試してみる(1)

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


 はじめに

共有の開発やCIサーバにMySQLの別のバージョンを使いたい!ってときにOSに共存させるのは結構面倒で、最悪壊したりしてしまいます。

そんなときに、Docker は便利です。

Dockerは仮装マシンではなくOS上で仮想環境を構築するソフトウェアです。

Linuxコンテナ型仮想化技術を使ってますが、vagrantと同様に簡単に使える環境が整っています。

今回はその使い方を調べてみました。

 インストール

今回はCentOS7を使いますが、せっかくなので vagrant を使いましょう。

前準備

以下のソフトウエアを準備します。

  • VirtualBox 5.0.14
  • vagrant 1.8.1
  • bento/chentos-7.1 (virtualbox, 2.2.2)

適当なフォルダで次のコマンドを実行します。

$ vagrant init bento/chef-7.1
$ vagrant up
$ vagrant ssh

準備はできましたか?

ログイン後、dockerの動く環境であるか一応確認します。

  • 64bitであること
  • Kernel 3.10 以降であること
[vagrant@localhost ~]$ uname -a
Linux localhost.localdomain 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

インストール

CentOS7のextrasレポジトリに docker 1.8.2 がありますが、今回はdocker公式のものを使います。

repository の登録

デフォルトで有効にしちゃってますので、気に入らなければ enabled = 0 を設定してください。

[vagrant@localhost ~]$ sudo su -
[root@localhost ~]# cat > /etc/yum.repos.d/docker.repo <<'EOF'

[dockerrepo]

name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg EOF [root@localhost ~]# cat /etc/yum.repos.d/docker.repo

[dockerrepo]

name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg

インストール
[root@localhost ~]# yum install docker-engine -y
[root@localhost ~]# systemctl start  docker
[root@localhost ~]# systemctl status docker
docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled)
   Active: active (running) since ...
[root@localhost ~]# systemctl enable docker
一般ユーザで動かす

デフォルトではdockerはrootユーザしか使えません。

一般ユーザで使うためには docker グループに追加します。

[vagrant@localhost ~]$ sudo gpasswd -a vagrant docker

コンテナを起動してみる

使用するコンテナを探す

vagrant と同様にコンテナのイメージは Docker Hubで公開されています。

コマンドラインからも検索できますが、今回は Webから mysql 用のコンテナを探してみましょう。

https://hub.docker.com/explorer

現在対応しているのは 5.5, 5.6, 5.7 の3種類ですが、今回は 5.7 を使います。

でも、わざわざダウンロードする必要はありません。自動的にpullしてくれます。

使用するコンテナを実行する

以下のコマンドを実行して、仮想環境にログインしてみましょう。

[vagrant@localhost ~]$ docker run -t -i --rm mysql:latest /bin/bash
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
...
Status: Downloaded newer image for mysql:latest
root@4e05429b2b2f:/# 

プロンプトが返ってきたら成功です。もう仮想環境の中です。
-iインタラクティブモード-t端末を使用する–rm終了時にコンテナを削除する

実行中のコンテナを確認する

別の端末を起動して、以下のコマンドを実行してみます。

[vagrant@localhost ~]$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4e05429b2b2f        mysql:latest        "/entrypoint.sh /bin/"   4 minutes ago       Up 4 minutes        3306/tcp            pensive_payne

コンテナの一覧が表示されます。
IMAGE実行中のコンテナCOMMAND実行中のコマンドSTATUSステータスNAMESコンテナの名前(指定するか勝手に付けられる)

今回は STATUS が 「Up 4 minutes 」なので起動中と分かります。

コンテナを終了させる

stop コマンドを使います。引数には ps コマンドで出力された NAMES の値を指定します。

[vagrant@localhost ~]$ docker stop pensive_payne
pensive_payne

pensive_payne にはpsコマンドのNAMESの値を指定してください。

もう一度コンテナの一覧をみてみます。

[vagrant@localhost ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

なにも表示されなくなりました。

MySQLを使う

次は mysqlサーバを起動します。

起動

run コマンドを使います。

[vagrant@localhost ~]$ docker run  -e MYSQL_ROOT_PASSWORD=password -d mysql:latest
8e05ca461fa74135cf84e1f0f5f2e229810b40402e865c28fc593320bd26ba3a
[vagrant@localhost ~]$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
8e05ca461fa7        mysql:latest        "/entrypoint.sh mysql"   19 seconds ago      Up 15 seconds       3306/tcp            small_lichterman

-dデタッチオプション。コンテナをバックグラウンドで動作させる

mysql コンテナはmysqldをフォアグラウンドで起動するので、サーバとして起動させるならば -d オプションは必須です。

サーバに接続する

コンテナ中の mysql クライアントを使って接続するには以下の通り。

[vagrant@localhost ~]$ docker exec -it small_lichterman sh -c 'mysql -uroot -p'
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

次回はもうちょっと進んだ使い方を説明します。

サーバのデータ完全消去をやってみた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

もうすぐ2年目が終わってしまって、新人と言えなくなってきた中西です。

少し前にサーバーの撤去を行う機会があり、その時にサーバーのデータ完全消去の方法を色々と調べて行ったので、まとめてみました。

今回行ったデータ消去の方法は、インストールCDのレスキューモードをもちいた方法です。

ちょうど、サーバー構築用のSentOS6のiosデータが入ったCDがあったため、それをもちいて行いました。

事前準備物

・LinuxOSのCD(今回はCentOS6.6のisoイメージのインストール用CDを使用)

・データを完全消去するサーバー

・任意のディスプレイ

・任意のキーボード、マウス

 実行手順

今回行った時の手順を説明します。

前準備

1. サーバー起動

2. 任意のユーザーでログイン

3. ディスク配置の確認

$ df -kl
Filesystem                   1K-blocks     Used Available Use% Mounted on
/dev/mapper/VolGroup-lv_root  18102140 16079472   1103116  94% /
tmpfs                           510172        0    510172   0% /dev/shm
/dev/sda1                       495844    32670    437574   7% /boot

 例えば、上記のように表示されている場合、接続されているHDDはsdaとなる。

 消去対象になるため、間違えないようにメモしておく。

4. CDをドライブにセット後、サーバー再起動

 $ reboot

レスキューモードで起動(CentOS6.6の場合)

※OSによりレスキューモードの起動方法が異なる場合があるので要確認

1. 青画面に「Welcome to CentOS 6.6!」と表示されるページで「ESC」キーを押す

 (中段にいくつか選択肢があり、下部に「Automatic boot in ○○ seconds…」とカウントダウンされているページ)

2. ブートオプション画面(「boot:」と表示される画面)が開くので、「linux rescue」と入力する

3. Choose a Language画面で、「Japanese」を選択する(Englishや他言語でも可)

4. Language Unavailable画面で、「OK」を押す(言語によっては、表示されない。Japaneseは表示される)

5. Keyboard Type画面で、「jp106」を選択する

6. Setup Networking画面で、「No」を選択する

7. Rescue画面で、「Skip」を選択する

8. 「Shell」や「reboot」などの選択肢が表示される画面で、「Shell Start shell」を選択する

9. 画面下部に「bash-4.1#」と表示される

ディスクのパーティションを切りなおす

1. fdiskコマンドを起動(fdisk -l)

# fdisk /dev/sda 

2. “p”コマンドでパーティションを確認する

コマンド (m でヘルプ):p
〜略〜
デバイス Boot Start End Blocks Id System
/dev/sda1 * 1 13 104391 83 Linux
/dev/sda2 14 913 7229250 8e Linux LVM

 例えば上記の場合、パーティションは1、2の2つとなる。

3. “d”コマンドでパーティションを削除する

 手順2の場合、下記の用に2から削除を行う。

コマンド (m でヘルプ):d
コマンド (m でヘルプ):2

4. 手順3を「1」まで繰り返す

5. “p”コマンドでパーティションがないことを確認する

コマンド (m でヘルプ):p

6. 作業結果を”w”コマンドでディスクに書き込む

コマンド (m でヘルプ):w

ディスクの初期化(0埋め)

1. ディスク全域に”0″で埋めることで、情報を全て消去する

# dd if=/dev/zero of=/dev/sda

 上記は1度だけ”0″で上書きするもの。

 現状の15GBytes以上のハードディスクに関しては、データの完全消去は1度の上書きで十分であると言われている。

 アメリカ国立標準技術研究所(NIST)が2006年に発表したSpecial Publication 800-88の7ページでは、次のように述べられている。『2001年以降の(15GBytes以上の)集積度の高いATAハードディスクにおいては、データの完全消去はディスク全域に1回のみ上書きすれば事足りる』。

 また、Center for Magnetic Recording Researchは、次のように述べている『データの完全消去はディスクに対する1回の上書きのことである。アメリカ国家安全保障局も推奨要綱にて、同相信号除去比(CMRR)試験をした結果、複数回の上書きは何ら安全性の向上に優位な差をもたらさず、1回の上書きで十分であることを認めている』。

https://ja.wikipedia.org/wiki/

 より、安全になるか分からないが複数回の上書きを行いたい場合、shredコマンドをもちいると良い

# shred -n 3 -z -v /dev/sda

 上記shredコマンドは、ランダムな値を3回上書きし、その後”0″で上書きを行っている。

 上記をddコマンドで行う場合、下記のようになる。

# dd if=/dev/urandom of=/dev/sda
# dd if=/dev/urandom of=/dev/sda
# dd if=/dev/urandom of=/dev/sda
# dd if=/dev/zero of=/dev/sda

消去の確認

1. 「exit」と入力することで「Shell」や「reboot」などの選択肢が表示される画面に戻る。

2. 「reboot」を選択し、CDを取り出す

3. OSが立ち上がらないことを確認する

 ddコマンドによるデータ全消去における注意点

ddコマンドは下記コマンドでデータの全消去が行える。

# dd if=/dev/zero of=/dev/sda

この場合、全ての設定がデフォルト値となる。

この中には、1度に読み込むまた、書き込みバイト数も設定されている。

デフォルトの読み込み及び書き込みのバイト数は512byteであるため、大容量のディスクにたいしてコマンドを実行する場合、多大な時間がかかってしまう。

1度の読み込み及び書き込みのバイト数を設定するには下記のようにすればよい。

# dd if=/dev/zero of=/dev/sda bs=32M

上記では、1度の読み込み及び書き込みのバイト数を32Mbyteに設定している。

このバイト数は単純に大きくすれば早くなるという訳ではなく、スペック等により、大きくしすぎると逆に処理が遅くなる場合があることに注意してもらいたい。

32Mから256Mほどがちょうど良い設定値だと言われている。

また、読み込み及び書き込みのバイト数はそれぞれ個別に設定することもできる。

下記に一覧を表示する。

・bs=[バイト数]:1度に読み込み及び書き込めるバイト数の設定

・ibs=[バイト数]:1度に読み込めるバイト数の設定 

・obs=[バイト数]:1度に書き込めるバイト数の設定

 ddコマンドによるデータ全消去にかかる時間

300GBのハードディスクを消去した時

# dd if=/dev/zero of=/dev/sda

・9836.86s

・30.4MB/s

# dd if=/dev/zero of=/dev/sda bs=256M

・1736.51s

・172MB/s

もう少しbsの値を抑えてもそれほど時間は変わらなかったかもしれません。

環境により異なるため、あくまで1例としてご覧ください。

生産的な振り返り方法「KPT」について

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

たまごです。

技術ネタではないですが。今回、開発フェーズ終了に際して、チーム内でKPTを実施しましたので、以下、KPTについてご説明したく思います。

 KPTとは

「KEEP 続けていきたいこと」「PROBLEM 問題点」「TRY 次回からこうしよう」を順番に書き出していく振り返り方式です。

左上部にKEEP、左下部にPROBLEM、そして両者を受けて右側にTRYを書いていきます。

 実施方法

必要なアイテム

最もオーソドックスなやり方は、ホワイトボードと付箋を使うやり方です。

ホワイトボードへの準備

まず、ホワイトボードの中心に縦線を引きます。次に左側の中心に横線を引きます。左上スペースにKEEP、左下スペースにPROBLEM、右スペースにTRYとマーカーで記入します。

KEEPTRY
PROBLEM

↑こんなかんじ。

振り返り手順

準備ができたら、KEEP⇒PROBLEM⇒TRYの順番で振り返りを実施します。

付箋書き書きタイムを設ける

この際、KEEP、PROBLEM、TRYの各振り返りのフェーズごとに、五分ほどの時間をとって付箋記入タイムを作ります。そして、付箋記入タイミング後、書いた付箋をホワイトボードに貼りだしていくわけです。

ホワイトボードに貼りだした付箋をもとに、わいわいする

貼りだす際は、進行者が似た付箋ごとである程度グループ化してあげると、より俯瞰がしやすくなります。また、貼りだした内容について各自が色々コメントしていくと(全部にコメントしていると時間がなくなると思うので、臨機応変に)盛り上がります。

 KPTの利点

利点1 : 声なき声を拾える

まずは、KPTというより、振り返り自体の効能について。

普段なかなか共有できない各人の感じている思いを、共有することができます。「何か懸念点はあるか」と漠然と問いかけるよりは、フォーマットを提示した方がアウトプットしやすくなります。そのフォーマットのひとつとして、KPTが有用です。

利点2 : we vs problem の構図を作れる

こちらは、KPTというよりホワイトボードを利用する利点です。

問題が人から切り出されて、ホワイトボードという形に可視化されるため、いわゆるwe vs problemの構図を作りやすくなります。人 vs 人になると不毛なので。個人攻撃ではなく、問題を解決するべきです。そのためにこの図式を意識することは有用です。

これは何もホワイトボードに限らず、プロジェクタで映し出したexcelファイルでもいいし、evernoteでも同じことです。要は、皆が一同に見えるもので、かつ、個人から切り離されていればよいかと思います。

利点3 : 「KEEP」の存在

振り返りというと、ついつい問題点ばかりがクローズアップされがちです。しかし、KPTはまずKEEPの洗い出しから始める点が秀逸です。これによって、(1)出だしがポジティブになり、振り返り自体が生産的な場になりやすくなる。(2)忘れがちなプロジェクトの価値を再認識できる――などの効果があります。

(1)の効果があるため、KPTの実施順は是非ともKEEPから始めた方が良いように思われます。

利点4 : 「KEEP」「PROBLEM」を受けての「TRY」である点を可視化できている

KPTは「続けたいこと」「改善したいこと」、その止揚としての「次からこうしようぜ」の三つから成り立つ非常にシンプルな振り返り方法です。

にもかかわらず、KEEPとPROBLEMを左、TRYを右に配置することで、TRYが左のKEEPとORBLEMを精査した上での止揚であることが明示できていることが素晴らしい。「良い点がこれだけありました。改善点がこれだけありました。だから、次はこうしましょう」のストーリーがたった二本の線で表現できるのは、白眉です。

利点5 : アウトプットが他人の影響を受けない

最初に付箋を記入している段階では、互いがどんなことを書こうとしているかが見えないため、他人の意見に影響されずに済みます。「個人の意見を吸い出すタイミング」「それを共有するタイミング」が両方存在するのは、大きなメリットではないでしょうか。

(もちろん、他人の意見が起爆剤となった発想が湧く場合もあるかと思うので、そういう場合は、思いついた段階で付箋を足していってもいいのではないでしょうか)

 KPTのカスタマイズ案

以下は、KPTを実践して思ったカスタマイズ案

ホワイトボードではなく、プロジェクタを使いたいかもしれない

今回、付箋の文字が小さすぎたり読みづらかったりしたために、メンバーがホワイトボード上の付箋を判読できない問題が発生しました。

ホワイトボードとの距離の近さによってミーティングのイニシアチブに差が生まれるのは、あまり好ましいことではありません。なので、次からはプロジェクタを使って、事前に書き込んでもらった共有ファイルを映す形も検討しようかなと考えています。(書き込む時間を会議外に持てるので、振り返り自体の時間短縮にもつながります)

ただ、そのままやると、上記にあげたKPTの利点をいくつか潰すことになってしまうので、やり方を考えねばなりません。その辺りは、また書く機会があれば、いずれ。

PROBLEMをPROBLEM(WISH)としたい

これは以前からKPTをやるたびに思っていたことなのですが。KPTはKEEP(続けていきたいこと)、PROBLEM(改善したいこと)の観点しかないため、ふと思いついた次からやりたいことをどこに含めればよいか迷ってしまいます。TRYに書いてもいいのですが、できればTRYは「左の内容を精査したもの」という位置づけを保ちたいです。

そこで左下の「PROBLEM」を「PROBLEM(WISH)」として、突発的なやりたいことはここに書いたらどうかと思います。

「次から~したい」という思いは、いわば「今~できていない」の裏返しです。なので、WISHという観点をPROBLEMの中に含めることで、PROBLEMがよりポジティブで生産的なものになりやすくなる効果もあるのではないかと、勝手に思っています。

IDCF オブジェクトストレージを利用したMySQLのバックアップ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

rickNo39です。
IDCフロンティアでは、スナップショットという機能がありますが、対象ディスク全てが対象となりサイズと時間で従量課金となるため、オブジェクトストレージ(の無料枠)を利用して対象ファイルだけバックアップを行った設定を記載します。

事前設定

使用するミドル

  • logrotate
  • mysql

料金プラン

50GBまで無料、10TBまでの定額プラン有
136.7GBまで保存すると定額プランのほうがお得になってくるようです。

オブジェクトストレージへ送信・削除

vim /etc/logrotate.d/mysql-dump
—–
/extdisk1/dump/*.sql {
create 600 mysql mysql
daily
rotate 7
size 0
missingok
dateext
compress
create 444
postrotate
mysqldump -uroot -h localhost –single-transaction –opt –all-databases > /extdisk1/dump/dump.sql
endscript
lastaction
// 圧縮したdumpをオブジェクトストレージに送信
s3cmd put /extdisk1/dump/dump.sql-`date ‘+%Y%m%d’`.gz s3://バケット名
// logrotateでは当日分圧縮してくれないので自分で圧縮
cp /extdisk1/dump/dump.sql /extdisk1/dump/dump.sql-new
gzip /extdisk1/dump/dump.sql-new
// 当日分のdumpもオブジェクトストレージへ送信
s3cmd put /extdisk1/dump/dump.sql-new.gz s3://バケット名
// 6日前(実質7日前)のdumpを削除
s3cmd del s3://バケット名/dump.sql-`date -d ‘6 day ago’ ‘+%Y%m%d’`.gz
endscript
}
—-

容量確認のメール送信

日々容量を確認するのも手間なので、
下記のようなシェルを作成しcronで設定してメールを送るようにします。
vim object_storage_consumption.sh
—-
#!/bin/bash
PID=$!
TIMER=1
HOSTNAME=”hoge@hoge.com”
ADDRESS=”hoge@hoge.com”
DATA=`timeout -s 9 60 s3cmd du -H`
if [ -n “$DATA” ]; then
BODY=”IDCF オブジェクトストレージ使用量\n$DATA\n50GBから有料、136.7GBを超える場合はプラン変更”
echo -e “$BODY” | /usr/bin/mail -s ‘IDCF Object storage consumption’ -r $HOSTNAME $ADDRESS
echo “s3cmdからデータを取得できませんでした。”
fi
—-

たまに?オブジェクトストレージのレスポンスがやたら遅くてメールの中身が途中で途切れることもありますが、気にしない。

以上、とっても簡単バックアップ方法でした。

【Oracle】トリガーの状態とエラー内容の確認方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

トリガーを作成したは良いけど動作しない。

そんな時はトリガーの状態とエラー内容を確認してみましょう。

※注)以下はMacの設定となります

 メソッドジャンプ

command + R

Eclipseではcommandを押したままメソッドをクリックすると宣言元のメソッドにジャンプできる機能があります。

Atomの場合、似たような機能としてcommand + Rでメソッドを検索できます。

Eclipseに比べると若干不便ですが、Atomはスクリプト系の言語で使われることが多く、定義位置の解析が難しいらしいので仕方ないのかもしれません。

 Eclipse風テーマ

テーマ:Atom Light

Atomのデフォルトのテーマは背景が黒ですが、Eclipseに近づけるため背景が白のAtom Lightに設定変更します。

Atom->環境設定->テーマ->

 インターフェーステーマ:Atom Light

 シンタックステーマ:Atom Light

 文字サイズ小さくする

フォントサイズ:12

デフォルトだと文字サイズが少し大きめですので、小さくします。

Atom->環境設定->設定->

 フォントサイズ:12

 不可視文字を表示

この設定はEclipseでもデフォルトでは無いですが、個人的にあったほうが良いと思う設定です。

Atom->環境設定->設定->

 ■不可視文字を表示

次回、パッケージ編に続きます

VirtualBoxを使ってjenkinsを動かした際のメモ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

以前、railsでスマホ用アプリを作成する際、

rspecテストなどを自動で走らせたいという事で、

rails環境を構築した仮想OS上に、jenkinsを入れて動かそうとし,

ハマった部分についてのメモです。

jenkinsとは

Javaによって書かれた「オープンソース継続的インテグレーションツール」。

様々なプラグインを使用する事によって、継続的にジョブを監視したり、ビルドをしたりすることができます。

railsと合わせて、自動的にrspecのテストを行わせる目的で入れようとしました。

(今回仮想環境にjenkinsを入れる事が目的となる為、詳しい使用方法などは割愛)

 Jenkinsのインストール

仮想環境

・VirtualBox

・CentOS 6.6

# yum -y install java-1.7.0-openjdk wget
# wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
# rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
# yum -y install jenkins

 Jenkinsの起動

# service jenkins start
# chkconfig jenkins on

以上で、http://サーバーのIPアドレス:8080/(初期設定)にアクセスすればJenkinsのトップ画面が表示されるはずでしたが、ip接続がうまくいかず、表示されませんでした。

 仮想OSのサーバipアドレスを確認する

VirtualBoxの メニュー>環境設定>ネットワーク

で、ネットワーク名が表示される。

各ネットワーク名を右クリック>編集で、IPv4のアドレス/ネットマスクが見れるので、それらをメモします。

そして、CentOS内の/etc/sysconfig/network-scripts/ifcfg-eth0を、メモしたipアドレス・ネットマスクに書き換えます。

例えば、ipアドレスとマスクが「166.166.66.6/255.255.255.0」だったとしたら、以下のように。

IPADDR=166.166.66.6
NETMASK=255.255.255.0

これで再度、networkをリスタートして、ホストOSのブラウザからアクセスすると、

jenkinsのトップ画面が表示されました。。

ブラウザからJenkinsにプラグインがインストールできないとき

上記の操作で、ブラウザでJenkinsが確認出来ても、

ブラウザ上での操作から、プラグインのインストール等が出来ないことがありました。

その場合、仮想環境がネットワークにつながっていない場合があります。

VirtualBoxのアダプターの設定を見直して、

・アダプター1:ホストオンリーアダプタ

・アダプター2:NAT

になっているかを確認します。

自分の場合、アダプタ設定が逆になっていたので、正しく戻したらきちんとブラウザからインストールできるようになりました。

svn moveを試してみる

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ブランチをトランクにするために、svn moveをローカルで検証してみました。

 svn moveって何?

svn moveコマンドは、作業コピーやリポジトリにある、ファイルやディレクトリを移動することができます。

※内部的には、svn copyの後にsvn deleteを行っている模様

※以下の手順のパス等は、Mac環境のものです。

 事前準備(検証用のデータを作成)

リポジトリ作成

$ cd
$ mkdir -p Documents/svn/repos
$ svnadmin create Documents/svn/repos
$ svn mkdir file://localhost/Users/hoge/Documents/svn/repos/trunk -m "create directory trunk"
$ svn mkdir file://localhost/Users/hoge/Documents/svn/repos/branches -m "create directory branches"
$ svn mkdir file://localhost/Users/hoge/Documents/svn/repos/tags -m "create directory tags"

チェックアウト

$ cd Documents/svn
$ mkdir working-copy
$ cd working-copy
$ svn co file://localhost/Users/hoge/Documents/svn/repos/trunk

コミット

トランク見分けるためファイルをコミットします。

$ cd trunk
$ touch trunk.txt
$ vim trunk.txt
---- ここから ----
trunk!
---- ここまで ----
$ svn add trunk.txt
$ svn ci trunk.txt -m 'create trunk.txt'

ブランチ作成(URL -> URL)

$ svn copy file://localhost/Users/hoge/Documents/svn/repos/trunk file://localhost/Users/hoge/Documents/svn/repos/branches/branch -m 'create new branch'
$ svn ls file://localhost/Users/hoge/Documents/svn/repos/branches
branch/
$ svn ls file://localhost/Users/hoge/Documents/svn/repos/branches/branch
hoge.txt
trunk.txt

ブランチチェックアウト

$ cd ../working-copy
$ svn co file://localhost/Users/hoge/Documents/svn/repos/branches/branch
A    branch/trunk.txt
Checked out revision 5.

ブランチを区別するコミット

$ cd branch
$ touch branch.txt
$ vim branch.txt
---- ここから ----
branch!
---- ここまで ----
$ svn add branch.txt
$ svn ci branch.txt -m 'create branch.txt'

 svn move検証

いよいよ本題のsvn moveの検証です。

①branch -> tagsにコピー

バックアップのためブランチをtagsにコピーします。

$ svn copy file://localhost/Users/hoge/Documents/svn/repos/branches/branch file://localhost/Users/hoge/Documents/svn/repos/tags/branch_snapshot -m 'create tags branch_snapshot'
$ cd ..
$ svn co file://localhost/Users/hoge/Documents/svn/repos/tags/branch_snapshot
$ cd branch_snapshot/
$ ls
branch.txt trunk.txt
$ cat branch.txt
branch!
$ cat trunk.txt
trunk!
$ svn log
------------------------------------------------------------------------
r7 | hoge | 2015-12-24 15:45:45 +0900 (水, 24 12 2015) | 1 line

create tags branch_snapshot
------------------------------------------------------------------------
〜省略〜
→copy時点のbranchのファイルとリビジョン履歴がコピーできている。OK

②trunk -> tagsにmove

バックアップのためトランクをtagsに移動します。

$ svn move file://localhost/Users/hoge/Documents/svn/repos/trunk file://localhost/Users/hoge/Documents/svn/repos/tags/trunk_snapshot -m 'create tags trunk_snapshot'

trunk-snapshotが出来ているか

$ svn ls file://localhost/Users/hoge/Documents/svn/repos/tags/branch_snapshot/
trunk_snapshot/
→OK

trunkが消えていること

$ svn ls file://localhost/Users/hoge/Documents/svn/trunk
svn: Unable to open an ra_local session to URL
svn: Unable to open repository 'file://localhost/Users/hoge/Documents/svn/trunk'
→OK

trunk_snapshotをcoしてファイル(trunk.txtのみ)とリビジョン履歴確認

$ cd ..
$ svn co file://localhost/Users/hoge/Documents/svn/repos/tags/trunk_snapshot
A    trunk_snapshot/trunk.txt
Checked out revision 8.
$ cat trunk_snapshot/trunk.txt
trunk!
$ svn log trunk_snapshot/
------------------------------------------------------------------------
r8 | hoge | 2015-12-24 15:55:16 +0900 (水, 24 12 2015) | 1 line

create tags trunk_snapshot
------------------------------------------------------------------------
r4 | hoge | 2015-12-24 15:36:01 +0900 (水, 24 12 2015) | 1 line

create trunk.txt
------------------------------------------------------------------------
r1 | hoge | 2015-12-24 15:33:03 +0900 (水, 24 12 2015) | 1 line

create directory trunk
------------------------------------------------------------------------
→OK

③branch -> trunkにmove

ブランチをトランクに移動します。

$ svn move file://localhost/Users/hoge/Documents/svn/repos/branches/branch file://localhost/Users/hoge/Documents/svn/repos/trunk -m 'create trunk move branch'

trunkが出来ているか

$ svn ls file://localhost/Users/hoge/Documents/svn/repos/trunk
branch.txt
trunk.txt
→OK

branchが消えていること

$ svn ls file://localhost/Users/hoge/Documents/svn/branches/branch
svn: Unable to open an ra_local session to URL
svn: Unable to open repository 'file://localhost/Users/hoge/Documents/svn/branches/branch'
→OK

trunkをcoしてファイル(trunk.txtとbranch.txt)とリビジョン履歴確認

$ cd ~/Documents/svn/working-copy
$ svn co file://localhost/Users/hoge/Documents/svn/repos/trunk trunk_moved
$ cat trunk_moved/trunk.txt
trunk!
$ cat trunk_moved/branch.txt
branch!
$ svn log trunk_moved/
------------------------------------------------------------------------
r9 | hoge | 2015-12-24 16:06:14 +0900 (水, 24 12 2015) | 1 line

create trunk move branch
------------------------------------------------------------------------
r6 | hoge | 2015-12-24 15:40:30 +0900 (水, 24 12 2015) | 1 line

create branch.txt
------------------------------------------------------------------------
r5 | hoge | 2015-12-24 15:36:56 +0900 (水, 24 12 2015) | 1 line

create branch from trunk
------------------------------------------------------------------------
r4 | hoge | 2015-12-24 15:36:01 +0900 (水, 24 12 2015) | 1 line

create trunk.txt
------------------------------------------------------------------------
r1 | hoge | 2015-12-24 15:33:03 +0900 (水, 24 12 2015) | 1 line

create directory trunk
------------------------------------------------------------------------
→OK

ちゃんとブランチにコミットしたファイルが存在し、ログも問題なさそうですね。

以上です。

Rails ブラウザバックでどうやってもjsのイベントが取れない件

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ブラウザバックでページ遷移した時に起こる不具合は意外とたくさんあることに気づくポッキーの日。その1つとしてjsのイベントがどうやっても取れない現象に出くわしたので、その時の対処法をメモとして残しておきます。

きっかけ

ブラウザバックした際、デザインが崩れてしまう不具合が報告されたので調査することに。デザイン崩れの原因が2つの特定条件の時に起こるみたい。

・スマホ端末とタブレット端末のみ
・端末を縦横に向きを変えて任意のページからブラウザバックした時に起こる

ちなみにリロードすると元に戻る。デザイン崩れが発生しているのがjsのプラグインを使っている箇所だったのでソースを見ても訳分からない..。なのであまり良くないですが、デザインが崩れるページに戻った際はリロードして崩れないようにしようと思いました。

原因と対応

結論から言うと、この不具合の根本原因はturbolinksによる影響でした。
ページロードの高速化(これしか知らない)などのメリットがあるけど、デメリットの方が多いと言われるturbolinks..。実際にデメリットの部分を実感できたのでまぁぁ良しとしましょう。

turbolinksの影響だと気づいていない時にブラウザバックでイベントを取得する方法をいろいろ探してたら、このイベント(下記に記載)なら取れるよ!って言う記事がたくさんあったのですが、turbolinksの前では全く効果ありませんでした。

$(window).load(function(){});
$(window).onload(function(){});
$(window).unload(function(){});
$(window).pageshow(function(){});
$(window).onpageshow(function(){});

参考: iOS ブラウザバック時にリロードさせる (javascript)

turbolinksを無効にすれば手っ取り早いですが

#app/assets/javascripts/application.js
//= require turbolinks   #これを削除

そうもいかず路頭に迷ってたら見つけました、turbolinksが提供しているイベントが!
ブラウザバック時に以下のイベントを取得することができるみたい。

page:before-unload
page:change
page:update
page:restore

参考: infinite scrollとRails4のTurbolinks

結果としてこの記述でブラウザバックした時にページリロードすることができました。

$(document).on 'page:restore', ->
  location.reload();

他にもturbolinks絡みの不具合を経験したので嫌いになりかけていましたけど(もう使いたくない)、便利なところもあるのでうまく共存していきたいですね..。turbolinksについて、そもそもturbolinksって何?だったりメリットデメリット、使っていく上で気をつけるべきことなのがわかりやすい記事があったので載せておきます。

参考: 今更ながらTurbolinksを初めて仕事で使ってみたので色々調べてみた

記憶の固執 dalli をDBレコードに使ったときのメモ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Webアプリを高速化するのに memcached を使うことがある。

今回は Ruby on Rails 上で memcached 簡単に行うことができる gem に dalli を使ったときのメモ。

 環境

OS (cat /etc/redhat-release )

CentOS Linux release 7.1.1503 (Core)

kernel (uname -r)

3.10.0-229.1.2.el7.x86_64

memcached

rpm -qa memcached
	memcached-1.4.15-9.el7.x86_6

ruby

ruby -v
	ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]
	rails -v
	Rails 4.2.2
	gem list pry
	
	 LOCAL GEMS ***
	
	pry (0.10.1)
	pry-rails (0.3.4)
	
	gem list dalli
	
	 LOCAL GEMS ***
	
	dalli (2.7.4)

 dalli インストール例

dnf install memcached

gem install dalli

 rails アプリケーションの設定ファイルの記載

config/environments/development.rb に下記行を追記。

※ 本番環境なら config/environments/production.rb

config.cache_store = :dalli_store

 基本的な使い方

キャッシュを作成する

Rails.cache.write(key, obj)

キャッシュを読み込む

Rails.cache.read(key)

キャッシュがあれば読み込み、なければ作成し読み込む

Rails.cache.delete(key)
	Rails.fetch(key, obj,  expires_in: cache_tol_sec) do
	  obj
	end

※ キャッシュの寿命を指定するには write や fetch の第3引数に秒数を指定する。

 気をつけること

ひとつのキーでひとつの値を保持するのでdevlopmentや test など複数環境で使用することを考慮しておく。

テーブル名や引数、sql文などをキーにしているときにテスト実施後に開発環境で表示不具合が発生した。memcache はキーバリューなので不自然でないが rails の開発時に環境ごとの db の切り替えに気を使ったコーディングをすることが少ないので注意。この度はキーに “#{Rails.env.first}_” の接頭辞をつけるようにして解決。

キーはシンボルで指定しても文字列で作成されるので意図せぬ書き換えに注意。

Rails.cache.write(:key_str, obj1)
	Rails.cache.write('key_str', obj2)

Hash と異なる。

DBレコードごとにキャッシュを作成する場合、レコードの更新・削除にあわせてキャッシュも更新すること。

after_save や after_destroy などを使うとよいかも。

【Rails】フォームの要素を動的に追加・削除 〜JSON編〜【jquery】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

フォームの要素を追加・削除する機能がよくあるので作成方法をまとめます。

例として作る機能

特徴や内容量などにつかいそうなフォーム。今回はプロパティという名前で作成。

Modelにメソッド追加

	    def properties
	      parse_property = JSON.parse(property) # propertyに不正な値が入っていた場合に例外発生する
	      return [] unless parse_property.is_a?(Array) && parse_property.all? { |prop| prop.is_a?(Hash) }
	      parse_property
	    rescue
	      []
	    end
	

Helperにメソッド追加

	      def add_property_button_tag(name)
	        fields = render 'property_fields', property_key: nil, property_value: nil
	        button_tag(name, type: :button, class: 'add_property btn btn-default pull-right', data: { fields: fields.delete("\n") })
	      end
	

View (_form.slim)

	  fieldset
	    .col-md-3
	      legend プロパティ
	
	    .col-md-9
	      .form-group
	        / 入力フィールド
	        table.table#properties
	          - @モデルのインスタンス.properties.each do |property|
	            = render 'property_fields', property_key: property['property_key'], property_value: property['property_value’]
	        / 実際に値が入るフィールド↓
	        = f.hidden_field :property
	
	        / 追加ボタン
	        = add_property_button_tag 'プロパティ追加'
	

View (_property_fields.slim)

	tr.property
	  td
	    = text_field_tag nil, property_key, id: nil, class: :property_key
	  td
	    = text_field_tag nil, property_value, id: nil, class: :property_value
	  td
	    button.btn.btn-default.pull-right.remove_property type="button"
	      = '削除'
	

coffee script

	class クラス名
	  constructor: ->
	    @properties = $('#properties')
	    @add_property = $('.add_property')
	
	    @add_event_to_property()
	
	  # イベント設定
	  add_event_to_property: ->
	    @properties.on('change', 'input', @reset_property)
	    @properties.on('click', '.remove_property', @remove_property)
	    @properties.on('click', '.remove_property', @reset_property)
	    @add_property.click(@adding_property_field)
	
	  # hiddenフィールドに入れる値設定
	  reset_property: =>
	    property_attrbutes = $('.property').map( (_index, property) ->
	      property_key = $(property).find('.property_key').val()
	      property_value = $(property).find('.property_value').val()
	      return unless property_key && property_value
	      {
	        'property_key': property_key,
	        'property_value': property_value
	      }
	    )
	    # JOSN形式で保存
	    @property.val(JSON.stringify(property_attrbutes.get()))
	
	  # 削除
	  remove_property: ->
	    $(this).closest('tr').remove()
	
	  # 追加
	  adding_property_field: ->
	    field_tags = $(this).data('fields')
	    $field = $(field_tags)
	    $('#properties').append($field) # タグを追加
	

保存した値

	$ rails c
	2.2.0 :002 > モデルインスタンス.property
	 => "[{\"property_key\":\"高さ\",\"property_value\":\"10cm\"},{\"property_key\":\"横幅\",\"property_value\":\"20cm\"},{\"property_key\":\"重さ\",\"property_value\":\"100g\"}]”
	
	2.2.0 :003 > モデルインスタンス.properties
	 => [{"property_key"=>"高さ", "property_value"=>"10cm"}, {"property_key"=>"横幅", "property_value"=>"20cm"}, {"property_key"=>"重さ", "property_value"=>"100g”}]
	
	

checkboxとlabelの変な現象

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

railsで、checkboxとlabelの組み合わせで、チェックボックスが反応なしの現象が起こりました。

調査しにくいので、共有したいと思います。

 現象

チェックボックスをクリックしても、チェックされなくて、反応なしです。

 開発環境

Rails 4.1.4

ruby 2.1.2p95

viewテンプレート: erb

 lable forとは

<lable for="ID属性値">タグを使用すると、
<lable>タグの開始タグと終了タグに挟まれた文書が、
ID属性の属性値として「ID属性値」と同じ値が書き込まれた部品と、関連付けされます。

 発生状況

<%= check_box_tag '/feature_ids[]'/, feature.id, feature_ids.include?(feature.id), 
id: "feature_id_1_#{ feature.id }", class: "g_1" %>
<lable for="<%= " feature_id_#{ feature.id }" %>"><%= feature.name %></lable>

checkboxのID:feature_id_1_#{ feature.id }

lableのfor:   feature_id_#{ feature.id }

checkboxのIDを修正し、lableのforを修正し忘れたため、現象が起こりました。

 対処

lableのforの値はcheckboxのidと一致します。

※関連付けるために、値は一致しないのは正しくないですが、

まさかチェックボックス動作に影響するのは思いませんでした。

RailsのViewを自在にカスタマイズするための「Cosme」gem

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

既存のViewに手を加えずカスタマイズするためのRails向けgem「Cosme」を紹介します。

 はじめに

Railsには便利なgemがたくさんあり、この中にはロジックだけでなく画面のデザインであるViewを含んだものが数多くあります(たとえばActiveAdminやDevise、Comableなど)。これらをこのまま利用できれば楽ですが、認証のための項目を増やしたいとか商品価格の横には定価を載せたいとか、やりたいことが増えてくるとその一部に手を加えたくなるケースが少なからずあります。

通常Viewは一部分だけを変更することが不可能で、カスタマイズを行う場合はファイルを丸ごと置き換える形で対応することになります。ただしこの手法には、gemのバージョンアップの際にViewの更新を追うことができなくなってしまう、という欠点があります。

今回はこの欠点を補いつつ既存のViewをカスタマイズするためのgem「Cosme」を紹介します。

 使い方

1. gemのインストール

bundlerを利用している場合は下記の行を Gemfile に追加します。

gem 'cosme'

2. JavaScriptライブラリの読み込み

※ v0.4.0 からこの操作は不要になりました。

`app/assets/javascripts/application.js` に下記の行を追加します。

//= require cosme

3. ヘルパメソッドの組み込み

※ v0.2.0 からこの操作は不要になりました。

`app/views/layouts/application.html.erb` の <body> タグ直下に下記の行を追加します。

<%= cosmeticize %>

4. カスタマイズ内容を定義

カスタマイズ用のViewとメタ情報を記載した設定ファイルを `app/cosmetics` ディレクトリに設置します。

カスタマイズの定義を行うために `Cosme.define` というメソッドを呼び出します。

「target」はカスタマイズ対象で、jQueryのHTMLセレクタと同じ役割を果たします。

「action」はカスタマイズ方法で、「before」「after」「replace」をいずれかを指定します。

# app/cosmetics/after_example.rb
Cosme.define(
  target: '.example',
  action: :after
)
<%# app/cosmetics/after_example.html.erb %>
<h2>After Example</h2>

 結果

これで、すべての `example` というCSSクラスを持つHTML要素の後に「After Example」と表示されるようになりました。

例えば `app/views/layouts/application.html.erb` が下記のように `example` クラスを持つ要素を含んでいたとすると、最終的には「Example」のあとに「After Example」が表示されるようになります。

<%# app/views/layouts/application.html.erb %>
<html>
  <head>
    <title>Example</title>
    <%= stylesheet_link_tag '/application'/, media: '/all'/ %>
    <%= javascript_include_tag '/application'/%>
  </head>
  <body>
    <div class="example">
      <h1>Example</h1>
    </div>
  </body>
</html>

上記の結果、<body> タグ内は下記のようになります。

<div class="example">
  <h1>Example</h1>
</div>
<h2>After Example</h2>

 しくみ

CosmeはHTMLの置換処理を JavaScript 上で行っています。そのため動作速度や非JavaScript環境での動作を求める方にはあまりオススメできません。その一方でとてもシンプルな実装になっているためすべてのテンプレートエンジンに柔軟に対応できます。

同じことを実現できる「deface」というgemがありますが、こちらはActionViewを拡張することで実装されているため対応テンプレートエンジンが限定されており、またその一部にバグがある*1状態です(*1 2015/10/1現在: slimにおいてブロック内の要素がHTMLエスケープされてしまう https://github.com/spree/deface/issues/133 )。ただし、動作速度を求めていてバグにも引っかからない場合はこちらのgemをオススメします。

 おわりに

今回はViewのカスタマイズに便利なCosmeというgemを紹介しました。

追加機能の要望や不具合の報告は こちら にリクエストすると中の人が対応してくれるかもしれません。

 関連リンク

Cosme :: https://github.com/appirits/cosme

Deface :: https://github.com/spree/deface

 改訂

  • 2015/10/18 :: v0.4.0へのバージョンアップに伴い、スクリプトの組み込みが不要になりました。
  • 2015/10/09 :: v0.2.0へのバージョンアップに伴い、ヘルパメソッドの組み込みが不要になりました。

IDCF keepalivedを使用したグローバルIPとローカルIPの紐付け

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

rickNo38です。
IDCフロンティアでhttp/httpsのアクセス先を冗長化するため
keepalivedを使用するために行った設定を記載いたします。

用意するもの

・IDCF契約(仮想サーバ2台以上)
・グローバルIP1個(IDCF管理画面上はIPアドレス)
・実施したOSはCentOS7

冗長化を行う理由

用意されているルーターを使用するとhttpsの場合、アクセス元IPが取得できなくなります。
そのため、ルーターを返さず直接apache等で受け取る必要があります。
また、冗長化していないと安全性が低いため冗長化も必用となってきます。

APIコマンドinstall

keepalivedでの冗長化を実現するためには、
管理画面上の設定では不可能なため、
APIをinstall必要があります。
設定するのはmasterサーバの1台だけです。su – curl -kL https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python
yum -y install libxml2 libxml2-devel libxslt libxslt-devel gcc python-devel
pip install git+https://github.com/idcf/cloudstack-api
cloudstack-api –version
—–
cloudstack-api v0.10.2
—–

API設定

vim ~/.idcfrc
—–
[account]
host=エンドポイント
api_key=API Key
secret_key=Secret Key
—–
chmod 600 ~/.idcfrc
# 下記表示されればok
cloudstack-api listZones
—–
{
“listzonesresponse”: {
“count”: 3,
“zone”: [
{
“allocationstate”: “Enabled”,
“dhcpprovider”: “VirtualRouter”,
“id”: “xxxx”,
“localstorageenabled”: true,
“name”: “tesla”,
etc…
—–

サーバに2個目のIPを付与

# 仮想マシンIDの確認
cloudstack-api listVirtualMachines -t displayname,id
—–
+————–+————————————–+
| displayname | id |
+————–+————————————–+
| test | 1234567890 |
—–
# NICの確認
cloudstack-api listNics –virtualmachineid 1234567890
—–
{
“listnicsresponse”: {
“count”: 1,
“nic”: [
{
“gateway”: “10.3.0.1”,
“id”: “abvdefg”,
“ipaddress”: “10.3.0.2”,
“isdefault”: true,
“macaddress”: “xx:xx:xx:xx:xx”,
“netmask”: “xxx.xxx.xxx.xxx.xxx”,
“networkid”: “xxxxxxx”
}
]
}
}
—–
# サーバにIPを付与
cloudstack-api addIpToNic –nicid abvdefg –ipaddress 10.3.0.3
# secondaryipが指定されているか確認
cloudstack-api listNics –virtualmachineid 1234567890
—–
{
“listnicsresponse”: {
“count”: 1,
“nic”: [
{
“gateway”: “10.3.0.1”,
“id”: “abvdefg”,
“ipaddress”: “10.3.0.2”,
“isdefault”: true,
“macaddress”: “xx:xx:xx:xx:xx”,
“netmask”: “xxx.xxx.xxx.xxx.xxx”,
“networkid”: “xxxxxxx”
“secondaryip”: [
{
“id”: “zxcvasdf”,
“ipaddress”: “10.3.0.3”
}
]
}
]
}
}
—–

NAT設定

# グローバルIPのリスト取得
cloudstack-api listPublicIpAddresses -t ipaddress,id
—–
+—————–+————————————–+
| ipaddress | id |
+—————–+————————————–+
| 210.140.111.111 | aaaaaa |
——
# ローカルIPとグローバルIPのNAT設定
cloudstack-api enableStaticNat –ipaddressid aaaaaa –virtualmachineid 1234567890 –vmguestip 10.3.0.3
管理画面メニューのIPアドレスから「210.140.111.111」がNAT設定されているか確認できます。

keepalived設定

後は普通にkeepalivedの設定をするだけです。

RailsでEnumerizeの使い方

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

railsのModelで列挙型を扱うのに、gemのenumerizeが便利です。

enumerizeについて、幾つかの使い方を紹介したいと思います

 gem

gem ‘enumerize’

 モデル

class User < ActiveRecord::Base
  extend Enumerize

  enumerize :sex, in: [:male, :female]  #配列
  enumerize :role, in: {:user => 1, :admin => 2}  #ハッシュ
end

これだけでsexに対するinclusionのバリデーションがかかる

エラーメッセージ

性別は一覧にありません。

 ja.yml

ja:
  enumerize:
    user:
      sex:
        male: 男
        female: 女
      role:
        user: 会員
        admin: 管理者

 使い方

User.sex.values  # => ["male", "female"]
User.sex.options # => [["男", "male"], ["女", "female"]]

※もしフィールド名はnameの場合、User.nameはUserモデルのメソッドのため、enumerized_attributesを利用する
User.name  # => "User"
User.enumerized_attributes[:sex].values # => ["male", "female"]
User.enumerized_attributes[:sex].values # =>  [["男", "male"], ["女", "female"]]

user = User.new
user.male?   # => false
user.female? # => false
user.sex = 'male'
user.male?   # => true
user.female? # => false
user.sex_value # => "male"
user.sex_text # => "男"

user.role = :user
user.role #=> 'user'
user.role_value #=> 1
user.role_text  #=>  "会員"

User.role.find_value(:user).value #=> 1
User.role.find_value(:admin).value #=> 2

 form_for

<%= form_for @user do |f| %>
  <%= f.select :sex, User.sex.options %>
<% end %>

 SimpleForm

select collection
<%= simple_form_for @user do |f| %>
  <%= f.input :sex %>
<% end %>

radio buttons
<%= simple_form_for @user do |f| %>
  <%= f.input :sex, :as => :radio_buttons %>
<% end %>

 enumerizeを使用する際、モデルのdefault値

マイグレートファイルでdefaultを指定していたとしても、モデルでenumerizeのdefaultを指定しないとnullが挿入される。

enumerize :role, in: [:user, :admin], default: :user

 ActiveRecord scopes

scope: trueを利用して、scopeとして利用できる。

class User < ActiveRecord::Base
  extend Enumerize
  enumerize :sex, :in => [:male, :female], scope: true
  enumerize :status, :in => { active: 1, blocked: 2 }, scope: :having_status
end

User.with_sex(:female)
# SELECT "users".* FROM "users" WHERE "users"."sex" IN ('female')

User.without_sex(:male)
# SELECT "users".* FROM "users" WHERE "users"."sex" NOT IN ('male')

User.having_status(:blocked).with_sex(:male, :female)
# SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."sex" IN ('male', 'female')

 参照

https://github.com/brainspec/enumerize

lambda のスコープ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

lambda というのを使ってみたのでメモです。

使い方は Proc.new と同じです。

※ ブロック内で return したときの挙動が違います。

メソッドを変数のように扱うことができます。

定義時のスコープの変数を参照するところが面白いと思いました。

 使い方

lambda ブロック

※ ブロックというのは雑にいうと do ;end や {} で囲った処理の定義のこと。

 環境

ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

Pry version 0.10.1 on Ruby 2.2.2

 使ってみました。

ブロック定義時に未定義の変数は未定義のままとなることの確認(変数を定義すると試せないので先に試します)

proc = lambda {puts i}
proc.call
出力
NameError: undefined local variable or method `i' for main:Object
from (pry):1:in `block in __pry__'
i = 3
proc.call
出力
NameError: undefined local variable or method `i' for main:Object
from (pry):1:in `block in __pry__'

標準的な使い方

i = 2
proc = lambda {puts i}
proc.call
出力
2
  • ブロック定義前に使用される変数を定義されていることがポイント

each内での挙動

i = 5
proc = lambda {puts i}
(1..4).each do |i|
  proc.call
end
出力
5
5
5
5

each内で意図した出力を試みる

i = 7
proc = lambda {puts i}
(1..4).each do |j|
  i = j
  proc.call
end
出力
1
2
3
4

for を使って見る

i = 11
proc = lambda {puts i}
for i in (1..4)
  proc.call
end
出力
1
2
3
4

直接引数を渡すときはブロック引数を使う

proc = lambda { |value|  puts value}
proc.call('引数はこれ')
出力
引数はこれ

[scala] [vim] vimでSnakeCaseとcamel_caseとを変換する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

RailsとPlayで同一のDBを参照した環境で開発している場合には、この変換を機械的にできると便利

 本記事の対象者

・RailsからもPlayからも同一のDBに対してアクセスするモジュールをvimで開発している。

 RailsとPlayのいずれでも開発しているときの問題点

  • Railsの推奨は、キャメルケース(単語間をアンダーバーで区切る)
  • Playの推奨は、スネークケース(単語間の文字の先頭を大文字にする)

特にDBのカラム名を扱うとき、Rails側ではキャメルケースで書き、Play側ではスネークケースで書くことになり、双方のコードの編集を行き来しているとキャメルケースとスネークケースとを機械的に変換したくなる。

 対応方法

vimにはキャメルケースとスネークケースとを機械的に変換するプラグインが存在する。

その1つのoperator-camelizeというプラグインを導入した。

なお、当該プラグインのベースとなるこのプラグインも必要。

 設定

「.vimrc」に

map <leader>c <plug>(operator-camelize-toggle)

と設定しておくことで、VisualModeで選択した後「\c」でキャメルケースとスネークケースとをトグル変換できる。

トグル変換が嫌な場合には、以下のように設定するとよい。

「\c」でキャメルケースへの変換。

「\C」でスネークケースへの変換。

map <leader>c <plug>(operator-camelize)
map <leader>C <plug>(operator-decamelize)

ThinReports使用に関するTips

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Ruby on RailsにてデータをPDF出力できるThinReportsを使用する際のTipsを記載する。

 プログラム的に問題なくデータ転送しているはずなのに出力されない場合に確認すべき点

項目が非表示になっている可能性があるので、確認する。

(PROPERTY => 基本 => 表示 にチェックが入っているか確認)

 レイアウトファイル上にある項目とプログラムの転送項目が一致しない場合の挙動

レイアウト:有、PG:無

レイアウトファイル上にありプログラムで転送していない項目がある場合

=> エラーにならず、項目が配置されている場所には何も表示されない。

レイアウト:無、PG:有

レイアウトファイル上になくプログラムで転送している項目がある場合

=> エラーが発生する。

 値がnilとなる可能性のあるキーを含むハッシュを指定する場合の注意

前提

  1. レイアウトファイルに「tax」という項目が配置されている。
  2. priceの基本書式(PROPERTY => 簡易書式 => 基本書式)に「{value}円」と設定されている。
  3. 「products」(商品)テーブルに「tax」カラムがあり、NULLを許可している(NULLの可能性がある)。
product = Product.find(id)
# product.taxがnilの可能性がある

report.values { price: product.tax }

taxが100の場合:「100円」と表示される。

taxがNULLの場合:「円」と表示される。

対処方法

ハッシュにcompactメソッドを介してから引数に指定する。

report.values { price: product.tax }.compact

taxが100の場合:「100円」と表示される。

taxがNULLの場合:何も表示されない。

【Rails】RailsでAjaxを使用する簡単手順【Ajax】

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

RailsでAjaxを使用する手順を簡単に説明します。

例として作る機能

選択されたユーザーの年齢が表示されるようなものを作成します。

例として使うデータ

	>> User.all
	=>[
	    #<user id: 1, name: “ユーザー1”, age: 11>,
	    #<user id: 2, name: “ユーザー2”, age: 22>,
	    #<user id: 3, name: “ユーザー3”, age: 33>
	]
	

1. routes.rbにajax用のアクションを追加

vim config/routes.rb

	resources :users
	

	resources :users do
	  get :search_user, on: :collection
	end
	

2. controllerにajax用のアクションを追加

	def search_user
	  @user = User.find(params[:user_id])
	  render layout: false
	end
	

3. viewにタグを記述

下記の3つを記述します。

①イベントを走らせるセレクトボックス

②ユーザー名を入れる用のタグ

③jsでpostする用のフォーム

vim app/views/users/index.slim

	#select_user
	  = select :user, :name, [[“ユーザー1", 1], [“ユーザー2", 2], [“ユーザー3", 3]], include_blank: true
	
	p このユーザーの年齢
	p#user_age
	
	div style=‘display: none;’
	  = form_tag(search_user_users_path, remote: true, method: :get) do
	    = text_field_tag :user_id
	    = submit_tag
	

4.フォームをpostするjsを記述

vim app/assets/javascripts/users.coffee

	$ ->
	  # セレクトボックスが変更されたらフォームをsubmit
	  $(‘#select_user select’).change( ->
	    $user_id = $('#user_id')
	    $user_id.val($(this).val()) # 選択されたユーザーのIDをパラメータとして渡す
	    $user_id.closest('form').submit()
	  )
	

4.ajax用のアクションのview(js)を記述

vim app/views/users/search_user.coffee

	$('#user_age’).text(‘<%= @user.age %>')
	

以上で完了です。

これでセレクトボックスを変更するたびにユーザーの年齢が変更されると思います。

誤解しやすいSQL

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

プログラムコードを書く際、書く言語の文法を理解している事は重要であるが、

理解している様で実は意外と誤解しているエンジニアが(比較的)多そうな、SQLのWHERE条件について、挙動と注意点を記述する。

 前提

次の様なデータを持つテーブル「t」があるとする。

+----+------+------+
| id | a    | b    |
+----+------+------+
|  1 | NULL | NULL |
|  2 | NULL | 2222 |
|  3 | 1111 | 2222 |
|  4 | 1111 | 1111 |
+----+------+------+

このテーブルに対して、WHERE句で条件を指定して抽出するSELECT文を考える。

SELECT id FROM t WHERE /* ここに条件を記載 */;

このWHERE句が以下のパターン1-4に記述する様な内容であった場合、どのidが抽出されるか正確に想像できるであろうか。

余談

Oracle, MySQL 等、DUALが使用可能なデータベースでは、次の様に記述すれば簡単に確認ができる。

SELECT * FROM (
SELECT 1 id, NULL a, NULL b FROM DUAL UNION 
SELECT 2 id, NULL a, 2222 b FROM DUAL UNION 
SELECT 3 id, 1111 a, 2222 b FROM DUAL UNION 
SELECT 4 id, 1111 a, 1111 b FROM DUAL
) t
WHERE /* ここに条件を記載 */;

 パターン1 (通常比較)

問題

(1) a = b
(2) a <> b
(3) a < b
(4) a > b
(5) a IS NULL
(6) a IS NOT NULL

結果

(1) 4
(2) 3
(3) 3
(4) なし
(5) 1, 2
(6) 3, 4

結果から言える注意点

=, >, <>, <= を指定した場合、NULLデータはヒットしなくなる。

 パターン2 (パターン1にNOT付加)

問題

(1) NOT a = b
(2) NOT a <> b
(3) NOT a < b
(4) NOT a > b
(5) NOT a IS NULL
(6) NOT a IS NOT NULL

結果

(1) 3
(2) 4
(3) 4
(4) 3, 4
(5) 3, 4
(6) 1, 2

結果から言える注意点

NOTを付けると付けなかった場合に抽出されなかったレコードが抽出されると考えがちであるが、実際にはそうではない。

中身の比較演算子(IS NULL等も含めるとする)が逆の意味を持つ比較演算子に変化したと考えると理解し易い。

= の逆は <>
> の逆は <=
< の逆は >=
IS NULL の逆は IS NOT NULL

※即ち以下と同じになる。

(1) a <> b
(2) a = b
(3) a >= b
(4) a <= b
(5) a IS NOT NULL
(6) a IS NULL

 パターン3 (複数条件)

問題

(1) a = b AND a IS NOT NULL
(2) a = b AND b IS NOT NULL
(3) a = b OR b IS NULL
(4) a < 1111 AND b < 2222 OR a < b

結果

(1) 4
(2) 4
(3) 1, 4
(4) 3

結果から解る点

パターン1で述べた様に、=を用いるとNULLデータはヒットしなくなる(もともとIS NOT NULL を含意している)ので、「AND a IS NOT NULL」等を付け足しても結果に差は出ない。

 パターン4 (パターン3にNOT付加)

問題

(1) NOT (a = b AND a IS NOT NULL)
(2) NOT (a = b AND b IS NOT NULL)
(3) NOT (a = b OR b IS NULL)
(4) NOT (a < 1111 AND b < 2222 OR a < b)

結果

(1) 1, 2, 3
(2) 1, 3
(3) 3
(4) 4

結果から言える注意点

この結果からも解る様に、NOTを付けなかった場合に抽出されなかったレコードがNOTを付けると抽出される訳ではない((1)と(2)はパターン3では同じ結果であるがパターン4は結果が異なる)。

次の様に考えると理解し易い。

ANDやORを含む句にNOTを付けると、それぞれの比較演算子は逆の意味を持つ演算子になり、ANDはORに、ORはANDに変化する。また、ANDとORが複合している場合は、もともとANDであった条件同士の方が結合度が強くなる。

※即ち以下と同じになる。

(1) a <> b OR a IS NULL
(2) a <> b OR b IS NULL
(3) a <> b AND b IS NOT NULL
(4) (a >= 1111 OR b >= 2222) AND a >= b

 結論

NULL値が含まれるデータに対するWHERE条件は、数学的な式の結果と異なるので、誤解をし易い。特に、NOTが含まれる条件は、解釈の際に1手間増えるというだけでなく、誤解する確率を上げる事になるので、もし同じ条件でNOTを使わない記述が可能な場合は、理由がなければ使わない方が良いと言えるであろう。

最近人気な記事