マイグレーション
http://railsdoc.com/references/rake%20db:migrate
実行
$ bundle exec rake db:migrate
バージョン指定
$ bundle exec rake db:migrate VERSION=201010190000
環境指定
$ bundle exec rake db:migrate RAILS_ENV=test
現在のバージョン確認
$ bundle exec rake db:version
前回のマイグレーションを取り消す
$ bundle exec rake db:rollback
CarrierWaveのファイル名変換(original_filename)の挙動
ファイルアップロード機構にCarrierWaveを利用しています。
アップロードしたファイル名は、
self.file_column.file.original_filename
のように取得出来ますが、デフォルトでは日本語を利用出来ません。
ファイル名に日本語を利用する場合、
./config/initializers/carrierwave.rb
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
のように設定します。
ここまではググればすぐ出てくる情報なのですが、
「Simple (1).csv」というファイル名が、「Simple__1_.csv」に変換されることが分かりました。
CarrierWaveのコードを見てみると、先の設定は、
./vendor/bundles/ruby/2.1.0/gems/carrierwave-0.10.0/lib/carrierwave/sanitized_file.rb
def sanitize(name) name = name.gsub("\\", "/") # work-around for IE name = File.basename(name) name = name.gsub(sanitize_regexp,"_") name = "_#{name}" if name =~ /\A\.+\z/ name = "unnamed" if name.size == 0 return name.mb_chars.to_s end
上記の、
name = name.gsub(sanitize_regexp,"_")
で変換されます。
指定した正規表現を「_」に変換するわけです。
[:word:]はPOSIX文字クラスで「単語構成文字」を表現する正規表現になりますので、ここを調整すると修正出来そうです。
http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fregexp.html
調べたところ、
[:print:] 表示可能な文字(空白を含む)
という文字クラスがあり、これを使えばファイル名に制限を無くすことが出来るはず。
./config/initializers/carrierwave.rb
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:print:]]/
としたところ予想通り変換を回避する事が出来たのですが、念のため色々な記号をファイル名に使い試したところ、「+」が「半角スペース」に変換されてしまう事が分かりました。
どうもコードの意図通りに動いていないようです。
pry(main)> "+".gsub("[^[:print:]]","_") => "+"
やはり変換されない。
./vendor/bundles/ruby/2.1.0/gems/carrierwave-0.10.0/lib/carrierwave/sanitized_file.rb
def sanitize(name) name = name.gsub("\\", "/") # work-around for IE name = File.basename(name) name = name.gsub(sanitize_regexp,"_") name = "_#{name}" if name =~ /\A\.+\z/ name = "unnamed" if name.size == 0 return name.mb_chars.to_s end
に渡ってくるパラメータ(name)を見てみたところ、すでに「+」が半角スペースになっていました。
これはコアの動きっぽいと感じつつ、小一時間デバックをしてみたところ原因が分かりました。
./vendor/bundles/ruby/2.1.0/gems/rack-1.5.2/lib/rack/multipart/parser.rb
def get_filename(head) filename = nil if head =~ RFC2183 filename = Hash[head.scan(DISPPARM)]['filename'] filename = $1 if filename and filename =~ /^"(.*)"$/ elsif head =~ BROKEN_QUOTED filename = $1 elsif head =~ BROKEN_UNQUOTED filename = $1 end if filename && filename.scan(/%.?.?/).all? { |s| s =~ /%[0-9a-fA-F]{2}/ } filename = Utils.unescape(filename) end if filename && filename !~ /\\[^\\"]/ filename = filename.gsub(/\\(.)/, '\1') end filename end
上記の、
filename = Utils.unescape(filename)
が犯人でした。
このメソッドの実態は、
./vendor/bundles/ruby/2.1.0/gems/rack-1.5.2/lib/rack/utils.rb
if defined?(::Encoding) def unescape(s, encoding = Encoding::UTF_8) URI.decode_www_form_component(s, encoding) end else def unescape(s, encoding = nil) URI.decode_www_form_component(s, encoding) end end module_function :unescape
で、この中の、
URI.decode_www_form_component
が変換処理を行っていました。
http://docs.ruby-lang.org/ja/2.0.0/method/URI/s/decode_www_form_component.html
ドキュメントを見ると、「"+" という文字は空白文字にデコードします」とあります。
すっきりしました。
ファイル名に"+"が使えないのはRails(Rack)の仕様という事でよさそうです。
GithubのイベントをChatworkに通知する
ChabotというChatworkが提供しているアプリを使います。
http://c-note.chatwork.com/post/69274738468/chabot
上記公式情報に説明がなかった点、修正が必要だった点をご紹介します。
Node環境整備
まずNode.jsの環境を作ります。
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash $ nvm install v5.1 $ npm install express (なくてもよいかな) $ nvm alias default v5.1.1
パスを通す
$ vi .bash_profile if [[ -s ~/.nvm/nvm.sh ]]; then source ~/.nvm/nvm.sh fi
chabotインストール
$ npm install chabot -g
不具合の修正
bots/github.js
にGithub用のプログラムが作成されますが、このままではエラーが出て動きませんでした。
module.exports = function (chabot) { // WebHook で受けたデータをセット var payload = JSON.parse(chabot.data.payload); // ChatWork API の endpoint をセット var endpoint = '/rooms/' + chabot.roomid + '/messages'; // templats/ 内のメッセージテンプレートを読み込む var template = chabot.readTemplate('github.ejs'); // WebHook で受けたデータでメッセージテンプレートを描画 var message_body = chabot.render(template, payload); // ChatWork API でメッセージ送信 chabot.client .post(endpoint, { body: message_body }) .done(function (res) { chabot.log('done'); }) .fail(function (err) { chabot.error(err); }); };
どうも、chabot.roomidに値がセットされないようです。
module.exports = function (chabot) { chabot.roomid = 123456789; // WebHook で受けたデータをセット var payload = JSON.parse(chabot.data.payload); // ChatWork API の endpoint をセット var endpoint = '/rooms/' + chabot.roomid + '/messages'; // templats/ 内のメッセージテンプレートを読み込む var template = chabot.readTemplate('github.ejs'); // WebHook で受けたデータでメッセージテンプレートを描画 var message_body = chabot.render(template, payload); // ChatWork API でメッセージ送信 chabot.client .post(endpoint, { body: message_body }) .done(function (res) { chabot.log('done'); }) .fail(function (err) { chabot.error(err); }); };
のようにroomidを書いてあげる事で解決しました。
Githubの設定
リポジトリのメニュー、
Settings > Webhooks & services > Add webhook
からアプリURLを登録しますが、Content typeを「application/json」にするとパースエラーが発生しました。
「application/x-www-form-urlencoded」とすると正常に動くのですが、NodeアプリなのでJsonで動いて欲しいところです。。
アプリの初期設定では、Pushイベントのみの対応となっています。
templates/github.ejs
IssueとPull Requestへのコメントも通知したかったので、追記したテンプレートが、
https://github.com/t-shida/chabot-github-template
になります。
Githubの設定としては、
Which events would you like to trigger this webhook? > Let me select individual events.
- Push
- Issues
- Issue comment
- Pull request review comment
にチェックを入れます。
Apacheの設定
アプリをポート8080で起動する想定で、バーチャルホストを以下のように設定
<VirtualHost *:80> ServerName chabot.domain.jp ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/ ProxyPreserveHost On </VirtualHost>
ProxyPreserveHostがポイントです。これがないと動きません。
foreverインストール
$ cd ./path/to/app $ node app.js
で起動出来ますが、実際の運用ではデーモンとして動かしたいですので、foreverを利用します。
$ npm install forever -g $ forever start app.js
とします。
あまりメンテされていない印象ですが、以上の内容で正常に動作しており、メールでの確認が億劫なメンバーには好評です。
AASMからRadioボタンを描画する
モデルのAASMはこう。
aasm column: "approving_state" do state :applied state :tested state :rejected state :approved, initial: true event :apply, after: :send_apply do transitions from: [:tested, :rejected, :approved], to: :applied end event :test, after: :send_test do transitions from: :applied, to: :tested end event :reject do transitions from: [:applied, :tested], to: :rejected end event :approve, after: :send_approve do transitions from: :tested, to: :approved end end
これをViewにて表示
<% v = [] Company.aasm.states.each do |s| next if s.state_machine.config.column.to_s != 'approving_state' state = s.name.to_s label = t("activerecord.attributes.company.approving_states.#{state}") event = '' s.state_machine.events.each_key do |k| if s.state_machine.events[k].transitions[0].to.to_s == state event = k.to_s break end end disabled = true disabled = false if @company.send("may_#{event}?") || @company.approving_state == state disabled = true if state == 'applied' && @company.approving_state != 'applied' checked = @company.approving_state == state v.push({:state => state, :label => label, :event => event, :disabled => disabled, :checked => checked}) end %> <% v.each do |r| %> <div class="radio-inline"> <%= f.radio_button :approving, r[:state], {:disabled => r[:disabled], :checked => r[:checked]} %><%= f.label "approving_#{r[:state]}".to_sym, r[:label] %> </div> <% end %>
却下されたけどね。
コンソール
$ rails console -e development
$ rails console -e development --sandbox
$ Rails.env
コンソールリロード
pry(main)> reload!
routes確認
pry(main)> show-routes
スキーマ確認
pry(main)> show-models
SQLを非表示
pry(main)> ActiveRecord::Base.logger = nil
文字コードをUTF8に揃える
show variables like "chara%";
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- +
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Variable_name | Value |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- +
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
character_set_client | utf8 |
character_set_connection | utf8 |
character_set_database | latin1 |
character_set_filesystem | binary |
character_set_results | utf8 |
character_set_server | utf8 |
character_set_system | utf8 |
character_sets_dir | /usr/share/mysql/charsets/ |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- +
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
character_set_client : クライアント側で発行したsql文はこの文字コードになる
character_set_connection : クライアントから受け取った文字をこの文字コードへ変換する
character_set_database : 現在参照しているDBの文字コード
character_set_results : クライアントへ送信する検索結果はこの文字コードになる
character_set_server : DB作成時のデフォルトの文字コード
character_set_system : システムの使用する文字セットで常にutf8が使用されている
/etc/my.cnf
[mysqld] character-set-server=utf8 #mysqldセクションの末尾に追加 [client] default-character-set=utf8 #clientセクションを追加
/etc/init.d/mysqld restart