@ledsun blog

無味の味は佳境に入らざればすなわち知れず

RDBを使わずにActiveRecordのインスタンスをつくる

ActiveRecordソースコードを読みたいです。 プログラムのソースコードを読むときは、実際に動かしてみて、動きを追っていくと理解が早いです。

ActiveRecordはデータベースのスキーマ情報を元にインスタンスをつくります。 単にPost.newを実行しても次のように例外が出ます。*1

~ bundle exec irb -r active_record
irb(main):001:0> class Post < ActiveRecord::Base; end
=> nil
irb(main):002:0> Post.new
/Users/shigerunakajima/rails/activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb:208:in `retrieve_connection': No connection pool for 'ActiveRecord::Base' found. (ActiveRecord::ConnectionNotEstablished)

ここでデータベースを用意するのは面倒です。 次の方法で、ActiveRecordインスタンスが作成可能です。

~ bundle exec irb -r active_record
irb(main):001:0> ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
=>
#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x00007f8bc4058b18
 @async_executor=nil,
 @automatic_reconnect=true,
 @available=
  #<ActiveRecord::ConnectionAdapters::ConnectionPool::ConnectionLeasingQueue:0x00007f8bc401e9b8
   @cond=#<MonitorMixin::ConditionVariable:0x00007f8bc401e6e8 @cond=#<Thread::ConditionVariable:0x00007f8bc401e508>, @monitor=#<Monitor:0x00007f8bc4052b78>>,
   @lock=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x00007f8bc4058b18 ...>,
   @num_waiting=0,
   @queue=[]>,
 @checkout_timeout=5.0,
 @connection_klass=ActiveRecord::Base,
 @connections=[],
 @db_config=#<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007f8bb4057160 @configuration_hash={:adapter=>"sqlite3", :database=>":memory:"}, @env_name="default_env", @name="primary">,
 @idle_timeout=300.0,
 @lock_thread=false,
 @mon_data=#<Monitor:0x00007f8bc4052b78>,
 @mon_data_owner_object_id=5160,
 @now_connecting=0,
 @pool_config=
  #<ActiveRecord::ConnectionAdapters::PoolConfig:0x00007f8ba409e070
   @_mutex=#<Thread::Mutex:0x00007f8ba409df30>,
   @connection_klass=ActiveRecord::Base,
   @db_config=#<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007f8bb4057160 @configuration_hash={:adapter=>"sqlite3", :database=>":memory:"}, @env_name="default_env", @name="primary">,
   @pool=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x00007f8bc4058b18 ...>>,
 @query_cache_enabled=#<Concurrent::Map:0x00007f8bc4051110 entries=0 default_proc=#<Proc:0x00007f8bc4046760 /Users/shigerunakajima/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:32>>,
 @reaper=#<ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper:0x00007f8bc401ddb0 @frequency=60.0, @pool=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x00007f8bc4058b18 ...>>,
 @size=5,
 @thread_cached_conns=#<Concurrent::Map:0x00007f8bc4034088 entries=0 default_proc=nil>,
 @threads_blocking_new_connections=0>
irb(main):002:1* ActiveRecord::Schema.define do
irb(main):003:2*   create_table :users, force: true do |t|
irb(main):004:2*     t.string :role
irb(main):005:2*     t.datetime :disabled_at
irb(main):006:1*   end
irb(main):007:0> end
-- create_table(:users, {:force=>true})
   -> 0.0101s
=> "default_env"
irb(main):008:0> class User < ActiveRecord::Base; end
=> nil
irb(main):009:0> User.new
=> #<User:0x00007f8be4a2dec0 id: nil, role: nil, disabled_at: nil>

pocke.hatenablog.com

を、読んでいて「へー、そんな書き方ができるんだー」と思い、やってみました。

追記

qiita.com

が、元ネタだそうです。pockeさんに教えていただきました。

ほかにも便利テンプレートファイルが rails/guides/bug_report_templates at main · rails/rails · GitHub に!

*1:git cloneしたrailsディレクトリで実行しているので、何気なくactive_recordが読み込めています。