カテゴリー別アーカイブ: Ruby on Rails

omniauth-google-oauth2はGoogle APIのContacts APIとGoogle+ APIを有効にする必要がある

devise + omniauth-google-oauth2でGoogleアカウントでのログインを実装しているRailsアプリケーションで bundle updateしたら、omniauth-google-oauth2 が0.2.2から0.2.4になり、Googleアカウントでのログインで、invalid credentials が発生するようになった。
0.2.3から、Google APIのContacts APIとGoogle+ APIを有効にしないといけなくなったようだ。

https://github.com/zquestz/omniauth-google-oauth2#google-api-setup

cronでRVMのRubyを使う

RVMで複数のRuby環境がある場合に、Railsアプリケーションのためのcronをどうするか? Rubyのパスはフルパス指定すればいいが、gemがRVMのgemを見に行かないのが問題。RVM環境でcronを実行する必要がある。

RVM: Ruby Version Manager - Using Cron with RVM

cron用のシェルスクリプト内で使用するRVM環境をロードするには以下のようにする。

まず、環境ファイルのパスを確認。

$ rvm env --path -- ruby-version[@gemset-name]

実行例

$ rvm env --path -- 1.8.7-p371
/Users/pistolfly/.rvm/environments/ruby-1.8.7-p371

cron用のシェルスクリプトで環境ファイルを読み込む

source /Users/pistolfly/.rvm/environments/ruby-1.8.7-p371

/home/pistolfly/app_dir
ruby script/runner -e production "ActiveRecord::SessionStore::Session.delete_all(['sessions.updated_at < ?', 6.hours.ago])"

Change PATH environment with Rails and Capistrano

Capfileに

load 'deploy/assets'

を追加すると、デプロイ時にassets:precompileを実行できるが、assets:precompile実行時に、

/usr/bin/env:
ruby
: そのようなファイルやディレクトリはありません

というエラーになってしまった。
ssh経由でのshellの実行時にPATHが通っていないのが原因と思われる。

解決方法

CapistranoでPATH等の環境変数を設定するには、:default_environmentを使う。

set :default_environment, {
  'PATH' => "/opt/ruby-enterprise-1.8.7-2011.03/bin:$PATH"
}

Change PATH environment with Rails and Capistrano - pastbedti.me
How do I configure capistrano to use my rvm version of Ruby - Stack Overflow
プリコンパイルする場合、config/environments/production.rbで、

config.assets.compile = false

にするが、assetsにapplication.js, application.css以外のjs、cssを使う場合は、以下のようにconfig.assets.precompileに追加する必要がある。追加しないと、smart_phone.css isn't precompiled のようなエラーになる。
config/environments/production.rb

config.assets.compile = false
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w( smart_phone.css web_app_theme.css )

Rails3のActionMailerでOpenSSL::SSL::SSLError (hostname was not match with the server certificate)

Rails3でメールを送信したところ、送信できなかった。
ActionMailerの設定は、
config/initializers/02_action_mailer.rb

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
  :address        => "mail.example.com",
  :port           => "587",
  :domain         => "example.com",
  :user_name      => "username",
  :password       => "password",
  :authentication => :cram_md5
}

のようにしている。
同じ設定で、Rails2では送信できている。

原因

ActionMailer::Base.raise_delivery_errors = true

を追加して実行したところ、

OpenSSL::SSL::SSLError (hostname was not match with the server certificate)

となり、SSL証明書の検証で例外が発生しているらしいことが分かった。
また、メールサーバのログでも、

connect from xxxxx
setting up TLS connection from xxxxx
TLS connection established from xxxxx
lost connection after STARTTLS from xxxxx
disconnect from xxxxx

という状態だった。
このメールサーバはテスト用のpostfixで、
smtpd_tls_security_level = may
にしており、
smtpd_tls_cert_file、smtpd_tls_key_file には、自己証明書を設定していた。
Rails3では、STARTTLSがデフォルトで有効になっているためTLSで接続しようとするが、このメールサーバの証明書がテスト用の自己証明書だったので検証に失敗していたのが原因らしい。

解決方法

証明書を正当なものにすればよいと思われるが、テスト環境なのでとりあえず今は自己証明書を使いたい。
そのためには、ActionMailer::Base.smtp_settingsの設定で、STARTTLSを無効にするか証明書の検証を無効にする。

ActionMailer::Base.smtp_settings = {
  :address        => "mail.example.com",
  :port           => "587",
  :domain         => "example.com",
  :user_name      => "username",
  :password       => "password",
  :authentication => :cram_md5,
  :enable_starttls_auto => true,  # STARTTLSを無効にする場合はfalseにする
  :openssl_verify_mode => 'none'  # STARTTLSを有効にしつつ、不正な証明書もOKにしたい場合は、証明書の検証を無効にする
}

証明書の検証を無効にするのは本当はよくないけど、テスト環境等で自己証明書でもOKにしたい場合は、とりあえず上記のようにすれば、TLSでメールが送信できます。
OpenWebOps
email - Postfix & Rails 3.0 ActionMailer: lost connection after STARTTLS - Stack Overflow

ActiveRecord::RecordNotSaved - before_save problem

ActiveRecordのクラスで、before_* コールバック がfalseを返すと、以降の処理がキャンセルされてしまうから、saveもされなくなる。
Rubyのメソッドは最後に評価された式が返り値になるから、うっかりコールバックがfalseを返してしまい、saveで変更が保存されず、「どうしてなのか?」とはまることがある。
そういう時は明示的にメソッドを
true
で終わるようにする。
after_* コールバックがfalseを返す場合も、以降のコールバックがキャンセルされてしまう。

If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.

Sketchpad - Dan Sketcher's personal blog » Blog Archive » ActiveRecord::RecordNotSaved - before_save problem