コミックマーケット87のお知らせ

おしらせ

中の人が主催しているサークル ProjectHL2 にて2014年末に開催されるコミックマーケットで新作を頒布します。
配置は3日目東、ル02bになります。


全5曲入り、「巡音ルカ」によるボーカル曲集で頒布価格は500円を予定しております。

クロスフェード

プレイヤー埋め込みがはてなブログでしか使えないようなのでとりあえずリンクで。
https://soundcloud.com/projecthl2/c87-xfade

追記

ニコニコ動画にもアップしてみました
D

rbenv の更新をした後 rbenv install がエラーになった話と gcc の更新

大きな開発が一段落したので環境の更新をしておこう、と思い年単位ぶりくらいに

brew update
brew upgrade rbenv ruby-build

を叩き、せっかくだから記事執筆時にリリースされたばかりの最新版 Ruby 2.1.5 をインストールしようと

rbenv install 2.1.5

を実行したところ gcc 関連のエラーが出てインストールができず。

Homebrew のログを読んでみると、更新時に削除されたフォーミュラ一覧に

apple-gcc42

の文字を発見。

せっかくなので gcc のバージョンも更新してみようと思い

brew tap homebrew/versions
brew install gcc47

と実行。gcc のインストールを行うので、30分程度はかかりました。

インストールが終わると

/usr/local/Cellar/gcc47/4.7.4: 1000 files, 126M, built in 36.7 minutes

のようにインストールされたパスが表示されるので export でコンパイラを指定します。

export CC=/usr/local/Cellar/gcc47/4.7.4/bin/gcc-4.7

終わったら改めて

rbenv install 2.1.5

エラー無くインストールされる事を確認しました。

追記

既存でインストールしていた分の ruby おそらくすべてのバージョンで OpenSSL のエラーが発生していました。
インストール済のバージョンで使うものすべてを再インストールすれば問題ないようです。

rbenv uninstall 2.0.0
rbenv install 2.0.0

wicked_pdf で Rails が送信するメールに PDF を添付する

表題の件ですが、案外はまってしまったので備忘録。

前提

以下の環境で確認

メーラーの準備

元々のコードがこうだったとして

class NotifyMailer < ActionMailer::Base
  def customer(mail_object, document)
    @mail_object = mail_object
    @document = document
    mail from: @mail_object.from,
      to: @mail_object.to,
      subject: @mail_object.title
  end
end

ファイルの添付は次のように行います。

class NotifyMailer < ActionMailer::Base
  def customer(mail_object, document)
    @mail_object = mail_object
    @document = document
    # ここから
    attachments["#{@document.title}.pdf"] = WickedPdf.new.pdf_from_string(
      render_to_string pdf: "#{@document.title}.pdf",
        template: 'documents/show.pdf.erb',
        no_background: false
    )
    # ここまで
    mail from: @mail_object.from,
      to: @mail_object.to,
      subject: @mail_object.title
  end
end

no_background オプションは背景画像を表示したい場合に指定してください。

また、ヘルパーメソッドを使いたい時は

  add_template_helper ApplicationHelper

を追加するのを忘れないようにします。

Rails の database.yml で collation を指定する

定期的に引っかかるので備忘録として。検証には Rails 4.0.8 及び Mysql 5.6.10 を使用しました。

Rails から MySQL を使う際、何も考えずにデフォルトのまま設定していくと、大体の場合小文字 a と大文字 A が区別されないデータベースが作成されます。具体的にサンプルを示すと

SELECT 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         1 |
+-----------+

このように 'a' = 'A' が真となってしまいます。主にメールアドレスなどの一貫性を保証したい時に問題になります。

こうした問題を解消するために使われるのが collation の指定です。バージョン 5.1 の記事ですが、公式ドキュメントはこちら。

http://dev.mysql.com/doc/refman/5.1/ja/charset-unicode-sets.html

詳しい解説は省きますが、今回は utf8_bin を collation に指定できれば問題が解決します。

新規作成する場合

config/database.yml に記述を追加します。

development:
  adapter: mysql2
  encoding: utf8
  collation: utf8_bin
  reconnect: false
  database: some_project_dev
  username: username
  password: password
  host: localhost

後は普段のように rake db:create からスタートすれば問題ありません。

既存のテーブルを何とかする場合

既存のデータベースについて設定を変更するには MySQL のクエリを直接発行する必要があります。

ALTER DATABASE dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;

しかし、この設定が適用されるのは上記クエリの受付後に作られたテーブル等のみで、既存のデータについてはどうしても区別ができないようです。そのような場合、明示的に BINARY オペレータを用いる事で比較を行います。

SELECT BINARY 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         0 |
+-----------+

ただし、この方法はパフォーマンス的にあまりオススメされないらしいので、必要なのであれば極力最初から大文字小文字(あるいはその他の何か)が区別可能なデータベースを作成するようにした方がいいでしょう。

wicked_pdf を Rails アプリケーションで使うまで

html から簡単に PDF が作れる便利なプラグインですが、割と面倒な行程が必要だったのでメモ。Rails 4.1 で確認しました。

インストール

Gemfile で以下のように記述します。

gem 'wkhtmltopdf-binary'
gem 'wicked_pdf'

が、環境によってはこれでは動作しません。具体的に言うとコンソールで

wkhtmltopdf

と叩いてパスが通っていないなら動作しません。
この場合、自分で wkhtmltopdf をインストールした後 config/initializers に wicked_pdf.rb というファイルを作成し、環境にあわせて実行パスをフルパスで設定します。

WickedPdf.config = {
    :wkhtmltopdf => '/path/to/wkhtmltopdf'
}
2014-09-25 追記

上記の設定では、追記現在の最新版では正しく動作しません。
以下のように書き換えてください。

WickedPdf.config = {
    :exe_path => '/path/to/wkhtmltopdf'
}

PDF を表示する

wicked_pdf を使うと Rails の render で :pdf が指定可能になります。
routes.rb で

resources :items

と指定されているとして items_controller の show メソッドを編集します。

def show
  @item = Item.find(params[:id])
  respond_to do |f|
    f.html
    f.pdf do
      render pdf: @item.title, encoding: 'UTF-8', layout: 'pdf.html'
    end
  end
end

このように指定すると @item.title が PDF のタイトルとして使われます。また encoding オプションは日本語を使いたい場合、レイアウトの指定は PDF の作成時に使うレイアウトを変えたい場合に必要となるので、事実上必須と言っていいでしょう。

あとは http://localhost/items/1.pdf のようにアクセスすると PDF が表示されるはずです(この段階でエラーになる場合、上記インストール部分を再度確認してください)。

レイアウトや CSS を正しく反映させる

レイアウトファイルについては以下のようなテンプレートを使います。これは erb ですが haml の場合も同じように指定してください。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <%= wicked_pdf_stylesheet_link_tag 'pdf' %>
</head>
<body>
  <%= yield %>
</body>
</html>

wicked_pdf_stylesheet_link_tag を使うのがポイントで、ここで指定した pdf.css を使うようになります。


大体の場合においてブラウザで表示するレイアウトや CSS と PDF にする CSS は別にしたいと考えるはずですが、その場合は app/assets/stylesheets 以下に pdf などのディレクトリを作成し config/environments/production.rb で

config.assets.precompile += %w( pdf/pdf.css )

のようにプリコンパイルさせるファイルを追加して

<%= wicked_pdf_stylesheet_link_tag 'pdf/pdf' %>

と指定すれば問題ありません。

背景の画像を表示する

CSS の background で指定した画像を表示させるのも素直にはいきません。
まず、先ほどのコントローラーを修正します。

def show
  @item = Item.find(params[:id])
  respond_to do |f|
    f.html
    f.pdf do
      render pdf: @item.title, encoding: 'UTF-8', layout: 'pdf.html', , no_background: false
    end
  end
end

no_background: false を追加していますが、これを指定しないと何をしても背景画像は表示されません。

次に、公式フォーラムによるとバージョンによっては jpg 以外の画像は表示されないようです(私が試した限りでは png も表示されましたが…)。特に問題がないのであれば、念のため jpg にしておいた方がいいでしょう。

最後に CSS の内部で background を指定する箇所ですが app/assets/stylesheets/pdf/pdf.css を pdf.css.erb にリネームした上で、次のように指定しました。

background: url(<%= Rails.root.join('public', 'images', 'hoge.jpg') %>) right center no-repeat;

ここだけは内部のパス、それもフルパスで指定しないと wkhtmltopdf が読めないのでしょうか。ともあれ、これで画像も表示されるはずです。

なお Rails 4.1 では pdf.css.erb と名前をつけたファイルについても config/environments/production.rb で

config.assets.precompile += %w( pdf/pdf.css )

と指定すればプリコンパイルの対象としてくれるようでした。動作がおかしい場合 public/assets 以下を確認し、対象の CSS ファイルが本当に作成されているか等を確認してみてください。

jQuery.ajax() で読んで来るデータをキャッシュさせない

次のコードは正しく動作しますが、サーバやブラウザの設定によってはデータを更新してもキャッシュが読まれてしまいます。

$.ajax({
  type: 'GET',
  dataType: 'json',
  url: 'hoge.json',
  success: function(data) {
    concole.log(data);
});

これを避けるには cache オプションを false に設定します。

$.ajax({
  type: 'GET',
  dataType: 'json',
  cache: false,
  url: 'hoge.json',
  success: function(data) {
    concole.log(data);
});

ちなみに jQuery.getJson() や jQuery.get() などのメソッドには cache オプションはバージョン 2.1.1 現在では存在しないようです。

そのようなケースでは、先に jQuery.ajaxSetup() で同様に設定することで対処できるようです。

$.ajaxSetup({
  cache: false
});

参考

公式ドキュメント
http://api.jquery.com/

ActiveModel::Model で簡単に ActiveModel の機能を利用する

例えばユーザからの問い合わせを受け付けるメールフォームなど、特にデータベースに値を保存したりする必要はないが ActiveModel の機能は使いたいケースで Rails 4 では ActiveModel::Model をインクルードする事で簡単に処理できます。

class MailForm
  include ActiveModel::Model

  attr_accessor :name, :email # 属性はこのように定義する
end

同じような事を Rails 3 で行う場合に次のような記述をした事があるのですが、これと比較するとかなりすっきりしています。

class MailForm
  include ActiveModel::Conversion
  include ActiveModel::Validations
  include ActiveModel::Validations::Callbacks
  extend ActiveModel::Naming
  extend ActiveModel::Translation

  attr_accessor :name, :email

  def attributes=(params)
    params.each do |k, v|
      send("#{k}=", v.html_safe)
    end
  end

もちろんバリデーションもそのまま使えます。

class MailForm
  include ActiveModel::Model

  attr_accessor :name, :email # 属性はこのように定義する

  validates :name,  presence: true
end

なお API はこちら。

http://api.rubyonrails.org/classes/ActiveModel/Model.html

これによると ActiveModel::Model にインクルードされているのは ActiveModel::Validations と ActiveModel::Conversion との事ですが i18n_generators を用いた i18n にも対応しています。
ただし日本語化する時に config/locales/translation_ja.yml で次のように指定してもうまく翻訳されません。

ja:
  activerecord:
    models:
      mail_form: メールフォーム

  attributes:
    mail_form:
      name: 名前
      email: メールアドレス

以下のように指定すると翻訳が行われるようになります。

  activemodel:
    models:
      mail_form: メールフォーム

  attributes:
    mail_form:
      name: 名前
      email: メールアドレス