Railsの設定ファイルを環境毎に書けるプラグインをいつも見失う。なんて名前だったっけ?
rails configとか検索し辛いワードなのでここに記す。(via @fakestarbabyさん)
railsjedi/rails_config - GitHub
SinatraやPadrinoに対応してるのにrails_configとは是如何に。
Railsの設定ファイルを環境毎に書けるプラグインをいつも見失う。なんて名前だったっけ?
rails configとか検索し辛いワードなのでここに記す。(via @fakestarbabyさん)
railsjedi/rails_config - GitHub
SinatraやPadrinoに対応してるのにrails_configとは是如何に。
production環境ではexception_notificationでエラーをメールしてる人も多い思います。(AirBreakとかも)
怖話でもそうやってエラーメールが一通も来ない状態にしたいんですが、例えば下記のような”バグじゃないエラー”は皆様どうやって対応してるんでしょう?
A ActionView::MissingTemplate occurred in home#index:
Missing template home/index, application/index with {:handlers=>[:erb, :builder, :haml], :formats=>["*/*;q=0.01"], :locale=>[:ja, :ja]}. Searched
formatsに*/*;q=0.01なんて文字列を送ってくるのは単なるスパム。使ってるformatだけに限定するように何か書く?うーん・・・。
怖話をruby1.8.7 & rails3.0.8からruby1.9.2 & rails3.1.1の最新状態に更新しました。引っかかったところメモ。
$ rake db:migrate
rake aborted!
couldn't parse YAML at line 267 column 42
rake db:migrate
がエラー。
require 'yaml' YAML::ENGINE.yamler= 'syck'
config/boot.rbの2行目に下記を追加。
require 'yaml'
YAML::ENGINE.yamler = 'syck'
db/seeds.rbで日本語を使ってたので先頭に下記magick commentを追加。
# coding: utf-8
何でもかんでもmagick commentを入れるのは良くないので必要なところにだけ。rubyのm17nは素晴らしいと思います。
ruby1.9.2ではArray#choiceが無くなってる。Array#sampleを使えばいい。
FixturesがActiveRecord::Fixturesになりました。
db/seeds.rbでfixtureを読み込む場合(test用のとは別に用意してる場合とか)
require 'active_record/fixtures'
Fixtures.create_fixtures("#{Rails.root}/db/seed", 'stories')
こんな感じだったんですが、
require 'active_record/fixtures'
ActiveRecord::Fixtures.create_fixtures("#{Rails.root}/db/seed", 'stories')
こうなりました。
developmentで余裕こいてるとproduction世界でひっそり幕を閉じる。(via ブロントさん)
Asset Pipelineを大きく下記の4つに分けて考えるとわかりやすいです。
対象は下記3つ
productionではrake assets:precompile
で上記4つを対象3つに施してpublic/assetsフォルダーに入れ、nginx等のWebサーバーに配信させてrailsは関与しません。アプリ起動前からpublic/assets以下に必要な全てのファイルが揃って準備完了している必要があります。
precompileされるにはファイルがsprocketsの記法= require tree .
等やconfig.assets.precompile += %w()
のリストに入ってる必要があります。ここから漏れているファイルはpublic/assetsに無いことになるので表示されません。
jsの中でひっそり使われてる画像や特定のページでだけ読み込んでるcss、そういえば使ってたjqueryプラグインなど、とても見落としやすいので気を付けなければなりません。
それを乗り越えればnginxでcache期限無限のフィーバー状態です。でも既存アプリのバージョンアップなどでは上記見落としを無くすのはとても難しいと思います。もし見逃しそうならば・・・
config.assets.compileをtrueにするんだな。
おまえにもかぞくがいるだろう…
怖話でコメント欄がスパムで埋め尽くされて困ったので日本語が入ってないコメントは弾くようにしました。
「日本語が入ってない場合弾く」というのはMovableTypeの時からあるやり方ですが、イマイチ綺麗に実装できる感がしなくて控えてました。しかしmojiという素晴らしいgemを使ったら簡単に出来ました。
class Comment < ActiveRecord::Base
validates_format_of :body,
:with => Moji.regexp(Moji::ZEN_ALNUM | Moji::ZEN_KANA | Moji::ZEN_KANJI),
:message => I18n.t('errors.messages.not_a_zenkaku')
end
mojiは色々な文字種の正規表現を持っていて手軽に組み合わせたりできます。最初はMoji::ZENで全角文字があればOKにしました。しかし実データ(スパム)にはギリシャ文字やキリル文字が存在していたのでそれも除外するようにしました。
$ rails c -E production
>> Comment.all.each {|c| c.destroy unless c.valid? }
これで今までの全てのスパムが消滅。今のところ新しいスパムも防げてるようでスッキリ。
以前、update_countersメソッドを使ってカウンターキャッシュを設定したつもりになっていました。しかし、update_countersメソッドは与えた数だけカウンターが増えるという動作だったようです。代わりにreset_countersメソッドを使えばcomments.countの数にresetしてくれるようです。
Story.all.each do |story|
Story.reset_counters(story.id, :comments)
end
Facebookページ・アプリでハマるところシリーズ。
RailsでFacebookアプリ作ります。FacebookアプリはIFRAME内のページをPOSTメソッドで呼び出します。エントリー一覧(/entries)のようなものをFacebookアプリのトップページにしようとしたらアレ?となります。(POSTしたらcreate呼ばれるから)
オーマイゴッド!じゃあ/entries/newをPOSTメソッドも受け入れるようにしてこれをトップにしよう。しかしFacebookアプリは/で終わるURLしか指定できません。仕方ないので/entries/new/を受け入れるようにしよう・・・。
しかしログインしたはずが情報が引き継がれません。おかしいな。
WARNING: Can't verify CSRF token authenticity
ログを見るとCSRF tokenのWARNING。考えてみりゃ当然ですが、FacebookからPOSTで呼ばれる時にはCSRF tokenなんぞ付いてないのでWARNINGが出ます。そして危ないのでsessionは一旦破棄されるわけです。自動ログアウト。
paperclipを使ってて「縦長の画像をアップしたら横長になる」という問題。
これはpaperclipが悪いんじゃなくて、元のファイルもMacのPreviewで見ると縦長なんだけど、ブラウザで見ると横長。MacのPreview他、ExifのOrientationタグに対応したソフトで見ると縦長に見える。
Webアプリ的にはちょっと困る。「縦長の画像をアップしたら横長になった!」と言われても見てるツールの違いで最初から横長なんだから。
imagemagickのconvertにはExifのOrientationタグの内容に合わせて画像データを回転させてくれる超便利な-outo-orientオプションがあるのでそれを使えばいい。
paperclipはrmagickを使わず、convertコマンドを呼び出すだけで、好きなオプションが渡せるというイカシタ作りになっているのでこんな感じでOK。
class User < ActiveRecord::Base
has_attached_file :picture, convert_options: {all: '-auto-orient'}
end
allは複数のstyleが合った場合に全部にこのオプションを付けるという指定。originalも残るから安心。
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env.production?
provider :twitter, 'xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxx'
else
provider :twitter, 'ooooooooooo', 'oooooooooooooooooooo'
end
end
今まで通りだと動きません。test/test_helper.rb
に下記を追加。
require 'shoulda/rails'
今βのshoulda 3.xなら大丈夫なのでもうすぐこれも必要無くなるみたいです。
rails3.1でMySQLからやってくる文字列がASCII-8BITになっているのでto_jsonすると壊れる(to_jsonがencodingを見て処理するので)。sqlite3では起こらない。
環境はSnow Leopard、ruby1.9.2-p290、homebrewで入れたmysql 5.1.54。
% rails new foo
% cd foo
% vi Gemfile
(...)
gem 'mysql'
(...)
% bundle
% vi config/database.yml
(...)
development:
adapter: mysql
encoding: utf8
database: foo_development
pool: 5
username: root
password:
host: localhost
socket: /tmp/mysql.sock
(...)
% rails g model post title:string
% rake db:create
% rake db:migrate
% vi db/seeds.rb
Post.create!(title: 'うんk')
% rake db:seed
% rails c
ruby-1.9.2-p290 :001 > puts Post.first.title
うんk
=> nil
ruby-1.9.2-p290 :002 > Post.first.title.encoding
=> #<encoding:ascii-8bit>
ruby-1.9.2-p290 :003 > puts Post.first.title.to_json
"\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd"
=> nil
CentOS 5.6でも同じ。
解決:
mysql gemはruby1.9.1からのencodingに対応してない。だからmysql2を使えば解決でした。
% vi Gemfile
(...)
gem 'mysql2'
(...)
% vi config/database.yml
(...)
adapter: mysql2
(...)
% rails c
ruby-1.9.2-p290 :001 > Post.first.title.encoding
=> #<Encoding:UTF-8>
adapterにmysql2と書けるというところが盲点でした・・・。
% node -v
v0.4.8
% rails -v
Rails 3.1.0
% rails new foo
% cd foo
% vi app/assets/stylesheets/foo.css.scss
body {
background: image-url("rails.png");
}
% rake assets:precompile
rake aborted!
rails.png isn't precompiled
(in /Users/komagata/tmp/foo/app/assets/stylesheets/foo.css.scss)
Tasks: TOP => assets:precompile
(See full trace by running task with --trace)
何故だろう?
とりあえずはconfig/environments/production.rb
をconfig.assets.compile = true
追記:
rails3.1のバグでした。3.1.1を待て。