遗留模式和动态查找(Ruby on Rails)

时间:2009-02-11 21:06:52

标签: ruby-on-rails ruby activerecord

我正试图在遗留数据库上放置一个rails面。这是一个旧的Sybase 11数据库安装。我有一个ODBC连接工作 使用unixODBC和FreeTDS工作。我也在使用 activerecord-odbc-adapter gem。

我必须使用set_table_name和set_primary_key来使其正常工作 远。但是,动态的find_by方法都不起作用。我总是得到一个 方法遗漏错误。此外,通过关联查找不起作用 同样的错误。正常发现模型工作,但我是 希望我能简写一些。

我是SOL,因为它是遗留数据库,或者我能做些什么 或检查以使其工作?

如果可以,那将为我节省一些编写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 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

我遇到了传统SQL Server数据库的类似问题,该数据库没有命名约定,并且在代码隐藏页面等中嵌入了大量的ASP.net代码,这使得我们无法修改现有的ASP.net应用程序,而不是无论如何,我想这样做。

这个数据库结构对于rails非常痛苦,我们认为由于表名都是单数,我们可以重命名所有表和列以与Rails一致,然后创建反映原始表/列结构的视图ASP.net应用程序。

这允许我们对新重命名的表进行更改,包括添加新字段等,同时将遗留应用程序与这些数据库结构更改隔离开来。

这个解决方案显然不适用于所有人,但事实证明它对我们来说非常成功。

答案 2 :(得分:1)

这是否有效:

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

......虽然这不是吗?

User.find_all_by_name("bob")

(这应该是评论,但我是新的,不能发表评论:) 堆栈跟踪可以帮助我挖掘并查看正在发生的事情。 你使用的是什么版本的rails?

答案 3 :(得分:0)

这篇文章对我很有帮助,我将其正式化为一个插件:http://github.com/reidmix/legacy_mappings我想分享。点击,看起来像url被编码。