Как вызвать тип атрибута ActiveRecord, возвращаемого: выберите фразу в объединенной таблице? - PullRequest
5 голосов
/ 23 апреля 2010

Возникли проблемы с AR 2.3.5, например ::100100

users = User.all( :select => "u.id, c.user_id", :from => "users u, connections c",
       :conditions => ... )

Возвращает, например ::1004 *

=> [#<User id: 1000>]
>> users.first.attributes
=> {"id"=>1000, "user_id"=>"1000"}

Обратите внимание, что AR возвращает id модели, найденной как числовой, а выбранный user_id объединенной модели как String, хотя обе являются int(11) в схеме базы данных.

Как мне лучше сформировать этот тип запроса, чтобы выбрать столбцы таблиц, поддерживающие несколько моделей и получить их естественный тип, а не String? Похоже, что AR где-то задумывается об этом. Как я могу принудительно возвращать возвращаемые типы во время загрузки AR, и при этом не нужно прикреплять .to_i (и т. Д.) К каждому доступу по запросу?

Ответы [ 3 ]

2 голосов
/ 21 мая 2010

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

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

Примерно так:

users = User.all(:select => "cl, comments.c2", ...)
users = convert_columns(users, 'c2' => :integer, 'other_column' => :date)

def convert_columns(records, columns = {})
  records.each do |rec|
    columns.each do |col, type|
      rec[col] = case type
         when :int then rec[col].to_i
         when :date then ........
         ....
      end
    end
  end
end
1 голос
/ 22 мая 2010

Почему вы используете: from => "users" внутри User.method? Следующее будет выполнять внутреннее соединение (что вы делаете в любом случае)

users = User.all(:include => :connections, :select => "users.id, connections.user_id", :conditions => {...})

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

Это также вернет ключи как INT, а не STRING

Гораздо более быстрой альтернативой было

Connection.all(:include => :user, :conditions => {...}).collect {|e| [e.user_id, e.id] }

Это дает вам массив массивов с идентификаторами. Если вы собираетесь выбирать только столбцы «id, user_id», то это не обязательно будет AR-объект. Массив может быть быстрее.

Надеюсь, я здесь не упустил какой-то смысл. Предложи мне, если я.

0 голосов
/ 23 мая 2010

Если вы хотите быстрое решение - попробуйте использовать обратный вызов after_find и предварительно установить правильные типы атрибутов:

class User < ActiveRecord::Base

  after_find :preset_types


  private
  def preset_types user
    user.user_id = user.user_id.to_i
  end

end
...