【问题标题】:Error when querying ActiveRecord sqlite database in Ruby在 Ruby 中查询 ActiveRecord sqlite 数据库时出错
【发布时间】:2013-10-12 10:57:58
【问题描述】:

我正在使用一些基本的 Ruby 代码来创建一个数据库表并设置一些值,但是在尝试运行代码时我收到一个关于“albums”表已经存在的错误(我使用的是 Ruby 1.9. 3 和 Active Record 4.0.0)。

代码和错误如下,但我的问题是:首先,我怎样才能防止这个错误(因为如果表确实已经存在,那么这个错误是有意义的)其次我如何查看哪些表数据库在命令行上有这些表的内容(使用 Mac OSX 终端 - 我尝试了 sqlite3 命令并查看了帮助文件,但我似乎无法让它做我想做的事?)。

代码是……

# gem install sqlite3
# gem install activerecord

require 'active_record'

ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.establish_connection(
  :adapter  => 'sqlite3',
  :database => 'dbfile_example' # :memory:
)

ActiveRecord::Schema.define do
  create_table :albums do |table|
    table.column :title,     :string
    table.column :performer, :string
  end

  create_table :tracks do |table|
    table.column :album_id,     :integer
    table.column :track_number, :integer
    table.column :title,        :string
  end
end

# Active Records don't specify their attributes directly
# but rather infer them from the table definition with which they're linked

class Album < ActiveRecord::Base
  has_many :tracks # adds additional collection methods to the class
end

class Track < ActiveRecord::Base
  belongs_to :album # specifies a one-to-one association with another Class (only use if this table holds the foreign key)
end

album = Album.create(
  :title     => 'In Utero',
  :performer => 'Nirvana'
) # notice you don't have to include the brackets to indicate it's a Hash

# notice the Album object instance can reference the 'tracks' collection
# via the `has_many` method and the `create` method is one of the additional
# methods added as part of the call to `has_many`

track_listing = [
  nil,
  'Serve the Servants',
  'Scentless Apprentice',
  'Heart-Shaped Box',
  'Rape Me',
  'Frances Farmer',
  'Dumb',
  'Very Ape',
  'Milk It',
  'Pennyroyal Tea',
  'Radio Friendly Unit Shifter',
  'Tourettes',
  'All Apologies'
]

track_listing.each_with_index do |value, index|
  album.tracks.create(:track_number => index, :title => value) if index # zero is falsey so we skip it
end

album = Album.create(
  :title     => 'La-te-ra-lus',
  :performer => 'Tool'
)

track_listing = [
  nil,
  'The Grudge',
  'Eon Blue Apocalypse',
  'The Patient',
  'Mantra',
  'Schism',
  'Parabol',
  'Parabola',
  'Ticks & Leeches',
  'Lateralus',
  'Disposition',
  'Reflection',
  'Triad',
  'Faaip de Oiad'
]

track_listing.each_with_index do |value, index|
  album.tracks.create(:track_number => index, :title => value) if index
end

p Album.find(1).tracks.length
p Album.find(2).tracks.length
p Album.find_by_title('La-te-ra-lus').title
p Track.find_by_title('Very Ape').album_id

...错误是...

-- create_table(:albums)
D, [2013-10-05T14:07:55.478413 #46822] DEBUG -- :    (0.2ms)  CREATE TABLE "albums" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "performer" varchar(255)) 
E, [2013-10-05T14:07:55.478496 #46822] ERROR -- : SQLite3::SQLException: table "albums" already exists: CREATE TABLE "albums" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "performer" varchar(255)) 
/Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/sqlite3-1.3.8/lib/sqlite3/database.rb:91:in `initialize': SQLite3::SQLException: table "albums" already exists: CREATE TABLE "albums" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255), "performer" varchar(255))  (ActiveRecord::StatementInvalid)
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/sqlite3-1.3.8/lib/sqlite3/database.rb:91:in `new'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/sqlite3-1.3.8/lib/sqlite3/database.rb:91:in `prepare'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/sqlite3-1.3.8/lib/sqlite3/database.rb:134:in `execute'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/connection_adapters/sqlite3_adapter.rb:328:in `block in execute'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:425:in `block in log'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activesupport-4.0.0/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:420:in `log'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/connection_adapters/sqlite3_adapter.rb:328:in `execute'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/schema_statements.rb:190:in `create_table'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/migration.rb:625:in `block in method_missing'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/migration.rb:597:in `block in say_with_time'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/1.9.1/benchmark.rb:280:in `measure'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/migration.rb:597:in `say_with_time'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/migration.rb:617:in `method_missing'
  from sqlite-example.rb:13:in `block in <main>'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/schema.rb:42:in `instance_eval'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/schema.rb:42:in `define'
  from /Users/markmcdonnell/.rbfu/rubies/1.9.3-p385/lib/ruby/gems/gems/activerecord-4.0.0/lib/active_record/schema.rb:62:in `define'
  from sqlite-example.rb:12:in `<main>'

【问题讨论】:

  • 此代码是否在单个文件脚本中(例如,一个 .rb 包含所有代码)?如果是这样,那么您确实在尝试每次都创建数据库。如果是这种情况,您可以将该特定部分(表创建)分离到另一个文件中,或者通过在创建表之前删除表来启动脚本:drop_table :albums

标签: ruby-on-rails ruby activerecord sqlite rails-activerecord


【解决方案1】:

我想一种简单的方法是将数据库创建代码包装在begin ... rescue ... end 块中。

你是如何运行命令的?如果我记得,你需要运行sqlite3 your_db_name.db

【讨论】:

  • re:sqlite 命令行 - 我运行了sqlite3,然后运行.help 来查看命令,然后我开始运行它向我显示的命令,但没有一个按我预期的那样工作,所以没有不知道我是不是做错了什么?
【解决方案2】:

使用条件检查表的存在(显式样式)包装您的架构创建代码:

ActiveRecord::Schema.define do
  unless ActiveRecord::Base.connection.tables.include? 'albums'
    create_table :albums do |table|
      table.column :title,     :string
      table.column :performer, :string
    end
  end

  unless ActiveRecord::Base.connection.tables.include? 'tracks'
    create_table :tracks do |table|
      table.column :album_id,     :integer
      table.column :track_number, :integer
      table.column :title,        :string
    end
  end
end

可以用更简洁的方式写作,但保留明确的风格以便于理解。

【讨论】:

  • 这对我不起作用,仍然显示表“相册”已经存在。看起来问题稍后出现在它实际调用Album.create的代码中?
  • 另外,是否可以显示一个更简洁的版本,以便我可以看到有人会如何采用完整版本并将其重构为更红宝石
【解决方案3】:

代码复制自此要点:https://gist.github.com/unnitallman/944011

原来的要点有

ActiveRecord::Base.establish_connection(
    :adapter => "sqlite3",
    :dbfile => ":memory:"
)

所以它每次都会初始化一个新的数据库。它在您创建数据库文件时中断,该文件在脚本运行期间持续存在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多