Posts Tagged ‘Rails’

, | No Comments | 1月 8th, 2009

MacBookもSSDに入れ替えて完全にSSD厨な感じだけど、環境構築してたら MySQL + Ruby でつまづいたのでメモしとく。

Ruby は、MacPorts で 1.8.7 をインストール。MySQL は、MySQL公式のダウンロードページ から、Mac OS X 10.5 (x86_64) をインストールした(これが良くなかったみたい)。

このあと、いつものように

% sudo gem install mysql -- --with-mysql-config /usr/local/mysql/bin/
mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed

ってやってインストールするんだけど、

% script/console
=> Booting WEBrick...
dyld: lazy symbol binding failed: Symbol not found: _mysql_init
  Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
  Expected in: dynamic lookup

dyld: Symbol not found: _mysql_init
  Referenced from: /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle
  Expected in: dynamic lookup

って出てしまう。

ぐぐってみると、同じ症状が出てる人がいた。Leopard MacbookにMySQLをインストール〜Railsで使えるようにするまで
(http://blog.digital-squad.net/article/92963519.html) を参考にさせて頂いて、試してみる

% sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed

しかし・・・

% script/console
Loading development environment (Rails 2.0.2)
/Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle: dlopen(/Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle, 9): no suitable image found.  Did find: (LoadError)
        /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle: mach-o, but wrong architecture - /Library/Ruby/Gems/1.8/gems/mysql-2.7/lib/mysql.bundle       from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
        from /Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require'
        from /Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
        from /Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require'
        from /Users/chu/rails/viena/config/environment.rb:97
        from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
        from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:31:in `require'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/init.rb:253:in `load_modules'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/init.rb:251:in `each'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/init.rb:251:in `load_modules'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/init.rb:21:in `setup'
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb.rb:54:in `start'
        from /usr/bin/irb:13

違うエラーになった。

下記を試せばいいっていう書き込みもあったけど、どうやら、x86_x64 のMySQL を使うとこれが出るっぽい。

% sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed

というわけで、Mac OS X 10.5 (x86) を改めて入れ直して、

% sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed

ってやったら普通に動いた。うーん。

友達曰く、port で入れれば普通に動くのに。らしい(‘A`)

| No Comments | 12月 3rd, 2008

 複数プロセスを立ち上げていても、script/runner 等で叩くときも並行して同じ処理を走らせないようにするとき、ファイルのロックを使うのが簡単です。

ソース

#{RAILS_ROOT}/lib/batch_lock.rb という名前で下記を保存する。

# 同一処理を並行で走らせない様にするモジュール
class BatchLockException < Exception; end
module BatchLock
  # 処理を排他ロックして走らせる
  def self.run(batch_name)
    FileUtils.mkdir(RAILS_ROOT + '/tmp/batch_lock') unless File.exists?(RAILS_ROOT + '/tmp/batch_lock')
    # batch_name をスコープとして排他処理される。
    File.open("#{RAILS_ROOT}/tmp/batch_lock/#{batch_name}", 'w') do |f|
      if f.flock(File::LOCK_EX | File::LOCK_NB)
        yield
      else
        raise BatchLockException.new
      end
    end
  end
 
  # 処理が走っているか確認する
  def self.running?(batch_name)
    FileUtils.mkdir(RAILS_ROOT + '/tmp/batch_lock') unless File.exists?(RAILS_ROOT + '/tmp/batch_lock')
    # ロック用のファイル名は、バッチごとにユニークにする。
    File.open("#{RAILS_ROOT}/tmp/batch_lock/#{batch_name}", 'w') do |f|
      ! f.flock(File::LOCK_EX | File::LOCK_NB)
    end
  end
end

使い方

同時に走らせたくない処理をブロックで実行する。

begin
  BatchLock.run(:go_to_park) do
    # ユーザがみんな公園に行く
    User.find(all).each(&:go_to_park)
  end
rescue BatchLockException
  logger.error "既にバッチが走っていた…。"
end

今バッチが走ってるか確認する。

p BatchLock.running?(:go_to_park) ? 'バッチ進行中' : 'バッチは走ってない'

| No Comments | 10月 27th, 2008

 Railsで、ユーザが500万件居たりすると User.find(:all) とかやっただけでかなりきつい。こういうのをやるときって、バッチ処理だと思うんだけど、結構工夫してループ内で何回も find したりしても、メモリ足りなくなったりするから、結局 script/runner で Rails の起動コストを引いても シェルスクリプト回したほうが安全っていう結論になる。

 50000件ずつループで処理して、Railsを再起動みたいな感じになる。

#!/bin/sh
limit=50000
count=50000
while [ $count -le 5000000 ];
do
  script/runner "User.find(:all, :offset => $count,  :limit => $limit, :conditions => ['migration_complete = false']).each(&:check_email)"
 
  echo "$count"
  count=`expr $count + 5000`
done

| 3 Comments | 10月 6th, 2008

 デフォルトで用意されている Basic 認証の仕組みの使い方。ユーザ名 chihaya , パスワード password72 とすると、以下のようにする。

class ApplicationController < ActionController::Base
  before_filter :basic_authentication
  # テストだけ使うBasic認証
  protected
  def basic_authentication
    authenticate_or_request_with_http_basic do |user, pass|
      [user, pass] == ['chihaya', 'password72']
    end
  end
end

特定のActionはBasic認証かけたくないならば、skip_before_filter を使う。

class NanohaController < ApplicationController
  skip_before_filter :basic_authentication, :only => [:show]
 
  def show
  end
end

| 2 Comments | 9月 28th, 2008

 Rails で以下のメソッドで 該当アクションへの URL を生成することが出来るけれども、呼ぶ場所によって挙動が違ってちょっとつまずいた。

url_for :controller => 'user', :action => 'show', :id => 100

動かしてるサーバが http://localhost:3000 とすると、以下の様になりました。

Controller内
http://localhost:3000/user/show/100
View, Helper内
/user/show/100

View, Helper 内で絶対URL をとるのに一番簡単そうなのは、config/route.rb に以下のように書いて、それを呼ぶという感じかなぁ…。

config/route.rb

ActionController::Routing::Routes.draw do |map|
  map.user '/user/show/:id', :controller => 'user', :action => 'show'
end

viewやhelperで

config/route.rb で map.user と定義すると、user_url() が定義されて使えるようになるので、viewやhelper で以下の感じで以下のようにすると絶対URLが取れます。

user_url(:id => 100)

View から絶対URL を取りたいとすると、どっか外部に戻りURLをくっつけて投げる処理などで使うくらいしか思いつかないです。

download the hurt locker