フォーチュンサモナーズ
最新 追記

Don'tStopMusic

2003|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|02|03|04|05|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|

カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年

知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。


2005-02-17 この日を編集

_ [Ruby] rails ではまる このエントリーを含むブックマーク

るびま5号 を読んで rails を試してみました。で、さっそくはまってしまいました。既知の問題だとは思いますので、最初に ML でも調べればよかったのでしょうが……

コントローラの名前として既存の(インストール済みで利用可能な) Ruby のライブラリ名を指定すると、アクションの実行時にコントローラではなくライブラリがロードされてしまいます。

例えば、続・RubyOnRails を使ってみる で DebateController を作成し、scaffold を指定するところまで行ったとします。ここで、 続けて Profile という名前のコントローラを生成します。

$ ruby script/generate controller Profile

Debate と同様に scaffold を使います。

app/controllers/profile_controller.rb
class ProfileController < ApplicationController
   scaffold :topic
end

webrick を起動して http://localhost:3000/profile にアクセスします。

$ ruby script/server
=> Rails application started on http://127.0.0.1:3000
[2005-02-17 10:52:40] INFO  WEBrick 1.3.1
[2005-02-17 10:52:40] INFO  ruby 1.8.2 (2005-02-15) [i686-linux]
[2005-02-17 10:52:40] INFO  WEBrick::HTTPServer#start: pid=14602 port=3000
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
1150.00     0.46      0.46        1   460.00   460.00  Profiler__.start_profile
  0.00     0.46      0.00        1     0.00     0.00  Mutex#locked?
  0.00     0.46      0.00        1     0.00     0.00  Array#each
  0.00     0.46      0.00        2     0.00     0.00  String#==
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPServlet::AbstractServlet#service
  0.00     0.46      0.00        1     0.00     0.00  Dispatcher#dispatch
  0.00     0.46      0.00        1     0.00    40.00  #toplevel
  0.00     0.46      0.00        2     0.00     0.00  Hash#[]
  0.00     0.46      0.00        1     0.00     0.00  Dependencies.load?
  0.00     0.46      0.00        1     0.00     0.00  Dependencies.mechanism
  0.00     0.46      0.00        2     0.00   230.00  Dependencies.require_or_load
  0.00     0.46      0.00        1     0.00     0.00  Errno::ENOTCONN#===
  0.00     0.46      0.00        2     0.00     0.00  String#downcase
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPRequest#fixup
  0.00     0.46      0.00        2     0.00     0.00  Hash#default
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::GenericServer#start
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPServer#run
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPRequest#body
  0.00     0.46      0.00        1     0.00     0.00  Thread#current
  0.00     0.46      0.00        4     0.00     0.00  Module#===
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::SimpleServer#start
  0.00     0.46      0.00        1     0.00     0.00  DispatchServlet#handle_mapped
  0.00     0.46      0.00        1     0.00     0.00  DispatchServlet#handle_dispatch
  0.00     0.46      0.00        1     0.00     0.00  ActionController::Helpers::ClassMethods.inherited
  0.00     0.46      0.00        1     0.00     0.00  ActionController::Dependencies::ClassMethods.inherited_without_helper
  0.00     0.46      0.00        1     0.00     0.00  DispatchServlet#dispatch
  0.00     0.46      0.00        1     0.00     0.00  String#empty?
  0.00     0.46      0.00        1     0.00     0.00  DispatchServlet#do_GET
  0.00     0.46      0.00        1     0.00     0.00  Enumerable.member?
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPServer#service
  0.00     0.46      0.00        1     0.00     0.00  WEBrick::HTTPRequest#read_body
  0.00     0.46      0.00        2     0.00     0.00  WEBrick::HTTPRequest#[]
  0.00     0.46      0.00        2     0.00     0.00  Array#empty?
  0.00     0.46      0.00        1     0.00     0.00  Exception#backtrace
  0.00     0.46      0.00        2     0.00     0.00  Kernel.==
  0.00     0.46      0.00        1     0.00     0.00  Object#const_missing
/usr/local/lib/ruby/1.8/profiler.rb:27: undefined method `[]' for nil:NilClass (NoMethodError)
        from /usr/local/lib/ruby/1.8/profiler.rb:5:in `dispatch'
        from script/server:49:in `dispatch'
        from script/server:49

debug とか socket とかでも同様に変なことになります。コードも読まず、コントローラ名と実行結果との因果関係に気付くこともなく、「development 環境だから裏で profiler 動かしてパフォーマンスチューニングのデータを採っているんだろう。よく出来ているなあ」などと勝手に考えて、見当違いのところを調べていました……

環境は以下の通り。

  • ruby 1.8.2 (2005-02-15) [i686-linux]
  • mysql Ver 11.18 Distrib 3.23.57, for pc-linux (i686)
  • actionmailer (0.6.1)
  • actionpack (1.4.0)
  • activerecord (1.6.0)
  • rails (0.9.5)
  • rake (0.4.15)

2005-02-26 この日を編集

_ [Ruby] MT のデータベースに ActiveRecord を使ってみる このエントリーを含むブックマーク

ActiveRecord の勉強をするのに何か良い題材がないかと考えていましたが、それなりに複雑でそれなりに知っている MovableType のデータベースにします。

環境

MT は mt-load.cgi でテーブル作成済み。

  • Movable Type 3.151 ja
  • mysql Ver 12.22 Distrib 4.0.22, for pc-linux-gnu (i686)
  • ruby 1.8.2 (2004-12-25) [i686-linux]
  • activerecord 1.7.0

_ [Ruby][ActiveRecord] mt_author へアクセス このエントリーを含むブックマーク

mt-load.cgi を叩くと初期ユーザが作成されますので、まずはそのデータを Ruby+ActiveRecord で表示するところから。

いきなりコードを書いてみます。

#!/usr/bin/env ruby
require 'rubygems'
require_gem 'activerecord'
require 'pp'
require 'logger'
 
ActiveRecord::Base.logger = Logger.new("debug.log")
ActiveRecord::Base.establish_connection(
  :adapter  => "mysql",
  :host     => "localhost",
  :username => "mt",
  :password => "mt",
  :database => "mt"
)
 
module MT
  class Author < ActiveRecord::Base
  end #Author
end #MT
 
pp MT::Author.find(1)

意図としては

  • mt_author は MT::Author にマッピング
  • 初期ユーザ(id=1)を取得して表示

となります。で、これを実行すると、

$ ruby sample.rb 
/usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/abstract_adapter.rb:377:in `log': Table 'mt.authors' doesn't exist: SELECT * FROM authors WHERE id = 1  LIMIT 1 (ActiveRecord::StatementInvalid)
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:95:in `execute'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:173:in `select'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:73:in `select_all'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:337:in `find_by_sql'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:330:in `find_all'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:346:in `find_first'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:287:in `find'
        from sample.rb:21

などと怒られます。エラーメッセージにも表示されていますが、debug.log に実行しようとした SQL が記録されますので、それを見てみます。

$ tail -1 debug.log
  MT::Author Load (0.000000)   Table 'mt.authors' doesn't exist: SELECT * FROM authors WHERE id = 1 LIMIT 1

データベース mt には authors という名前のテーブルはないと言われています。これは ActiveRecord には、暗黙的なクラス名とテーブル名の命名規則があるためです。上のコードでは Author クラスを定義しましたので、authors テーブルとマッピングしようとします。

マッピングの命名規則
クラス名
単数形
テーブル名
複数形

mt_author というテーブル名は変えられませんので、Ruby のコードの方で何とかしないといけません。何とかするには ActiveRecord::Base.table_name を使います。上のコードの Author クラス定義部分だけを抜き出してみます。

module MT
  class Author < ActiveRecord::Base
    def self.table_name
      "mt_author"
    end
  end #Author
end #MT

再び実行してみるとまだエラーです。さっきとはエラーメッセージが違っていますね。

$ ruby sample.rb 
/usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/abstract_adapter.rb:377:in `log': Unknown column 'id' in 'where clause': SELECT * FROM mt_author WHERE id = 1  LIMIT 1 (ActiveRecord::StatementInvalid)
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:95:in `execute'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:173:in `select'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/connection_adapters/mysql_adapter.rb:73:in `select_all'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:337:in `find_by_sql'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:330:in `find_all'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:346:in `find_first'
        from /usr/lib/ruby/gems/1.8/gems/activerecord-1.7.0/lib/active_record/base.rb:287:in `find'
        from sample.rb:24
 $ tail -1 debug.log
  MT::Author Load (0.000000)   Unknown column 'id' in 'where clause': SELECT * FROM mt_author WHERE id = 1 LIMIT 1

これは、ActiveRecord はデフォルトでは主キーのカラム名を id とみなすためです。mt_author のスキーマを見てみましょう。

mysql> show fields from mt_author;
+-----------------------------+--------------+------+-----+---------+----------------+
| Field                       | Type         | Null | Key | Default | Extra          |
+-----------------------------+--------------+------+-----+---------+----------------+
| author_id                   | int(11)      |      | PRI | NULL    | auto_increment |
| author_name                 | varchar(50)  |      | MUL |         |                |
| author_type                 | tinyint(4)   |      |     | 0       |                |
| author_nickname             | varchar(50)  | YES  |     | NULL    |                |
| author_password             | varchar(60)  |      |     |         |                |
| author_email                | varchar(75)  |      | MUL |         |                |
| author_url                  | varchar(255) | YES  |     | NULL    |                |
| author_can_create_blog      | tinyint(4)   | YES  |     | NULL    |                |
| author_can_view_log         | tinyint(4)   | YES  |     | NULL    |                |
| author_hint                 | varchar(75)  | YES  |     | NULL    |                |
| author_created_by           | int(11)      | YES  |     | NULL    |                |
| author_public_key           | text         | YES  |     | NULL    |                |
| author_preferred_language   | varchar(50)  | YES  |     | NULL    |                |
| author_remote_auth_username | varchar(50)  | YES  |     | NULL    |                |
| author_remote_auth_token    | varchar(50)  | YES  |     | NULL    |                |
+-----------------------------+--------------+------+-----+---------+----------------+
15 rows in set (0.00 sec)

主キーは author_id ですね。これもデータベースの方は変更できませんから、Ruby+ActiveRecord 側でなんとかしなくてはなりません。で、なんとかするのがこのコードです。

ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore

主キーの命名規則を指定します。author テーブルの主キーは author_id でしたので、「テーブル名_id」 という規則であるとしています。

これでまた実行すると、、、

$ ruby sample.rb 
#<MT::Author:0x2af7c7a4
 @attributes=
  {"author_remote_auth_token"=>nil,
   "author_name"=>"Melody",
   "author_can_create_blog"=>"1",
   "author_type"=>"1",
   "author_nickname"=>nil,
   "author_can_view_log"=>"1",
   "author_created_by"=>nil,
   "author_public_key"=>nil,
   "author_id"=>"1",
   "author_password"=>"0osHZ.scFVmok",
   "author_email"=>"",
   "author_remote_auth_username"=>nil,
   "author_url"=>nil,
   "author_hint"=>nil,
   "author_preferred_language"=>"ja"}>

ようやく上手くいきました。

以上で見てきましたように、既に存在しているデータベースに対して ActiveRecord を使って OR マッピングをする場合には、ActiveRecord が想定するデフォルトの命名規則には従っていないことが多いため、定義やオプション設定をする必要があります。どんなパターンに対応できるかは、今のところ ActiveRecord の API で調べるしかないようです。

最終的なコード

#!/usr/bin/env ruby
require 'rubygems'
require_gem 'activerecord'
require 'pp'
require 'logger'
 
ActiveRecord::Base.logger = Logger.new("debug.log")
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
ActiveRecord::Base.establish_connection(
  :adapter  => "mysql",
  :host     => "localhost",
  :username => "mt",
  :password => "mt",
  :database => "mt"
)
 
module MT
  class Author < ActiveRecord::Base
    def self.table_name
      "mt_author"
    end
  end #Author
end #MT
 
pp MT::Author.find(1)
本日のツッコミ(全2件) [ツッコミを入れる]

_ キムキム [残念。。。もうこのページの意味分かりませんから そのページに来た私に切腹。。。]

_ MoonWolf [MTとActiveRecordの両方から同時にDBにアクセスするのでなければ、DBの構造を見直してActiveRec..]


最近のコメント:

  1. MoonWolf (12-19)
  2. キムキム (05-11)

RSS
Creative Commons License
This work is licensed under a Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).