在 Rails 上使用带有 jRuby 的 jdbc sqlserver 适配器时出现 NoMethodError

Getting NoMethodError when using jdbc sqlserver adapter with jRuby on Rails

我在 Rails 应用程序上有一个 jRuby 托管在 Windows Server 2012 R2 上的 IIS 8 上(我知道,我一定是疯了)。经过大约 2 周的痛苦编程后,我有了一个可以工作的应用程序,但我正在尝试将其配置为通过 Microsoft JDBC SQL 服务器驱动程序而不是默认的 sqlite3 使用 SQL Server 2012 Express数据库。到目前为止,进展并不顺利。

配置我的 database.yml 文件后,我尝试 运行:
bundle exec rake db:migrate RAILS_ENV=production --trace
我遇到错误
rake aborted! NoMethodError: undefined method 'type' for "nvarchar(255)":String

下面可以看到我的错误的完整痕迹:

耙子db:migrate

C:\inetpub\wwwroot\rails>bundle exec rake db:migrate RAILS_ENV=production --trac
e
io/console not supported; tty will not be manipulated
io/console not supported; tty will not be manipulated
NOTE: ActiveRecord 4.2 is not (yet) fully supported by AR-JDBC, please help us f
inish 4.2 support - check http://bit.ly/jruby-42 for starters
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:migrate
rake aborted!
NoMethodError: undefined method `type' for "nvarchar(255)":String
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_methods/time_zone_conversion.rb:64:in `create_time_zone_conversion_attr
ibute?'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_methods/time_zone_conversion.rb:53:in `inherited'
org/jruby/RubyProc.java:271:in `call'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:61:in `matching'
org/jruby/RubyArray.java:2470:in `select'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:60:in `matching'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:56:in `decorators_for'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:47:in `apply'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:29:in `add_user_provided_columns'
org/jruby/RubyArray.java:2414:in `map'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttribute_decorators.rb:28:in `add_user_provided_columns'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttributes.rb:93:in `columns'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/a
ttributes.rb:98:in `columns_hash'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/q
uerying.rb:41:in `find_by_sql'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/r
elation.rb:638:in `exec_queries'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/r
elation.rb:514:in `load'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/r
elation.rb:243:in `to_a'
C:0:in `map'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:844:in `get_all_versions'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:985:in `migrated'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:990:in `ran?'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:967:in `runnable'
org/jruby/RubyArray.java:2640:in `reject!'
org/jruby/RubyArray.java:2611:in `reject'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:967:in `runnable'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:952:in `migrate'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:820:in `up'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/m
igration.rb:798:in `migrate'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/t
asks/database_tasks.rb:137:in `migrate'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/activerecord-4.2.2/lib/active_record/r
ailties/databases.rake:44:in `(root)'
org/jruby/RubyProc.java:271:in `call'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/task.rb:240:in `e
xecute'
org/jruby/RubyArray.java:1613:in `each'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/task.rb:235:in `e
xecute'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/task.rb:179:in `i
nvoke_with_call_chain'
C:/jruby-1.7.22/lib/ruby/1.9/monitor.rb:211:in `mon_synchronize'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/task.rb:172:in `i
nvoke_with_call_chain'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/task.rb:165:in `i
nvoke'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:15
0:in `invoke_task'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:10
6:in `top_level'
org/jruby/RubyArray.java:1613:in `each'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:10
6:in `top_level'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:11
5:in `run_with_threads'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:10
0:in `top_level'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:78
:in `run'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:17
6:in `standard_exception_handling'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/lib/rake/application.rb:75
:in `run'
C:/jruby-1.7.22/lib/ruby/gems/shared/gems/rake-10.4.2/bin/rake:33:in `(root)'
org/jruby/RubyKernel.java:1059:in `load'
C:\jruby-1.7.22\bin\rake:23:in `(root)'

Tasks: TOP => db:migrate

database.yml

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test.sqlite3

production:
  adapter: sqlserver
  database: smdb
  url: jdbc:sqlserver://localhost;instanceName=SQLEXPRESS;databaseName=smdb;user=sa;password=password123;

Gemfile

source 'https://rubygems.org'

ruby '1.9.3', :engine => 'jruby', :engine_version => '1.7.22'

gem 'rails',                                '4.2.2'
gem 'bootstrap-sass',                       '3.2.0.0'
gem 'sass-rails',                           '5.0.2'
gem 'uglifier',                             '2.5.3'
gem 'coffee-rails',                         '4.1.0'
gem 'coffee-script-source',                 '1.8.0'
gem 'jquery-rails',                         '4.0.3'
gem 'turbolinks',                           '2.3.0'
gem 'jbuilder',                             '2.2.3'
gem 'faker',                                '1.4.2'
gem 'tzinfo-data',                          '1.2015.6'
gem 'sdoc',                                 '0.4.0', group: :doc

group :development, :test do
  gem 'activerecord-jdbcsqlite3-adapter',   '1.3.17'
  gem 'spring',                             '1.1.3'
end

group :test do
  gem 'minitest-reporters',                 '1.0.5'
  gem 'mini_backtrace',                     '0.1.3'
  gem 'guard-minitest',                     '2.3.1'
end

group :production do
  gem 'trinidad',                           '1.4.6'
  gem 'deprecated',                         '3.0.1'
  gem 'activerecord-jdbcmssql-adapter',     '1.3.17'
end 

最后是我的两个数据库迁移文件:

20150805101650_create_servers.rb

class CreateServers < ActiveRecord::Migration
  def change
    create_table :servers do |t|
      t.string :server_name
      t.string :application
      t.string :server_role
      t.string :team_contact
      t.string :individual_contact
      t.string :business_owner
      t.string :vendor
      t.string :vendor_contact
      t.string :main_doc
      t.string :main_win

      t.timestamps null: false
    end
  end
end

20150805105953_add_index_to_server_name.rb

class AddIndexToServerName < ActiveRecord::Migration
  def change
    add_index :servers, :server_name, unique: true
  end
end

我知道该实例正在被攻击,因为我之前遇到了身份验证错误,自从我将用户名和密码添加到 jdbc 连接字符串后,该错误已经消失

解决方案

降级到 Rails 4.1.0,似乎与 JDBC 适配器更兼容。 运行 a rake db:migrate RAILS_ENV=production 导致另一个错误。通过从 application.rb

中删除 config.active_record.raised_in_transactional_callbacks = true 解决了该错误

AR-JDBC 不处理 Rails 4.2 特别是。对于 MS-SQL 等数据库,会出现警告:

NOTE: ActiveRecord 4.2 is not (yet) fully supported by AR-JDBC, please help us finish 4.2 support - check http://bit.ly/jruby-42 for starters

...SQL服务器支持需要您的help/support!