ホーム ブログ ページ 40

ruby-opencvのインストール

0

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

RubyでOpenCVを使ってみたくて
gemのruby-opencvを入れてみました。

OpenCVは画像処理や画像解析ができるオープンソースのライブラリです。

http://opencv.org/http://opencv.jp/

画像の顔認識や、
動画中の特定条件に合致したコマのみキャプチャするとか
そういうことができます。
機械学習機能があるので、
学習させれば、好みの顔が写ってる画像だけ拾って来る
みたいなこともできるようです。(難しいようですが)

RubyはOpenCV公式の対象言語ではないとのことですが、
問題なく使えるとのこと。
gemもあって、わりとメジャーなようだったので
インストールしてみました。

https://github.com/ruby-opencv/ruby-opencvhttp://www.rubydoc.info/gems/ruby-opencv/frames

なかなか依存関係のバージョンが合わず一苦労だったので
以下手順メモ。・環境・OpenCVインストール

  1. ライブラリをいろいろインストール
  2. yasm のインストール
  3. x264 のインストール
  4. fdk-aac のインストール
  5. ライブラリ設定
  6. ffmpeg1.2 のインストール
  7. opencv-2.4.6.1 のインストール

・ruby-opencvインストール

■ 環境

  • CentOS6.7
  • Ruby 2.1.7(rbenv)
  • Rails 4.1.6(rbenv)

■ OpenCVインストール

1. ライブラリをいろいろインストール

# yum --setopt=group_package_types=optional groupinstall Base
# yum groupinstall "Development Tools"
# yum install http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm

# vi /etc/yum.repos.d/rpmforge.repo
※enabled=0にする

# yum -y install gtk2-devel
# yum install expat-devel
# yum install libarchive libarchive-devel
# yum install libcurl3 ※ない
# yum install qt qt-devel

# yum install gtk*
# yum install cmake28

# yum install autoconf automake make gcc gcc-c++ pkgconfig wget libtool zlib-devel
# yum install http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
※enabled=0にする

2. yasm のインストール(x264 のビルドに必要)

# cd /usr/local/src
# wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
# tar zvxf yasm-1.3.0.tar.gz 
# cd yasm-1.3.0
# ./configure
# make
# make install

3. x264 のインストール(ffmpeg のビルドに必要)

# cd /usr/local/src
# git clone git://git.videolan.org/x264
# cd x264
# ./configure --enable-shared
# make
# make install

4. fdk-aac のインストール

# cd /usr/local/src
# git clone --depth 1 git://github.com/mstorsjo/fdk-aac.git
# cd fdk-aac
# autoreconf -fiv
# ./configure
# make
# make install

5. ライブラリ設定

# export LD_LIBRARY_PATH=/usr/local/lib/
# export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig"
# echo /usr/local/lib > /etc/ld.so.conf.d/custom-libs.conf
# ldconfig

6. ffmpeg1.2 のインストール

# cd /usr/local/src
# git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
# cd ffmpeg
# git checkout -b release1.2 origin/release/1.2
# ./configure --enable-gpl --enable-nonfree --enable-libfdk_aac --enable-libx264 --enable-shared
# make
# make install

# yum --enablerepo=rpmforge install ffmpeg-devel

バージョン確認

# ffmpeg -version

7. opencv-2.4.6.1 のインストール

# cd /usr/local/src
# wget ftp://ftp.jp.netbsd.org/pub/pkgsrc/distfiles/opencv-2.4.6.1.tar.gz
# tar vxzf opencv-2.4.6.1.tar.gz
# cd opencv-2.4.6.1
# cmake28 .
# make
# make install
# ldconfig

バージョン確認

# cat /usr/local/share/OpenCV/OpenCVConfig-version.cmake

■ ruby-opencvインストール

$ vi Gemfile

以下を追記
--------------------
gem 'ruby-opencv'
--------------------

$ bundle update

インストール完了です。

以下は失敗例

・opencv-2.4.11入れた時のエラー

/usr/local/src/opencv-2.4.11/modules/highgui/src/ffmpeg_codecs.hpp:104: error: ‘CODEC_ID_H264’ was not declared in this scope

コーデック関連のライブラリでエラーがたくさんでる。。

http://code.opencv.org/issues/3986OpenCV3.0RC1で解決されたらしいですが、ruby-opencvはOpenCV3.*に対応してないのでバージョンは上げられず。

https://github.com/Itseez/opencv/issues/4940OpenCV2.4.9、2.4.10でも同様のエラーがでるぽいです。OpenCV2.4.8も別のエラーがでて結局だめでした。

とりあえず試してみる分には問題ないので
2.4.6.1でよしとしました。

bashプロンプトのカスタマイズ

0

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

bashのプロンプトが突然「-bash-4.1$」のようになってしまって
直した時に調べたメモです。

いつもは「[hoge@localhost ~]$」のように
[ユーザ名@ホスト名 カレントディレクトリ]$
の形で表示されていたのが、
突然「-bash-4.1$」となってしまいました。

何かのタイミングでデフォルト設定に戻ってしまったようです。

・フォーマットの設定
・色の設定

■ フォーマットの設定

bashのプロンプトはPS1でフォーマットを設定できます。
デフォルトは¥s-¥v¥$です。

[hoge@localhost ~]$export PS1="\s-\v\$"
-bash-4.1$

-bash-4.1$

むむ。どうも落ち着つきません。

なので、いつもどおり
[ユーザ名@ホスト名 カレントディレクトリ]$
のフォーマットで表示されるよう設定し直します。

[\u@\h \W]\$

これを設定する。

-bash-4.1$export PS1="[\u@\h \W]\$"
[hoge@localhost ~]$

直りました。
これを「/etc/profile」や「~/.bashrc」に追記しておけばOKです。

他にも設定できるフォーマットがいろいろあって、
man bashで確認できます。

PROMPTING
       When  executing  interactively, bash displays the primary prompt PS1 when it is ready to read a command, and the secondary prompt PS2 when it needs more input to complete a command.  Bash allows these prompt strings to
       be customized by inserting a number of backslash-escaped special characters that are decoded as follows:
              \a     an ASCII bell character (07)
              \d     the date in "Weekday Month Date" format (e.g., "Tue May 26")
              \D{format}
                     the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation.  The braces are required
              \e     an ASCII escape character (033)
              \h     the hostname up to the first ‘.’
              \H     the hostname
              \j     the number of jobs currently managed by the shell
              \l     the basename of the shell’s terminal device name
              \n     newline
              \r     carriage return
              \s     the name of the shell, the basename of $0 (the portion following the final slash)
              \t     the current time in 24-hour HH:MM:SS format
              \T     the current time in 12-hour HH:MM:SS format
              \@     the current time in 12-hour am/pm format
              \A     the current time in 24-hour HH:MM format
              \u     the username of the current user
              \v     the version of bash (e.g., 2.00)
              \V     the release of bash, version + patch level (e.g., 2.00.0)
              \w     the current working directory, with $HOME abbreviated with a tilde (uses the value of the PROMPT_DIRTRIM variable)
              \W     the basename of the current working directory, with $HOME abbreviated with a tilde
              \!     the history number of this command
              \#     the command number of this command
              \$     if the effective UID is 0, a #, otherwise a $
              \nnn   the character corresponding to the octal number nnn
              \\     a backslash
              \[     begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
              \]     end a sequence of non-printing characters

■ 色の設定

サーバ毎にプロンプトの色を変えておけば
どのサーバにログインしているのかわかりやすくなります。

・文字色をシアンに変える例

$ export PS1=”¥[¥e[0;36m¥][¥u@¥h ¥W]¥$¥[¥e[0m¥]”

¥[¥e[0;36m¥]~¥[¥e[0m¥]で挟まれた部分が「0;36」で指定された装飾/色になります。

この形式はANSIエスケープシーケンスというそうです。

0;36をもっと詳しく説明すると、
0と36の2つの装飾指定がされていて、

0→文字装飾なし
36→文字色をシアンにする

という意味になります。
これにさらに背景色を青にしたい、となると0;36;44となって、0と36と44の3つの装飾指定をする
という意味になります。

0→文字装飾なし
36→文字色をシアンにする
44→背景色を青にする

\[\e[0;36;44m\][\u@\h \W]\\$\[\e[0m\]

なので、最初に「¥[¥e[0;36m¥]~¥[¥e[0m¥]」挟まれた部分が…
とは言いましたが、本来は、¥[¥e[0;36m¥]以降 を「装飾無し&文字色シアン」で表示する
¥[¥e[0m¥]以降 を「装飾なし」で表示するという意味になるようです。

もっと他の装飾指定を追加することも可能です。

↓こちらのページでとてもわかりやすく説明されていました。
http://oxynotes.com/?p=5418

とりあえず↓のように設定。

$ export PS1="\[\e[0;36m\][\u@\h \W]\\$\[\e[0m\]"

これでどのターミナル開いてるか分かりやすくなりました。

FullCalendarで営業日カレンダーを作成する(小さいカレンダー)

0

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

営業日カレンダーを作成したくて、FullCalendarのオプションを色々いじって実装しました。

バージョン:fullcalendar-2.4.0

js

$(document).ready(function() {

	$('#calendar').fullCalendar({
		header: {
			left: 'prev,next today',
			center: 'title',
			right: ''
		},
		buttonText: {
			today: '今日'
		},
		dayNamesShort: ['日','月','火','水','木','金','土'],
		defaultDate: '2016-02-03',
		businessHours: false,
		titleFormat: {
			month: 'MMM YYYY'
		},
		// 表示用データ
		events: [
			{
				start: '2016-02-09',
				rendering: 'background',
				color: '#ff9f89'
			},
			{
				start: '2016-02-06',
				end: '2016-02-08',
				rendering: 'background',
				color: '#ff9f89'
			},
			{
				start: '2016-02-13',
				end: '2016-02-15',
				rendering: 'background',
				color: '#ff9f89'
			},
			{
				start: '2016-02-20',
				end: '2016-02-22',
				rendering: 'background',
				color: '#ff9f89'
			},
			{
				start: '2016-02-27',
				end: '2016-02-29',
				rendering: 'background',
				color: '#ff9f89'
			},
		]
	});
});

eventsのデータの中で、

dayNamesShort: [‘日’,’月’,’火’,’水’,’木’,’金’,’土’]で曜日の表示を1文字にします。

rendering: ‘background’を指定することにより、そのイベントの日が背景色の表示になります。

color: ‘#ff9f89’を指定することにより、休日っぽい色にしています。

businessHours: falseで土日の背景色を無効にしています。

実際はevents部分のデータはjsonでサーバから取得していたのですが、今回は表示のテスト用にjsの中に記述しています。

css

body {
	margin: 40px 10px;
	padding: 0;
	font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
	font-size: 14px;
}

#calendar {
	max-width: 220px;
	margin: 0 auto;
}

max-width: 220px;でカレンダーのサイズを指定します。

また、デフォルトのままだとスクロールバーが出たりするので、微調整します。

css続き

.fc-basic-view .fc-body .fc-row {
	min-height: 1em !important;
}

.fc button {
	height: 2em !important;
	padding: 0 .1em !important;

	/* text & cursor */
	font-size: 0.8em !important;
}

jsのオプションでセルの高さを指定する方法がわからなかった(小さくできなかった)ので、fullcalendar.cssのスタイルを一部上書きしています。

これで冒頭の営業日カレンダーを作成することができました。

irb 上で using の動作を試したときのメモ

0

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

インスタンスメソッドを特定の場面のみ変更したい場合に using と refine を使う方法があります。irb 上でなかなか思った通りに動かなかったのでメモしておきます。

 参考 (instance method Module#refine)

http://docs.ruby-lang.org/ja/2.0.0/method/Module/i/refine.html

 環境

OS (sw_vers ; uname -a)

ProductName: Mac OS X

ProductVersion: 10.11.3

BuildVersion: 15D21

Darwin pomme.local 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64

ruby (ruby -v; irb -v ; pry -v)

ruby 2.1.9p441 (2015-12-23 revision 53262) [x86_64-darwin15.0]

irb 0.9.6(09/06/30)

Pry version 0.10.3 on Ruby 2.1.9

 使ってみました。

変更されるクラス (Enterprise) の定義

pomme:~ kadosaway$ pry
	[1] pry(main)> class Enterprise
	[1] pry(main)* def earn
	[1] pry(main)* puts "much!"
	[1] pry(main)* end
	[1] pry(main)* end
	=> :earn

変更を加えるモジュール (Strategist) の定義

[2] pry(main)> module Strategist
	[2] pry(main)* refine Enterprise do
	[2] pry(main)* def earn
	[2] pry(main)* puts 'more!!!'
	[2] pry(main)* end
	[2] pry(main)* end
	[2] pry(main)* end
	=> #<refinement:enterprise @strategist>

変更前の動作確認

[3] pry(main)> prj = Enterprise.new
	=> #<enterprise:0x007fc5788456d0>
	[4] pry(main)> prj.earn
	much!
	=> nil

変更を using によって適用しての動作確認のつもり

[5] pry(main)> using Strategist
	=> main
	[6] pry(main)> prj = Enterprise.new
	=> #<enterprise:0x007fc57909ca90>
	[7] pry(main)> prj.earn
	much!
	=> nil

irb (pry)上では期待した通りにならない!?

命令を1行にして実行してみると

[8] pry(main)> using Strategist; prj = Enterprise.new; prj.earn
	more!!!
	=> nil

期待通りになりました。

同じメソッドを再度呼んでみると

[9] pry(main)> prj.earn
	much!
	=> nil

変更が解除されている。

試しに

[10] pry(main)> using Strategist; prj.earn; prj.earn
	more!!!
	more!!!
	=> nil
	[11] pry(main)> using Strategist; prj.earn; \
	[11] pry(main)* prj.earn
	more!!!
	more!!!
	=> nil
	[12] pry(main)> prj.earn; prj.earn; using Strategist; prj.earn
	much!
	much!
	more!!!
	=> nil

using を使用後に同行にて変更が反映される様でした。

arel_tableを使った時のメモ

0

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

日々の気温差に体がついて行っていない気がする中西です。

少し前にarel_tableを使用したので、簡単な使い方等をメモしてみます。

複雑なSQL文

スコープなどを書こうと思った場合に、条件がすこし難しい場合があります。

そういった時に、生のSQL文を使用することもあると思います。

少し前に、下記のようなスコープを書いたとこがありました。

scope :except_codes, -> { where.not('(test_code = 0 OR test_code IS NULL) AND code_created_at IS NULL') }

生のSQL文をを用いています。

そのとき、先輩からarel_tableの話を聞き使ってみることにしました。

使ってみた結果が、下記になります。

scope :except_codes, -> { where.not(arel_table[:test_code].eq_any([0, nil]).and(arel_table[:code_created_at].eq(nil))) }

今回は、短いSQL文ですが、長いSQL文になった場合、生のSQL文では後々わかりずらくなってしまう恐れがあります。

そういった場合に、arel_tableを使うことで後々理解がしやすくなると思われます。

arel_tableの使い方

今回上記で使用した部分について簡単にメモします。

まず、下記部分で使用するカラム名を指定しています。

arel_table[:test_code]
arel_table[:code_created_at]

このあとに、条件を追加します。

それぞれ、今回使用している部分は下記のような意味となります。

eq_any(○) :○以外の場合(≠)
eq(○)   :○の場合(=)

○の部分が複数ある場合、配列として入力することで複数の値を条件にできます。

a.eq([0, 1]) :aが「0」か「1」の場合

複数の条件を組み合わせたい場合には、andやorを用いることができます。

こうすることで、複雑な条件文の場合にも比較的簡単に書くことができます。

まとめ

今回は実際に自分が使用した、簡単な部分についてメモしてみました。

このほかにも、likeやorder等も簡単に書けるようです。

気になる方が、調べてみてください。

追記(2016/2/2)

ちょっと指摘があったので追記。

今回紹介しているarel_tableは、Rails用の非公開APIなので、使用する場合は、それを念頭に置き、注意してください。

CarrierWave使用時のTips

0

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

Railsに画像等のファイルをアップロードする機能を実装するgem「CarrierWave」を使用する際のTipsを纏める。

Railsに画像等のファイルをアップロードする機能を実装するgem「CarrierWave」を使用する際のTipsを纏める。

 話の前提

テーブル「users」にフィールド「picture_url」があるという前提。

(picture_urlにはアップロードするファイルのURLが格納される。)

 モデルに関するTip

acts_as_paranoid を併用する場合の注意点

Railsに論理削除を実装できるgem「acts_as_paranoid」を導入しているモデルにCarrierWaveを使用する場合は、skip_callback を設定する必要がある。

class User < ActiveRecord::Base
  acts_as_paranoid
  mount_uploader :picture_url, ImageUploader
  skip_callback :commit, :after, :remove_picture_url!
end

※skip_callbackがないと、データベースが更新された後、画像が削除されてしまう。

 コントローラに関するTip

確認画面が存在する場合の工夫

確認画面がなく、1クリックで更新する様なシステムの場合は非常に単純(編集画面→更新)。

# データベースの更新を行い、指定のディレクトリにファイルを配置する。
@user.save!

しかし、確認画面がある場合は、少し複雑になる(編集画面→確認画面→更新)。

確認画面がある場合は、暗黙的に以下を満足する必要がある事が恐らく一般的である。

  1. 確認画面にファイルを表示する(画像の場合)。
  2. 確認画面を表示しただけでは、データベース更新も格納ファイルの変更もしない。

CarrierWaveでは、通常のアップロード(save)以外に、一時的なアップロードを行う事ができるので、その機能を活用する。

※一時的アップロードでは、データベースは更新されず、指定のディレクトリとは別の一時ディレクトリにファイルがキャッシュとして保存される。

確認時のアクション
# 一時的アップロード(@userインスタンスには一時ディレクトリのパスが入る)
@user.picture_url.cache!
確認画面のビュー
<%# 一時ディレクトリの場所にある画像を表示 %>
<%= image_tag(@user.picture_url.url) %>

<%# キャッシュ名(一時ディレクトリの名前)をhiddenで渡す %>
<%= hidden_field_tag :"cache[picture_url]", @user.picture_url.cache_name %>

※アップロードファイルのフィールドが1つの場合はパラメータ名は”cache_picture_url”等でも良いが、この例では複数フィールドがある場合にも対応できる様に配列にしている。

更新時のアクション
# パラメータで受け取ったキャッシュから画像を復元する
@user.picture_url.retrieve_from_cache! params[:cache][:picture_url]
@user.save!

 ビューに関するTip

form_for, form_tag 使用時の注意点

form_for, form_tagを使用する場合はmutipartオプションが必要である。

<%= form_for(@user, html: { multipart: true }) do |f| %>

【Java】Bean Validationで条件付きチェック

0

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

Javaで条件付きチェックを実装するにあたり、Bean Validationのバリデーショングループを使ってみました。

※Spring Frameworkを使用しています。

 【グループ】

検証グループのインターフェースを作ります。

public interface Role {
	interface Admin {}
	interface General {}
}

 【Bean】

チェック対象のフィールドにグループを指定します。

public class ValidationTestBean {

	private String role;

	@NotEmpty(groups = Admin.class)
	@Size(min = 1, max = 30, groups = General.class)
	private String name;
	
	// getter,setter省略
}

 【コントローラ】

コントローラからバリデータを呼び出します。

@Controller
@RequestMapping({ "/validation/test" })
public class ValidationTestController {

	@Autowired
	private Validator validator;

	@RequestMapping(value = "confirm", method = GET)
	public String confirm(@ModelAttribute("bean") ValidationTestBean bean,
			Errors errors, Model model) {

		// 検証グループ生成
		Object[] groups = createValidationGroups(bean);

		// 入力チェック
		ValidationUtils.invokeValidator(validator, bean, errors, groups);
		if (errors.hasErrors()) {
			return "validation/test/input";
		}
		return "validation/test/confirm";
	}

	private Object[] createValidationGroups(ValidationTestBean bean) {

		List<object> groups = new ArrayList<object>();

		// 条件によりグループを追加
		if ("admin".equals(bean.getRole())) {
			groups.add(Admin.class);
		} else {
			groups.add(General.class);
		}
		return groups.toArray();
	}
}

createValidationGroupsメソッドでグループを追加しています。

このとき、条件により異なるグループを設定することにより、Beanで指定したグループのみバリデーションを実行することができます。

今回割愛しましたが、グループは省略したり複数指定したりも可能です。

グループを活用することにより条件付きチェックをできるだけアノテーションで実装することができました。

RailsでMySQLに格納できない文字が入力された場合の対処法方の検討

0

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

RailsでMySQLに格納できない文字が入力された場合の対処法方の検討しました

 テーブル例

FieldType
idint(11)
hogevarchar(255)

 エラーの出る文字の一例(本文中に記載すると投稿できないため外部サイト参照)

 実行例

ユーザが自由に文字列を入力できる場合、MySQLに格納できない文字が入力される可能性がある。

> t = Hoge.new(hoge: "<エラーの出る文字>")
=> #<hoge id: nil, hoge: "<エラーの出る文字>">
> t.save!
(0.6ms)  BEGIN
SQL (0.3ms)  INSERT INTO `hoges` (`hoge`) VALUES ('<エラーの出る文字>')
Mysql2::Error: Incorrect string value: '\xF0\xA8\xBC\xB2' for column 'hoge' 
at row 1: INSERT INTO `hoges` (`hoge`) VALUES ('<エラーの出る文字>')
(0.1ms)  ROLLBACK
ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect string value: 
'\xF0\xA8\xBC\xB2' for column 'hoge' at row 1: INSERT INTO `hoges` (`hoge`) 
VALUES ('<エラーの出る文字>')

 検出方法

直接Mysql2::Errorは直接例外検出できないため、ActiveRecord::StatementInvalidを検出して判定することでエラー処理を行うことができる

テスト用のメソッド

def hoge_test(str)
  t = Hoge.new(hoge: str)
  t.save!
rescue ActiveRecord::StatementInvalid => e  
  if(e.cause.class == Mysql2::Error 
    && e.cause.message.match(/^Incorrect string value/))
    puts "[DEBUG!] MySQLに格納できない文字が入力されました."
	# エラー処理等
  end
end

実行結果

> hoge_test("<エラーの出る文字>")
(0.6ms)  BEGIN
SQL (0.5ms)  INSERT INTO `hoges` (`hoge`) VALUES ('<エラーの出る文字>')
Mysql2::Error: Incorrect string value: '\xF0\xA8\xBC\xB2' for column 'hoge' 
at row 1: INSERT INTO `hoges` (`hoge`) VALUES ('<エラーの出る文字>')
(0.1ms)  ROLLBACK
[DEBUG!] MySQLに格納できない文字が入力されました.
=> nil

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と一致します。

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

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

最近人気な記事