遗留架构和动态查找(Ruby on Rails)

3
我正在尝试在一个旧的 Sybase 11 数据库上使用 Rails。已经通过 unixODBC 和 FreeTDS 连接成功,同时也使用了 activerecord-odbc-adapter gem。至目前为止,我已经使用 set_table_name 和 set_primary_key 使它可以运行。然而,动态查找方法 find_by 都不起作用,总是出现方法未找到的错误。同样地,通过关联查找也存在相同的错误。虽然模型上的普通查找可以工作,但我希望能有更简单的方式来完成这些操作。因为这是一个遗留数据库,所以我是否束手无策或者有什么方法可以检查和解决呢?如果可以的话,这会节省我编写 SQL 的工作量。谢谢。
编辑:
控制台输出:
Person.find_by_last_name("Smith")


NoMethodError: undefined method `find_by_last_name' for Person(Table doesn't exist):Class
    from /opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:1778:in `method_missing'
    from (irb):1


Person.find(:first, :conditions => { :last_name => "Smith" })

#<Person Person_ID: <redacted>, Title: "Mr.", First_Name: "Aaron", Middle_Name: "Michael", Last_Name: "Smith", Suffix: nil, Preferred_Name: nil

进一步编辑:

我猜测将 Last_Name 大写。这样返回了一些东西。看来我必须这样做。但我仍然不知道关联部分如何工作。这仍然是一个问题。

4个回答

5

你的问题在于查找器是区分大小写的。我也遇到了与我的旧数据库完全相同的问题。

尝试这个方法,看看是否有效:

Person.find_by_Last_Name("Smith")

这应该可以解决问题。

我编写了一些代码来解决这类问题。它是一个小型修补程序,可插入到要修改的特定模型中的ActiveRecord中。

module ActiveRecord
  class Base
    # Indicates whether field names should be lowercased for legacy databse fields.
    # If true, the field Product_Name will be +product_name+. If false, it will remain +Product_Name+.
    # This is false, by default.
    cattr_accessor :downcase_legacy_field_names, :instance_writer => false
    @@downcase_legacy_field_names = false
  end
end

以上代码在ActiveRecord上创建了一个名为downcase_legacy_field_names的新访问器。它默认值为false。当在模型顶部将此访问器设置为true时,它将触发以下代码。

# set all accessor methods to lowercase (underscore)
# add set_columns_to_lower to each model that needs it 
class << ActiveRecord::Base

    # Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
    # and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
    # is available.
    def column_methods_hash #:nodoc:
      @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|

        attr_final = downcase_legacy_field_names ? attr.to_s.downcase : attr

        attr_name = attr_final
        methods[attr_final.to_sym]       = attr_name
        methods["#{attr_final}=".to_sym] = attr_name
        methods["#{attr_final}?".to_sym] = attr_name
        methods["#{attr_final}_before_type_cast".to_sym] = attr_name
        methods
      end
    end

   # adapted from: http://wiki.rubyonrails.org/rails/pages/HowToUseLegacySchemas
    def downcase_legacy_field_methods
      column_names.each do |name|
       next if name == primary_key
       a = name.to_s.underscore

       define_method(a.to_sym) do
         read_attribute(name)
       end

       define_method("#{a}=".to_sym) do |value|
         write_attribute(name, value)
       end

       define_method("#{a}?".to_sym) do
         self.send("#{name}?".to_sym)
       end

      end
    end


end 




ActiveRecord::Base.downcase_legacy_field_names = true

这段代码是从http://wiki.rubyonrails.org/rails/pages/HowToUseLegacySchemas中改编而来的。

column_methods_hash中,我们覆盖了ActiveRecord方法。此方法用于生成运行时为数据库模型创建的方法名称列表。我们不想在过程中覆盖任何早期的方法,因为这样会干扰ActiveRecord将我们的动态查找器(和其他方法)转换为适当的SQL语句以供遗留数据库使用的能力。

第二个方法downcase_legacy_field_methods是一个新方法,它将实际生成downcase'd方法将执行的代码。

以上所有代码都是对ActiveRecord进行的补丁。这是一个猴子补丁,因此可以在加载ActiveRecord之后的任何地方要求。我将其放在了environment.rb中。

一旦您修补了ActiveRecord,还需要执行一个步骤。在遗留数据库模型的顶部,您需要有downcase_legacy_field_methods这一行。它应该看起来像这样:

class LegacyDatabaseModel < ActiveRecord::Base
  downcase_legacy_field_methods

  def cubits_to_feet
    #conversion code goes here
  end
end

2
我曾经遇到一个与此类似的问题,那是一个没有命名规范的遗留SQL Server数据库,有大量的内嵌SQL代码和ASP.net代码。这导致我们无法修改现有的ASP.net应用程序,尽管我也不想这样做。
这个数据库结构对于Rails来说非常痛苦,我们认为,由于表名都是单数形式,我们可以将所有表和列重命名,以使其与Rails一致,然后创建反映原始表/列结构的视图供ASP.net应用程序使用。
这使我们能够对新命名的表进行更改,包括添加新字段等,同时将遗留应用程序与这些DB结构更改隔离开来。
这种解决方案显然并不适用于每个人,但对我们来说非常成功。

1

这个可以工作吗:

User.find(:all, :conditions => ['name = ?', "bob"])

... 而这不会呢?

User.find_all_by_name("bob")

(这应该是一个注释,但我是新手,还不能评论:) 一个堆栈跟踪会帮助我深入挖掘并查看发生了什么。 你使用的Rails版本是什么?

正确。正常工作。我正在使用2.2.2版本。当我尝试执行我提到的操作时,我会发布我的控制台所显示的内容。 - Robert Rouse
salt.racer已经有了它。他的修补程序也很棒。 - wesgarrison

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接