ホーム ブログ ページ 43

VirtualBoxの 「for reading: -102(File not found.) E_FAIL (0x80004005)」エラー

0

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

VirtualBoxは下記のエラーで、仮想マーシンへのアクセスが出来ません。■エラーメッセージ
Runtime error opening ‘C:\Users\xxx\VirtualBoxVMs\xxx\xxxx.vbox’ for reading: -102 (File not found).
:
:
:
E_FAIL (0x80004005)

■発生経緯
VirtualBoxが起動して、仮想マーシンへアクセスしているままで、
パソコンが自動更新で、勝手に再起動してしまった。

探していましたが、エラーが発生するxxxx.vboxファイルはどこにもありません。
VirtualBoxを修復しても、再インストールしても、PCシステムが更新前のポイントに戻しても治せません。

仮想マーシンを再作成するしかないかと困っているところ、
C:\Users\xxx\VirtualBoxVMs\xxxにxxxx.vbox-tmpというファイルがあったことに気がつきました。
試しに、このファイルをxxxx.vboxにrenameにして、VirtualBoxを再起動してみたら、
仮想マーシンへのアクセスができるようになりました。


  • 160 views
    • https://web.facebook.com/v2.8/plugins/like.php?action=like&app_id=&channel=https%3A%2F%2Fstaticxx.facebook.com%2Fx%2Fconnect%2Fxd_arbiter%2F%3Fversion%3D46%23cb%3Df127696a5476944%26domain%3Ddoruby.jp%26origin%3Dhttps%253A%252F%252Fdoruby.jp%252Ff1f93b8611d49c%26relation%3Dparent.parent&container_width=0&href=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_&layout=box_count&locale=ja_JP&sdk=joey&share=true&show_faces=false
    • https://platform.twitter.com/widgets/tweet_button.96fd96193cc66c3e11d4c5e4c7c7ec97.en.html#dnt=false&id=twitter-widget-1&lang=en&original_referer=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_&size=m&text=VirtualBox%E3%81%AE%20%E3%80%8Cfor%20reading%3A%20-102(File%20not%20found.)%20E_FAIL%20%7C%20DoRuby&time=1611202955995&type=share&url=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_
    • javascript:false
    • https://widgets.getpocket.com/v1/button?label=pocket&count=vertical&v=1&url=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_&title=VirtualBox%E3%81%AE%20%E3%80%8Cfor%20reading%3A%20-102(File%20not%20found.)%20E_FAIL%20%7C%20DoRuby&src=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_&r=0.9549710731375274
    • https://apis.google.com/u/0/se/0/_/+1/fastbutton?usegapi=1&size=tall&origin=https%3A%2F%2Fdoruby.jp&url=https%3A%2F%2Fdoruby.jp%2Fusers%2Froad_of_beginners%2Fentries%2FVirtualBox___for_reading__-102_File_not_found.__E_FAIL__0x80004005_&gsrc=3p&ic=1&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.ja.OLLmITnvXRk.O%2Fam%3DwQE%2Fd%3D1%2Fct%3Dzgms%2Frs%3DAGLTcCMuTMb4aruW2_sOgdLz_ON82D8QUg%2Fm%3D__features__#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh%2Conload&id=I0_1611202955829&_gfid=I0_1611202955829&parent=https%3A%2F%2Fdoruby.jp&pfname=&rpctoken=22232253

MongoDBのコレクション操作(名前変更、サイズ指定、サイズ変更)

0

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

アプリから履歴系を保存するのに好んでMongoDBを使っています。
サイズを指定しておくと古い方から消えてくれるので履歴に向いている。バッチ作って消したり、ディスク容量の心配をしなくて良いのがGood!
コレクション操作(名前変更、サイズ指定、サイズ変更)をメモしておきます。

●コレクション名を変更する

いずれは削除したいけど、当面は残す場合などに便利です。
下記は「hogehoge」から「hogehoge_bak」へ変更する例です。
use hoge
db.hogehoge.renameCollection(“hogehoge_bak”); 

●サイズ指定(古いのから削除)でコレクションを作る

Mongoはコレクションを作らなくても、なければ自動で作られるけど、サイズ指定をしたい場合は事前に実施します。
dbs単位での指定は出来なさそうなのが残念。
下記は「hogehoge」を100MBで作る例です。(sizeはバイト単位で指定)
use hoge
db.createCollection(“hogehoge”, {capped:true, size: 100000000}); 

●コレクションのサイズを変更する

既に作ってしまったコレクションのサイズを変更します。
想定よりも早く履歴が消えちゃう場合なんかに便利
下記は「hogehoge」を1GBに変更する例です。(sizeはバイト単位で指定)
use hoge
db.runCommand({“convertToCapped”: “hogehoge”, size: 1000000000}); 

●おまけ:よく使うコマンド

$ mongoshow dbs <- DBS(データベース)一覧
use hoge <- DBS(データベース)切替
show collections <- コレクション(テーブル)一覧
db.hogehoge.find() <- 検索(SELECT)
db.hogehoge.drop() <- コレクション(テーブル)削除
db.dropDatabase() <- DBS(データベース)削除

MybatisでOracleにListを一括insert

0

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

MybatisでOracleにList<object>を一括insert

主キーIDは自動増加ではないパターン

mybatisを利用して、OracleDBにList<object>を一括insert方法を紹介します。

主キーIDは自動増加ではないパターン

 mapperメソッド定義:

int insertBatch(@Param (“itemList” ) List<objectclass> itemList);

itemListを一括DBにinsertします。

 NGパターン

<insert id=”insertBatch” parametertype=”java.util.List”>

insert into TABLEAAA (C1, C2)

values

<foreach collection=”itemList” item=”item” index=”index” separator=”,”>

(#{item.c1},#{item.c2})

</foreach>

</insert>

書き方は大丈夫そうな感じですが、実は下記エラーが発生します。

Cause: java.sql.BatchUpdateException : ORA-00933: SQLコマンドが正しく終了されていません。

; bad SQL grammar []; nested exception is java.sql.BatchUpdateException: ORA-00933: SQLコマンドが正しく終了されていません。

Oracleの場合は特別です。

 OKパターン1

INSERT ALLを利用します。

<insert id=”insertBatch” parametertype=”java.util.List”>

INSERT ALL

<foreach collection=”itemList” item=”item”>

INTO TABLEAAA (C1, C2) values (#{item.c1},#{item.c2})

</foreach>

SELECT * FROM dual

</insert>

 OKパターン2

union allを利用します。

<insert id=”insertBatch” parametertype=”java.util.List”>

insert into TABLEAAA (C1, C2)

<foreach collection=”itemList” item=”item” separator=”union all”>

(select #{item.c1},#{item.c2} from dual)

</foreach>

</insert>

MybatisでOracleにListを一括update

0

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

MybatisでOracleにList<object>を一括update

mybatisを利用して、OracleDBにList<object>を一括update方法を紹介します。

 mapperメソッド定義:

int updateBatch(@Param (“itemList” ) List<objectclass> itemList);

itemListを一括DBにupdateします。

 NGパターン

      <update id="updateBatch" parametertype="java.util.List">
             <foreach collection="itemList" item="item" separator=";">
                  update TABLEAAA
                   <set>
                        C1 = #{item.c1},
                        C2 = #{item.c2}
                   </set>
                  WHERE ID = #{item.id}
             </foreach>
      </update>

書き方は大丈夫そうな感じですが、実はエラーが発生します。

Oracleの場合は特別です。

 OKパターン

      <update id="updateBatch" parametertype="java.util.List">
            begin
             <foreach collection="itemList" item="item" separator=";">
                  update TABLEAAA
                   <set>
                        C1 = #{item.c1},
                        C2 = #{item.c2}
                   </set>
                  WHERE ID = #{item.id}
             </foreach>
            ;end;
      </update>

Active Record のカラム名にエイリアスを使えるようにする Utusemi gem

0

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

Active Record のカラム名にエイリアスを利用できるようにするための gem「Utusemi」を紹介します。

 はじめに

Utusemi は Active Record のカラム名にエイリアスを利用できるようにするための Ruby on Rails 3, 4 向けの gem です。

Ruby on Rails にはモデルのインスタンスに対してエイリアスを張るための alias_attribute というメソッドが存在します。Utusemi は、これに加えてモデルクラスの where メソッドや order メソッドでもエイリアスが使えるようにするための gem になります。

カラム名へのエイリアスは以下のようなケースで利用されることが想定されます。

  1. カラム名が長いので実装上は短く済ませたい
  2. 既存のコードを変えずに DB のカラム名変更に対応したい
  3. gem で用意されている固定カラム名をアプリケーションの特定カラム名にマッピングさせたい

では早速インストールの仕方から紹介していきます。

 インストール方法

他の gem と同じように Bundler を使ってインストールするのがおすすめです。

この場合は Gemfile に下記の1行を追記し、bundle install を実行します。

gem 'utusemi'

また、Bundler を利用しない場合は下記のコマンドでもインストールできます。

gem install utusmei

 設定ファイルの書き方

エイリアス先のカラムとエイリアス元のカラムを設定していきます。

例として、下記のコードを config/initializer/utusemi.rb に設置します。

Utusemi.configure do
  map :sample do
    name :first_name
  end
end

 使い方

上記で設定したエイリアスの設定名を utusemi メソッドに渡すことで、エイリアスを有効にできます。

irb> User.utusemi(:sample).where(name: 'John')
SELECT "users".* FROM "users" WHERE "users"."first_name" = 'John'

例では sample というエイリアス設定を有効にすることで、User モデルの first_name カラムに対して name という名前でアクセスしています。

また、utusemi メソッドを介して取得したインスタンスでもエイリアスが有効です。

irb> user = User.utusemi(:sample).where(name: 'John').first
irb> user.name
#=> "John"

 詳細なメソッドの説明

ActiveRecord::Base.utusemi

モデルクラスに対するエイリアスを設定します。

「使い方」の項で紹介した例では、このメソッドを利用しています。

引数にはエイリアス設定名のシンボルまたは文字列を渡します。

引数を省略した場合はモデル名の小文字単数形をエイリアス設定名として利用します。

irb> Utusemi.configure do
  map(:user) { nickname :first_name }
end

irb> User.utusemi.where(nickname: 'John')
SELECT "users".* FROM "users" WHERE "users"."first_name" = 'John'

ActiveRecord::Base.utusemi!

モデルクラスに対してエイリアスを設定する、破壊的メソッドです。

ActiveRecord::Base.utusemi! を1度でも呼び出したモデルは、その後もエイリアスが有効な状態となります。

irb> User.where(name: 'John')
SQL:Error: Unknown column 'users.name' ...

irb> User.utusemi!(:sample)
irb> User.where(name: 'John')
SELECT "users".* FROM "users" WHERE "users"."first_name" = 'John'

ActiveRecord::Base#utusemi

モデルインスタンスに対するエイリアスを設定します。

irb> user = User.first

irb> user.name
NoMethodError: undefined method `name' for #<user:...>

irb> user.utusemi(:sample).name
#=> "John"

ActiveRecord::Base#utusemi!

モデルインスタンスに対してエイリアスを設定する、破壊的メソッドです。

ActiveRecord::Base#utusemi! を1度でも呼び出したインスタンスは、その後もエイリアスが有効な状態となります。

irb> user = User.first

irb> user.name
NoMethodError: undefined method `name' for #<user:...>

irb> user.utusemi(:sample)
irb> user.name
#=> "John"

 関連モデルに対するエイリアス

エイリアスの有効状態は関連モデルにも引き継がれます。

例として、User モデルに対して Blog モデルが複数紐付いている場合を詳細します。

app/models/user.rb

class User < ActiveRecord::Base
  has_many :blogs
end

app/models/blog.rb

class Blog < ActiveRecord::Base
  belongs_to :user
end

config/initializers/utusemi.rb

Utusemi.configure do
  map :user do
    name :first_name
  end

  map :blog do
    url_path :permanent_link_url
  end
end

このようなファイル構成となっているとき、次のような書き方ができます。

irb> user = User.first
irb> user.utusemi.blogs.where(url_path: 'path-to-link')
SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = 1 AND "blogs"."permanent_link_url" = 'path-to-link'

 リンク

https://github.com/hyoshida/utusemi

【GAIQ】2014年8月1日時点の出題傾向

0

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


新たにGoogleアナリティクスIQ(GAIQ)を取得しました。

個人的に100%を狙っていましたが…結果は95%。残念…。

ともあれ、無事合格できたので一安心です。

2014年8月4日現在、日本のGAIQの合格者は506名。

増えましたね。

1年半前に確認した際は100名程だったかと思います。

GAIQの認知度、問題傾向の共有が進み

受験しようという方も増えているのだと思います。

今回はGAIQの概要紹介と、

私が受けた現時点での問題の傾向を簡単にお伝えしたいと思います。

 GAIQとは

「Google アナリティクス IQ(以下、GAIQ)はGoogleが実施している個人認定資格です。Google アナリティクスの「導入」から「分析」「レポーティング」にいたるまでの総合的な知識を確認するものでテストに合格するとGoogleから認定証が発行されます。」

 受験概要

受験費用:US50ドル(テストセンターにてクレジットカード決済)

受験言語:英語

問題数:70問

出題形式:テスト画面での選択チェック方式

テスト時間:90分

※テスト開始後は中断が可能。中断中は経過時間のカウントも停止します。

ただし、テスト開始後120時間(5日間)以内に終了しないといけません。

合格正解率:80%

 出題傾向(2014年8月1日現在)

私の場合は下記のような問題の傾向でした。

※分け方が適切ではないかもしれませんが…ザックリと。

・解析環境 …特定条件の場合のビュー構成/GAの利用規約…など

・フィルタ …ビューやレポートに適用するフィルタの内容

・マーケティング …ROIの考え方やデジタルアナリティクスとは…など

・ディメンション …ディメンションの定義や使用方法

・レポート …特定条件の場合の閲覧対象レポート/レポートの定義…など

・指標 …指標定義…など

・eコマース …eコマース機能導入方法/取得される指標に関して

・adwords …アトリビューションモデルやadwordsの評価指標に関して

・GTM …GTM導入の意義など

ちなみに、ユニバーサルアナリティクスに特化した問題は

現時点では見られませんでした。

正式リリースして数か月。

GAIQにもそろそろ採用されるんじゃないかと思うので

問題傾向も大きく変わることを懸念していたのですが…

まだ大丈夫のようです。

でも近い将来、

ユニバーサルアナリティクスの問題も増えていくのでしょうね。

(分からない英単語が増える予感…)

他の方のブログ等でウォッチしていきたと思います。

 気になる問題

一つ、回答に困った問題がありましたのでご紹介します。

You have defined goal X such that 
any PDF download qualifies as a goal conversion.
A user comes to your site once and downloads five PDFs. 
How many goal conversions will be recorded?

A) 2
B) 0
C) 1
D) 5

※私の翻訳※

あなたのサイトではPDFダウンロードを目標Xとして目標設定してます。
一回のサイト訪問で5回ダウンロードしました。
目標完了数はどのように記録されるでしょう。

A) 2
B) 0
C) 1
D) 5

PDFにはGoogleアナリティクスのタグを設置することができないので

リンクにイベントトラッキング、もしくはバーチャルページビューを仕掛けることになると思います。

例えば、

イベントトラッキングを指定しており、それを目標設定しているなら目標完了数は「5」。

バーチャルページビューを指定しており、URLを目標設定しているなら「1」になると思います。

この問題ではどちらの機能を導入しているか

明確な記述はないと思うので、どちらかの判断に迷いました。

私はGoogleアナリティクスのヘルプ等でよく

イベントトラッキングの導入例としてPDFダウンロードが挙げられているので、

恐らくイベントトラッキングが導入されているのだろうと見越し、「5」にしましたが…。

皆様はどちらだと思いますか?

もしかして翻訳に不足があるかもしれません…。

その際はご指摘いただけますと幸いです_(_ _)_

 受験してみての感想

私は事前の勉強は特に行いませんでした。

なにせ有難い一時停止機能があるので…

分からない単語や問題は都度、

Google翻訳やGoogleアナリティクスのヘルプページで調べていました。

ただ、私の場合、従来のGA・ユニバーサルアナリティクス・GTMの機能を

予め十分理解した上で挑んだつもりです。

それでも多少は戸惑いました。

やはり、少し不安がある、という方はアナリティクスアカデミーでの勉強をお勧めします。

※アナリティクスアカデミー

https://analyticsacademy.withgoogle.com/explorer

有効期限が切れて受けなおす方、

初めて受ける方に対して、少しでも参考になれば幸いです。

以上、最新GAIQのレポートでした。

Google アナリティクス セミナー インターフェイス編

Google アナリティクスのレポート画面が把握できていない方向けの講座。

レポート画面の解説や既存機能の活用法、マルチチャネルなどの新レポートのインターフェイスを解説します。

Google アナリティクス セミナー 分析手法編

インターフェイスは把握しているが、数値の意味や考え方がよく分からないという方向けの講座です。 アクセス解析を用いた課題抽出やサイト改善の考え方を解説します。

Google アナリティクス セミナー 徹底設定編

現状のGoogle アナリティクスで取得可能な数値に物足りない方向けの講座。

外部サイトへの誘導やソーシャルボタン連携、eコマース機能などのカスタマイズ方法をレクチャーします。

MacでのOWASP ZAPのプロキシ設定

0

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

今回はMacでOWASP ZAPのプロキシ設定を行う手順をご紹介します。

 概要

【環境】
Mac OS X 10.7.5
OWASP ZAP 2.2.2

OWASP ZAPはWEBサイトの脆弱性を診断することができる、オープンソースのツールです。

このOWASP ZAPにはプロキシを利用する手動クロールと、OWASPが自動でリンクを辿って自動クロールする動的スキャンがあります。

ただ、動的スキャンだけでは検出できない項目もあるので、より細かい診断は手動クロールがおすすめです。

この手動クロール、仕組みとしてはブラウザでのリクエストを全てローカルの8080ポート(デフォルト)で起動しているOWASP ZAPを経由して行い、診断を行うというものです。

HTTPSのサイトはこの手動クロールでは診断できないのでご注意ください。

 プロキシ設定

プロキシの設定方法は以下になります。

1. [システム環境設定]
2. [ネットワーク]
3. [(任意のデバイス)]
4. [プロキシ]
5. [Web プロキシ (HTTP)]をチェック
5-1. Webプロキシサーバ [localhost] : [8080]
6. [OK]
7. [適用]
8. ブラウザ再起動

以上で設定は完了です。

OWASP ZAPの画面を見ると、左上の[サイト]にブラウザでアクセスしたサイトのURLが表示されていくかと思います。

注意点としては、設定したPC全体のWebアクセス(HTTP)がOWASP ZAP経由となってしまいますので、ブラウザ以外でHTTPを利用する他のアプリが利用不可能となります。

診断が終わったら忘れずに設定をもとに戻すようにしましょう。

以上です。簡単に設定ができ、脆弱性診断ができるOWASP ZAPおすすめです。

PHP技術者認定試験(初級)合格経験

0

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

PHP技術者認定試験(初級)合格経験

 【試験難易度】

初心者向けの試験です。

PHPプログラミングの基本知識を問う試験です。

試験の合格率は70%ぐらいです。

ちなみに、上級の合格率:11%ぐらいです。

 【使用教材】

初めてのPHP5増補改訂版(買ったけど、いらない感じでした。)

徹底攻略PHP5技術者認定[初級]試験公式問題集(会社の本棚にある)

http://www.phpexam.jp/material/

 【勉強方法】

問題集を中心として勉強した。

問題をやって、回答をしっかり覚えました

問題の回答は教材見たいです。表にしているので、覚えやすいです。

問題集に出た関数は必ず覚えてください。

ITPROの問題をやりませんでした。

開発環境を構築して、気になるところを実行してみた。

実際動かしたら、印象が深いです。

 【感想】

初心者レベルです。

問題集をしっかり把握すれば、合格できます。

PHPはスクリプト言語なので、Javaと違って、Rubyと似ている。

Ruby&Rails技術者はJava技術者より取りやすいと思います。

audio.js使う時、要注意

0

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

部分android機種の標準ブラウザにはにaudio.jsがうまく動かないaudio.jsは、みなさんご存知のようにMP3音声ファイルの再生にとても便利なjsプラグインです。

しかし、部分android機種の標準ブラウザにはにaudio.jsがうまく動かない現象があります。

うまく動かないというのは、
①曲再生のシークンは、曲再生後、瞬間終了
②曲再生時間は0のまま
③前進、バックの操作が効かない
のことです。

jsの中身を確認すると、loadProgressファンクションには、下記のif分があります。
      if(this.element.buffered!=null&&this.element.buffered.length){
        if(!this.loadStartedCalled)this.loadStartedCalled=this.loadStarted();
        this.loadedPercent=this.element.buffered.end(this.element.buffered.length-1)/this.duration;
        this.settings.loadProgress.apply(this,[this.loadedPercent])
      }

if分岐に入って、this.loadStarted()が呼ばれると、曲の再生時間this.duration(②)がセットされます。
さらにthis.loadedPercent(①)が正しく計算されます。
さらに前進、バック時(③)、this.loadedPercentを使うので、前進、バック動作は正しく動作します。

androidの部分機種には、this.element.bufferedが取れなくて、if分に入れず、動作がおかしくなります。

あまり強引な解決方法ですが、

if(this.element.buffered!=null&&this.element.buffered.length){
:
}
//追加
else userAgentを判断して、androidかつ標準ブラウザの場合{
 //↑同じ処理
}

但し、androidかつ標準ブラウザの判断は難しい。
最初、/(android)/i.test(navigator.userAgent)&&!(/(chrome)/i.test(navigator.userAgent))
で、androidかつchrome以外で、行けるかなと思っていましたが、
どうも、一部機種には、標準ブラウザでもuserAgentに”chrome”という文字が入っています。

残念ですが、完璧の解決方法が見つかりません。audio.js使う時、注意しましょう。

[Rails4]Bootstrap導入とassets:precompileでglyphiconが表示されない不具合対応

0

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

Rails4にBootstrapを導入するのは、とても簡単です。
だが、いざ本番環境にデプロイしたら、glyphiconが表示されないという不具合に見舞われました。
自分がベストだと思う導入方法と対処方法をメモします。
対象バージョンはbootstrap-sass-3.2.0.0です。バージョンアップで解消される事を期待したい。

●Bootstrapを追加

turbolinksと相性が悪いらしいので、turbolinksを外してbootstrap-sassを追加します。

編集:Gemfile

# gem 'turbolinks'

# Use Bootstrap
gem 'bootstrap-sass'

$ bundle install =========================================== Installing bootstrap-sass 3.1.1.1 =========================================== ※「Your bundle is complete!」と表示されればOK

●Bootstrapの適用順番を明示

JSとCSSは、デフォルトだと名前順に適用されるので、先に読まれるように明示します。
aとかで始まる名前のJS/CSSだとBootstrapの設定を上書けない為です。(CSSは後勝ちなので)

編集:app/assets/javascripts/application.js

//= require turbolinks
//= require bootstrap

編集:app/assets/stylesheets/application.css

 *= require bootstrap
 *= require_tree .
 *= require_self

●assets:precompileでglyphiconが表示されない不具合対応

本番環境ではassets:precompileして、public/assets以下をApacheから直接返すようにしていますが、gems/bootstrap-sass-3.2.0.0/assets/stylesheets/bootstrap/_glyphicons.scssで「url(」と定義されている為、precompile時にcssにハッシュ値が入らず、アイコンが表示できません。
SCSSで画像などを表示するには「image-url(」と定義して、Railsに変換してもらう必要があります。開発環境では「url(」でも表示されるので、開発段階では気付き難いので厄介です。

作成:app/assets/stylesheets/bootstrap_override.scss

//### assets:precompileでglyphiconが表示されない不具合対応 ###
@font-face{
  font-family:'Glyphicons Halflings';
  src: image-url("bootstrap/glyphicons-halflings-regular.eot");
  src: image-url("bootstrap/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"),
       image-url("bootstrap/glyphicons-halflings-regular.woff") format("woff"),
       image-url("bootstrap/glyphicons-halflings-regular.ttf") format("truetype"),
       image-url("bootstrap/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg")
}

編集:app/assets/stylesheets/application.css

 *= require bootstrap
 *= require bootstrap_override

論理削除Gem(Paranoia)を自分好みにカスタマイズ

0

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

DBのユニーク規制が、データの整合性を保つ最後の砦だと考えている。
実装に注意したり、DBを直接書き換える場合に、注意すれば良いのだけれど、やっぱりバグやヒューマンエラーは付き物。
バグやヒューマンエラーを考えると論理削除を使って、定期的にクリーニングがベストかな。
論理削除のGemを探しましたが、日付を使う物が多く、かつNULLが使われるので、複合キーでのユニーク規制が掛からない。
フラグを使う物もあったけど、0・1では一度削除したものと同じものを再度削除出来なくなる。
辿り着いたのは、初期値0で、削除時にIDと同じ値を設定するというDB設計。
ただ、これを満たすGemが見つからないので、良さそうなParanoiaの一部を修正する(モンキーパッチを充てる)事にしました。

また、JOINされるケースでSQLが「WHERE “.`deleted` = 0」となり、「Mysql2::Error: Column ‘deleted’ in where clause is ambiguous:」で落ちる問題も対応しました。
このバージョンの組み合わせだから動かない、という事なんだろうか?(謎)

前提:Rails 4、Paranoia 2.0.2

●Paranoia追加

編集:Gemfile

# Use Paranoia
gem 'paranoia', '2.0.2' # モンキーパッチ:config/initializers/extensions/paranoia.rb

$ bundle install
===========================================
Installing paranoia 2.0.2
===========================================
※「Your bundle is complete!」と表示されればOK

●Paranoiaカスタマイズ

作成:config/initializers/extensions/paranoia.rb

module Paranoia
  module Query
    def only_deleted
      # with_deleted.where.not(paranoia_column => nil)
      with_deleted.where.not(paranoia_column => 0)
    end
  end

  def restore!(opts = {})
    ActiveRecord::Base.transaction do
      run_callbacks(:restore) do
        # update_column paranoia_column, nil
        update_column paranoia_column, 0
        restore_associated_records if opts[:recursive]
      end
    end
  end

  private

  def touch_paranoia_column(with_transaction=false)
    if with_transaction
      # with_transaction_returning_status { touch(paranoia_column) }
      with_transaction_returning_status { update_attribute(paranoia_column, id) }
    else
      # touch(paranoia_column)
      update_attribute(paranoia_column, id)
    end
  end
end

class ActiveRecord::Base
  def self.acts_as_paranoid(options={})
    alias :really_destroy! :destroy
    alias :destroy! :destroy
    alias :delete! :delete
    include Paranoia
    class_attribute :paranoia_column

    # self.paranoia_column = options[:column] || :deleted_at
    self.paranoia_column = options[:column] || :deleted
    # default_scope { where(paranoia_column => nil) }
    def self.default_scope
      where(arel_table[paranoia_column].eq 0)
    end

    before_restore {
      self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers)
    }
    after_restore {
      self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers)
    }
  end
end

●ベースモデル作成

$ rails g model base
===========================================
invoke active_record
create db/migrate/20140707233955_create_bases.rb
create app/models/base.rb
invoke rspec
create spec/models/base_spec.rb
invoke factory_girl
create spec/factories/bases.rb
===========================================
※エラーが表示されなければOK
削除:db/migrate/20140707233955_create_bases.rb
削除:spec/factories/bases.rb
編集:app/models/base.rb

class Base < ActiveRecord::Base
  self.abstract_class = true
  acts_as_paranoid
end

●テストモデル作成

$ rails g model test
===========================================
invoke active_record
create db/migrate/20140707234352_create_tests.rb
create app/models/test.rb
invoke rspec
create spec/models/test_spec.rb
invoke factory_girl
create spec/factories/tests.rb
===========================================
※エラーが表示されなければOK
編集:db/migrate/20140707234352_create_tests.rb

class Tests < ActiveRecord::Migration
  def change
	create_table :tests do |t|
      t.string :name, null: false
      t.timestamps
      t.integer :deleted, null: false, default: 0
    end
    add_index :tests, [:name, :deleted], unique: true
  end
end

$ rake db:migrate
※エラーが表示されなければOK
編集:app/models/test.rb

class Test < ActiveRecord::Base
class Test < Base
end

○動作確認

$ rails cTest.create(name: ‘test’)
test = Test.find_by_name(‘test’)
test.blank?
=> false
test.destroy
=> UPDATE文
test = Test.find_by_name(‘test’)
test.blank?
=> true
exit

●テストモデル削除

削除:app/models/test.rb
削除:db/migrate/20140707234352_create_tests.rb
削除:spec/models/test_spec.rb
削除:spec/factories/tests.rb
$ rake db:migrate:reset
※エラーが表示されなければOK

jQuery flotr2 〜グラフ〜

0

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

rick No33です。
今回は、jQueryのプラグインflotr2を使用して簡単にきれいなグラフを作成します

環境

jQuery 2.1.1

インストール

http://humblesoftware.com/flotr2/よりダウンロード

手順

ダウンロードした中のflotr2.min.jsを読み込む

<!– 出力先 –>
<div id=”graph1″ style=”width:800px;height:300px;”></div>

<!– グラフ作成 –>
<script>
$(document).ready(function(){
var graph=[{data: [[1,10], [2,20], [3, 5]], label: “グラフ1”, yaxis: 1}, {data: [[1,30], [2,1], [3, 15]], label: “グラフ2”, yaxis: 1}];
var option={
title: “グラフ名”,
legend: {
position: “se” //ラベル表示位置(右下)
},
xaxis: {
title: “x軸名”,
ticks: [[1,”1個目”], [2, “2個目”], [3, “3個目”]]
}
}
Flotr.draw($(#graph1)[0], graph, options);
})
</script>

これだけです。 他にも色々グラフがあるので試してみてください。

[Ruby] 複数サーバの同じファイルをtail -fするプログラムを作ってみよう

0

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

複数サーバの同じファイルをtail -fするプログラムを作ってみよう

 この記事について

サーバでの作業にはかかせないログの監視。

tail -fは多くの方が利用されていると思います。

台数が少なければいいのですが、増えてくると一台ずつ

サーバにログインして→”tail -f <パス名>”とタイプして・・・

が面倒になってきます。

今回はこの手間を省くスクリプトを作成しようというのがテーマです。

 net/ssh/multi

今回使うrubygemsライブラリはnet-ssh-multiです。

複数のサーバにログインして同じ操作を行うことができるものです。

 プログラム作成

いきなりですが、以下のように作成しました。

#!/usr/bin/env ruby
#-*- coding: utf-8 -*-
require 'rubygems'
require "net/ssh/multi"
SSH_CONFIG = File.join(ENV['HOME'], ".ssh/config")

def main(hosts, paths)
  Net::SSH::Multi.start do |session|
    hosts.each do |host|
      connect_host(session, host)
    end
    tail_f(session, paths)
    session.loop
  end
rescue Interrupt
end

def connect_host(session, host)
  option = {}
  option[:config] = SSH_CONFIG if SSH_CONFIG && File.exists?(SSH_CONFIG)
  session.use host, option
end

def tail_f(session, paths)
  session.open_channel do |channel|
    channel.on_data do |ch, data|
      data.each_line do |line|
        puts ["[#{ch[:host]}]", line].join("\t")
      end
    end
    channel.exec "tail -f #{paths.join(" ")}"
  end
end    

if __FILE__ == $0
  raise "usage: mtailf <host ,host,...> <file file file...>" if ARGV.length < 2
  hosts = ARGV[0].split(/\s*,\s*/)
  paths = ARGV[1 .. -1]
  main(hosts, paths)
end

ポイントを説明していきます。

SSH_CONFIG = File.join(ENV['HOME'], ".ssh/config")

ssh_configの設定が使えるようにssh/configファイルの場所を指定しておきます。

def main(hosts, paths)
  Net::SSH::Multi.start do |session|
    hosts.each do |host|
      connect_host(session, host)
    end
    tail_f(session, paths)
    session.loop
  end
rescue Interrupt
end

mainメソッドです。

Net::SSH::Multiのブロック内でサーバへのコネクションをはり、

tailコマンドを実行しています。

tail -f はctrl+cを押すまで処理が続くので

session.loop

を実行しています。

def connect_host(session, host)
  option = {}
  option[:config] = SSH_CONFIG if SSH_CONFIG && File.exists?(SSH_CONFIG)
  session.use host, option
end

サーバへの接続です。

session.use で接続します。

def tail_f(session, paths)
  session.open_channel do |channel|
    channel.on_data do |ch, data|
      data.each_line do |line|
        puts ["[#{ch[:host]}]", line].join("\t")
      end
    end
    channel.exec "tail -f #{paths.join(" ")}"
  end
end

リモートホストに対してtail -fを実行している部分です。

channel.execでコマンドを実行して

ホストから応答があったら

channel.on_data

のブロックが実行されるかんじです。

JavaScriptっぽいですね。

ch変数にはホスト名も含まれているので

コンソールに出力する際には

puts [“[#{ch[:host]}]”, line].join(“\t”)

として、どのホストからの出力なのかがわかるようにしています。

 使い方

上記のプログラムを作成したら

ファイル名はmtailf とします。

そして

chmod 755 mtailf

と実行可能なようにパーミッションを設定します。

net-ssh-multiをインストールします。

gem install net-ssh-multi

ここまでが初期設定で、実際に使うときには

mtailf user@host01,user@host02 /path/to/file

のようにします。

引数は

第一引数→ホスト名をカンマ区切りで

第二引数以降→表示するファイルパス

以下は出力イメージです。

[host01]   ファイル行・・・・・・・・・・・
[host02]   ファイル行・・・・・・・・・・・
・
・
・
・

終了方法は

tail -fと同様に

ctrl+c です。

このコマンド打つのも面倒!となったら・・・・・・

aliasとか設定しましょう!

【LiveValidation】ブラウザ上でバリデーションを行う【RAILS/JS】

0

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

LiveValidation.jsを使用するとブラウザ上でバリデーションを行えます。

 動作環境

Ruby 1.8.7,1.9.3

Rails 2.3.15

prototype.jsがある

 1.「LiveValidation.js」をダウンロード

ここからダウンロードできます

 2.ダウンロードしたものをRailsのpublicディレクトリに配置(prototype.jsと同じ階層)

 3.Viewで使ってみる

JSを読み込み、テキストフィールド等のIDに対するscriptを書くだけ

	~~~~~~~~~~~
	~~~~~~~~~~~
	<%= javascript_include_tag "livevalidation_prototype" %>
	~~~~~~~~~~~
	~~~~~~~~~~~
	
	<%= :text_field, :product, :name, :id => '/product_name'/ %> 
	この下に↓を追加
	<script type="text/javascript">
	        var product_name = new LiveValidation('product_name', { validMessage: 'OKです', wait: 500 });
	        product_name.add(Validate.Presence, {failureMessage: "未入力です"});
	        //product_name.add(Validate.Length, { minimum: 3, maximum: 255,
	tooLowMessage: '3文字以上で', tooHighMessage: '255文字以下で' });
	        //product_name.add(Validate.Numericality, { minimum: 3, maximum: 255,
	tooLowMessage: '数字は3から', tooHighMessage: '数字は255まで' });
	        //product_name.add(Validate.Format, {pattern: /^会社名$/i, 
	failureMessage: "'会社名'と入力してください" } );
	</script>
	
	

Rails3系だとProduct.validatorsでバリデーションの設定がとれるのでペルパーとかを作成してもっとスマートにできそうです。

MyBatis Generator紹介

0

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

MyBatis Generator紹介

 MyBatis Generatorとは

データベースのスキーマを元にMyBatisが使用する各種ファイルを自動生成するためのツールです。

MyBatisを使う場合は基本的にSQLを手書きする必要がありますが、大量のXMLとJavaBeanファイルを手で書くのはミスの原因にもなりますし健康にも良くありません。

テーブルが多くて、カラム数が多い場合、MyBatis Generatorを使えば、効率はすごくアップしますし、ミスも少ないです。

 ダウンロード先:

https://code.google.com/p/mybatis/downloads/list?can=1&q=Product%3DGenerator

 使い方

●ファイル置き場:

D:\mybatis\generator
 ・src(保存先)
 ・mybatis-generator-core-1.3.2.jar(実行ファイル)
 ・generator.xml(設定ファイル)

●設定ファイル:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorconfiguration>
	-->
	<classpathentry location="D:\lib\ojdbc6.jar" />
	<context id="DB2Tables" targetruntime="MyBatis3">
		<commentgenerator>
			<property name="suppressAllComments" value="true" />
		</commentgenerator>
		-->
		<jdbcconnection driverclass="oracle.jdbc.driver.OracleDriver" connectionurl="jdbc:oracle:thin:@192.168.111.111:1521:XE" userid="xxxx" password="xxxx">
		</jdbcconnection>
		<javatyperesolver>
			<property name="forceBigDecimals" value="false" />
		</javatyperesolver>
		-->
		<javamodelgenerator targetpackage="com.test.webapp.model" targetproject="D:\mybatis\generator\src">
			<property name="enableSubPackages" value="true" />
			<property name="trimStrings" value="true" />
		</javamodelgenerator>
		-->
		<sqlmapgenerator targetpackage="com.test.webapp.mapping" targetproject="D:\mybatis\generator\src">
			<property name="enableSubPackages" value="true" />
		</sqlmapgenerator>
		-->
		<javaclientgenerator type="XMLMAPPER" targetpackage="com.test.webapp.persistence" targetproject="D:\mybatis\generator\src">
			<property name="enableSubPackages" value="true" />
		</javaclientgenerator>
		-->
		-->
			<generatedkey column="id" sqlstatement="SELECT TEST_TABELE_SEQ.nextval FROM dual" type="pre" />
		
	</context>
</generatorconfiguration>

●実行

コマンド:

java -jar D:\myibatis\generator\mybatis-generator-core-1.3.2.jar -configfile generator.xml -overwrite

●結果:

下記ファイルが作成されます。

TestTableMapper.xml

TestTable.java

TestTableMapper.java

RewriteRuleとWordPressのRedirectionで日本語URLを扱う方法

0

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

WordPressのページ構成変更に伴い日本語URLを日本語URLにリダイレクトしようした時にハマったのでメモしておきます。
最終的には、WordPressのRedirectionプラグインを使う事にしましたが、RewriteRuleでも成功しています。
書き方が違うので注意が必要です。

RewriteRuleを使う場合

Apacheの設定ファイルまたは.htaccessでmod_rewriteを有効にしてある前提です。
「http://example.com/ほげ」にアクセスされた場合に「http://example.com/ほげほげ」にリダイレクトする例です。
RewriteRule ^/\xe3\x81\xbb\xe3\x81\x92$ /\%e3\%81\%bb\%e3\%81\%92\%e3\%81\%bb\%e3\%81\%92 [NE,R=301,L]
「ほげ」をUTF-8でURLエンコードしたのはこれ「%e3%81%bb%e3%81%92」です。
転送元のURIは「%」を「\x」に、転送先のURIは「%」を「\%」とエスケープしてあげる必要があります。
また、最後に「NE」を追加して、エスケープしないようにしてあげる必要があります。
面倒ですね。

WordPressのRedirectionプラグインを使う場合

WordPressにRedirectionプラグインがインストール&有効化されている前提です。
RewriteRuleと同様に「http://example.com/ほげ」にアクセスされた場合に「http://example.com/ほげほげ」にリダイレクトする例です。
ソースURL:/%e3%81%bb%e3%81%92
ターゲットURL:/\%e3\%81\%bb\%e3\%81\%92\%e3\%81\%bb\%e3\%81\%92
「ほげ」をUTF-8でURLエンコードしたのはこれ「%e3%81%bb%e3%81%92」です。
転送元のURIはそのまま(RewriteRuleと異なる)で、転送先のURIは「%」を「\%」(RewriteRuleと同様)とエスケープしてあげる必要があります。
やはり面倒ですね。

MyBatisでwhere要素を使った時になぜか先頭の「AND」が取り除かれなかった時の話

0

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

仕事でMyBatisを使っているのですが、select文を書いてる際にWHERE句を編集したらSQLがエラーになりました。
ひょっとしたら同じ事でコケる人もいるかもしれないので原因を書いておきます。

MyBatisでSQLを定義するXMLのwhere要素には、中の文字列の先頭がAND|ORだったらそれを取り除く機能があるのですが、今回なぜかそれが機能しませんでした。

よくチェックすると、文字列のANDの後が半角スペースでなく、タブで入っていました。
タブを半角スペースに置き換えたところ、正常にSQLが流れるようになりました。

インデントにタブを使っていると同様の事態に引っかかるかもしれません。
どうしてもタブで書きたいという場合はwhere要素を使わずに
prefixOverrides=”AND★|OR★”(★をタブに置き換える)
とするとうまくいくかもしれません。

参考:
http://mybatis.github.io/mybatis-3/ja/dynamic-sql.html

システムのせいでタグがエスケープしても取り除かれてしまうので色々省略して書いてます。

続・たった1コマンドでネットショップ構築できちゃうelecoma-vagrant

0

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

通販サイトをたった1コマンドで簡単に構築できる「elecoma-vagrant」のしくみについて紹介します。

■ 概要

以前の記事」で紹介した「elecoma-vagrant」のに利用されている chef + vagrant の技術について、スライドにまとめました。

『オープンソースカンファレンス2014 Tokyo/Spring』のブースにてデモを交えて解説する予定ですので、是非お越し下さい!

■ 本編(スライド)

xinetd(ザイネットディー) 〜sshのIP制限とアクセスログの記録〜

0

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

rick No32です。
今回は、xinetdといわれるサービスを管理し、必用なときに起動させるデーモンです。
このxinetdでsshのIP制限とアクセスログの記録を行います。

インストール

yum -y install xinetd
> xinetd.x86_64 2:2.3.14-20.el5_10
ls /etc
> xinetd.confとxinetd.dフォルダが作成される

SSH設定

// 自動起動
chkconfig xinetd on
service sshd stop
chkconfig sshd off
cd /etc/xinetd.d/
vim ssh
————————
// 設定するサービス名を指定(/etc/servicesファイルに定義されたサービス名を指定)
service ssh
{
// サービスの停止指定
// no=サービスを起動する
disable =no
// サービスが使用するソケットタイプ
// stream=TCP
// dgram=UDP
// raw=IPダイレクトアクセス
// seqpacket=sequenced packet
socket_type =stream
// マルチスレッド
// yes=1つしかsshを受け付けない
// no=リミットまで受け付ける
wait =no
// サービスを実行するユーザ名
user =root
// 起動するサービスを絶対パスで指定
server =/usr/sbin/sshd
// サービスに渡す引数
server_args =-i
// 接続に成功した場合に記録するログの種類を指定(下記をスペース区切りで繋げられる)
// PID=サービスのプロセスID
// HOST=リモートホストのIPアドレス
// USERID=リモートホストの認証ユーザ名(マルチスレッド+TCPでのみ有効)
// EXIT=サービス終了シグナルを受けたのかを記録
// DURATION=セッション周期(秒)
log_on_success += DURATION HOST USERID
// 接続に失敗した場合に記録するログの種類を指定
// HOST=リモートホストのIPアドレス
// USERID=リモートホストの認証ユーザ名(マルチスレッド+TCPでのみ有効)
// ATTEMPT=起動に失敗した場合の記録
// RECORD=サービスが起動しなかった場合の諸事情を記録
//  設定するとエラー Bad log_on_failure flag: RECORD [file=/etc/xinetd.d/ssh] [line=10]
log_on_failure += HOST USERID
}
———————–
/etc/init.d/xinetd start

共通設定

vim /etc/xinetd.conf
defaults
{
// ログ出力方法を定義
log_type = SYSLOG daemon info
log_on_failure = HOST
log_on_success = PID HOST DURATION EXIT
// 毎秒ごとの可能な接続数上限の設定
// 第1引数=1秒間で処理可能な数
// 第2引数=上限を超えた後サービスが停止し再開するまでの時間
cps = 50 10
// 起動できるデーモンの数
instances = 50
// 同じクライアントからの接続数制限
per_source = 10
v6only = no
groups = yes
umask = 002
}

ログ出力

基本は
/var/log/messages
に出力される
別ファイルに出したい場合は
log_type = FILE ファイル名
を指定するとファイルにログが吐出される(log_typeは型も含めて2つで問題ない)

IP制限

個別指定に
lonly_from = 192.168.7.{23,91}
のようにすると23と91だけ許可になる

注意点

selinuxは停止しておかないと接続できない可能性があります。

[Ruby] コンソールアプリで表を出力しよう

0

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

コンソールアプリで表を出力しよう

 この記事について

メンテナンスや日々の確認のために

ちょっとしたスクリプトを書くことがあります。

データなどを確認したい場面では

タブ区切りでのテキストを出力していましたが

データ量が大きくなると視認性が悪くなります。

そこでコンソール上でも表を出力したい!

となります。

※記事内でソースコードを変更する箇所がありますが、利用する場合は自己責任でお願いします。

 formatador

rubygemsでインストールができる

formatador

を使うこととします。

簡単な使い方は以下の通りです。

#-*- coding: utf-8 -*-
require "rubygems"
require "formatador"

data = [
  {:name => "taro", :age => 30},
  {:name => "hanako", :age => 25}
]

Formatador.display_compact_table(data, [:name, :age])
#第2引数で列順を指定
  +--------+-----+
  | name   | age |
  +--------+-----+
  | taro   | 30  |
  | hanako | 25  |
  +--------+-----+

実行すると上記のように表が出力されます。

 日本語表示でずれる

スクリプト上のdataを以下のように変更して出力してみます。

data = [
  {:name => "太郎", :age => 30},
  {:name => "花子", :age => 25}
]
  +------+-----+
  | name | age |
  +------+-----+
  | 太郎   | 30  |
  | 花子   | 25  |
  +------+-----+

ずれました。

マルチバイト文字に対応させてみます。

formatador-0.2.4/lib/formatador/table.rb

を以下のように修正しました。

--- table.rb.org 
+++ table.rb 
@@ -1,3 +1,9 @@
+class String
+  def width
+    chars.inject(0){|s,c| s += c.bytesize > 1 ? 2 : 1}
+  end
+end
+
class Formatador
   def display_table(hashes, keys = nil, &block)
     new_hashes = hashes.inject([]) do |accum,item|
@@ -14,7 +20,7 @@
     # Calculate Widths
     if hashes.empty? && keys
       keys.each do |key|
-        widths[key] = key.to_s.length
+        widths[key] = key.to_s.width
       end
     else
       hashes.each do |hash|
@@ -52,7 +58,7 @@
     # Display data row
     columns = []
     headers.each do |header|
-      columns << "[bold]#{header}[/]#{' ' * (widths[header] - header.to_s.length)}"
+      columns << "[bold]#{header}[/]#{' ' * (widths[header] - header.to_s.width)}"
     end
     display_line("| #{columns.join(' | ')} |")
     display_line(split)
@@ -80,7 +86,7 @@
   private

   def length(value)
-    value.to_s.gsub(PARSE_REGEX, '').length
+    value.to_s.gsub(PARSE_REGEX, '').width
   end

   def calculate_datum(header, hash)

再度出力してみます。

  +------+-----+
  | name | age |
  +------+-----+
  | 太郎 | 30  |
  | 花子 | 25  |
  +------+-----+

ずれなくなりました!

環境

ruby 1.9.3p484

formatador 0.2.4

少人数チームにおけるプロジェクト管理のベストプラクティス

0

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

Redmine+Git+GitLab+Jenkinsを使ったプロジェクト管理について、自らの経験して実際にかなり利便性が高いと思えた内容をフロー化してスライドにまとめてみました。

■ 概要

チケット管理ツール(Redmine), バージョン管理ツール(Git), Git管理ツール(GitLab), CIツール(Jenkins) を総合的に利用した少人数チームでのプロジェクト管理について、自らの経験して実際にかなり利便性が高いと思えた内容をフロー化してスライドにまとめてみました。

前置きが長くても仕方がないので早速下記スライドをご覧ください。

■ 本編(スライド)

■ 関連リンク

Comableのページ: hyoshida/comable

最近人気な記事