Устаревшая схема и динамическая находка (Ruby on Rails) - PullRequest
3 голосов
/ 12 февраля 2009

Я пытаюсь поместить лицо рельсов в устаревшую базу данных. Это старая Sybase 11 установка базы данных. Я получил соединение ODBC, работающее, что использует unixODBC и FreeTDS для работы. Я также использую activerecord-odbc-адаптер gem.

Мне пришлось использовать set_table_name и set_primary_key, чтобы это работало так далеко. Однако ни один из динамических методов find_by не работает. Я всегда получаю Ошибка метода отсутствует. Кроме того, поиск через ассоциацию не работает как хорошо с той же ошибкой. Нормальные находки на моделях работают, но я был надеясь, что я смогу сократить это.

Я SOL на этом, потому что это устаревшая БД или я могу что-то сделать или проверить, чтобы это работало?

Если бы я мог, это избавило бы меня от необходимости писать SQL.

Спасибо.

Edit:

Выход на консоль:

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 голосов
/ 12 февраля 2009

Ваша проблема в том, что искатели чувствительны к регистру. У меня точно такая же проблема с моей прежней базой данных.

Попробуйте посмотреть, как это работает:

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 голосов
/ 19 февраля 2009

Я столкнулся с похожими проблемами с базой данных прежних версий SQL Server, в которой не было соглашений об именах, и большим количеством кода ASP.net с SQL, встроенным в страницы с выделенным кодом и т. Д. Это не позволило нам изменить существующее приложение ASP.net, а не что я все равно хотел это сделать.

Эта структура базы данных была довольно болезненной для rails, и мы придерживались мнения, что, поскольку имена таблиц единичны, мы можем переименовать все таблицы и столбцы в соответствии с Rails, а затем создать представления, отражающие исходную структуру таблицы / столбца для Приложение ASP.net.

Это позволило нам внести изменения во вновь переименованные таблицы, включая добавление новых полей и т. Д., В то же время изолируя устаревшее приложение от этих изменений структуры БД.

Это решение, очевидно, не будет работать для всех, но оно оказалось очень успешным для нас.

1 голос
/ 12 февраля 2009

Работает ли это:

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

... пока этого нет?

User.find_all_by_name("bob")

(Это должно быть в комментарии, но я новичок и пока не могу комментировать :) Трассировка стека поможет мне разобраться и посмотреть, что происходит. Какую версию рельсов вы используете?

0 голосов
/ 04 мая 2009

Этот пост мне очень помог, и я оформил его в плагин: http://github.com/reidmix/legacy_mappings, которым я хотел поделиться. Нажмите, похоже, что URL кодируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...