Activerecord-import & serial column в PostgreSQL - PullRequest
2 голосов
/ 16 марта 2012

Я нахожусь в процессе обновления проекта Rails 2.3.4 до Rails 3.1.1.Старая версия использовала ar-extensions для обработки импорта данных.Я вытащил ar-extensions и заменил его на activerecord-import, который, как я понимаю, имеет точно такие же интерфейсы.

Мой код вызова выглядит так

Student.import(columns, values)

Оба аргумента являются допустимыми массивамиправильные данные, но я получаю большую полную ошибку!

Стек ошибок выглядит следующим образом:

NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.split):
  activerecord (3.1.1) lib/active_record/connection_adapters/postgresql_adapter.rb:828:in 'default_sequence_name'
  activerecord (3.1.1) lib/active_record/base.rb:647:in `reset_sequence_name'
  activerecord (3.1.1) lib/active_record/base.rb:643:in `sequence_name'
  activerecord-import (0.2.9) lib/activerecord-import/import.rb:203:in `import'

При просмотре кода кажется, что Activerecord-import вызывает activerecord, который, в свою очередь,ищет имя и следующее значение последовательности Postgres.

Поэтому activerecord-import ищет имя последовательности lib / activerecord-import / import.rb: 203

# Force the primary key col into the insert if it's not
# on the list and we are using a sequence and stuff a nil
# value for it into each row so the sequencer will fire later
-> if !column_names.include?(primary_key) && sequence_name && connection.prefetch_primary_key?
   column_names << primary_key
   array_of_attributes.each { |a| a << nil }
end

Вызывает активную запись... lib / active_record / base.rb: 647: в `reset_sequence_name '

# Lazy-set the sequence name to the connection's default. This method
# is only ever called once since set_sequence_name overrides it.
def sequence_name #:nodoc:
->  reset_sequence_name
end

def reset_sequence_name #:nodoc:
  -> default = connection.default_sequence_name(table_name, primary_key)
  set_sequence_name(default)
  default
end

Код ошибки, когда serial_sequence возвращает ноль и default_sequence_name пытается его разбить.

lib/active_record/connection_adapters/postgresql_adapter.rb

# Returns the sequence name for a table's primary key or some other specified key.
def default_sequence_name(table_name, pk = nil) #:nodoc:
  -> serial_sequence(table_name, pk || 'id').split('.').last
rescue ActiveRecord::StatementInvalid
  "#{table_name}_#{pk || 'id'}_seq"
end

def serial_sequence(table, column)
  result = exec_query(<<-eosql, 'SCHEMA', [[nil, table], [nil, column]])
    SELECT pg_get_serial_sequence($1, $2)
  eosql
  result.rows.first.first
end

Когда я выполняю pg_get_serial_sequence() непосредственно для базы данных, я не получаю возвращаемого значения:

SELECT pg_get_serial_sequence('student', 'id')

Но я вижу, что в базе данных есть последовательность с именем student_id_seq

Я использую следующую версиюRuby, рельсы PG и т. д.

  • Rails 3.1.1
  • Ruby 1.9.2
  • Activerecord-import 0.2.9
  • pg 0.12.2
  • psql (9.0.5, сервер 9.1.3)

Я перенес базу данных из MySQL в PostgreSQL, я не думаю, что это имеет какое-либо отношение кпроблема, но я подумал, что лучше добавить ее для полноты.

Я не могу понять, почему это не работает!

1 Ответ

4 голосов
/ 17 марта 2012

Краткое описание вашего описания:

  • Таблица student существует.
  • Столбец id существует.
  • Последовательность student_id_seq существует.
  • pg_get_serial_sequence('student', 'id') все еще возвращает NULL.

Два возможных объяснения:

1) Последовательность не связана со столбцом.

Столбец по умолчанию и связь между столбцом и последовательностью являются независимыми элементами. Само существование подходящей последовательности не означает, что она делает то, что вы предполагаете. Если вы создадите столбец как serial, вы получите весь пакет. Прочитайте подробности в руководстве .

Чтобы это исправить (и если вы уверены, что так и должно быть), вы можете пометить последовательность как «принадлежащую» student.id:

ALTER SEQUENCE student_id_seq OWNED BY student.id;

Также проверьте, правильно ли задан столбец по умолчанию:

SELECT column_name, column_default
FROM   information_schema.columns
WHERE  table_name = 'student'
-- AND    schema = 'your_schema' -- if needed

Если нет, отремонтировать:

ALTER TABLE student ALTER COLUMN id SET DEFAULT nextval('student.id')

2) смешивание адреса хоста / порта / базы данных / схемы / использования заглавных букв в имени таблицы.

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

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