2013-10-01 5 views
1

У меня странная проблема, которую я просто не могу понять.Rails 4 альтернативный первичный ключ с MySQL

Я хочу использовать способность кластеризации mysql для хранения связанных записей друг с другом на диске. Mysql с помощью первичного ключа в таблице, который для модели рельсов по умолчанию является идентификатором.

Однако для большого количества таблиц может иметь смысл первичный ключ таблицы быть, например, user_id, subscription_id, кластеризовать связанные записи рядом с каждым и делать очень эффективный поиск при запросе базу данных для всех абонентских подписей.

Чтобы сделать это, я создал таблицу MySQL, как:

execute('create table subscriptions (
      id   integer not null auto_increment, 
      user_id integer not null, 
      feed_id integer not null, 
      folder_id integer, 
      created_at  datetime, 
      updated_at  datetime, 
      primary key (user_id, feed_id), 
      key id (id) 
     ) engine=InnoDB default charset=utf8'); 

Обратите внимание, что мой ПК является user_id, FEED_ID, но я до сих пор ID колонки настоящее, и я хочу, рельсы еще использовать это как то, что он считает ПК за столом.

Во-первых, это не будет работать вообще, пока я не установлен:

class Subscription < ActiveRecord::Base 

    self.primary_key = 'id' 
    ... 
end 

Теперь приходит странная часть.

Когда я запускаю свои тесты, я получаю странную ошибку:

Mysql::Error: Field 'id' doesn't have a default value: INSERT INTO `subscriptions` 

Однако - если я придерживаюсь приложение в режиме разработки и делать операции через веб-страницу, она работает просто отлично.

После много прибегая к помощи, я нашел обезьяну патч, чтобы остановить Rails настройки MySQL в более строгий режим:

class ActiveRecord::ConnectionAdapters::MysqlAdapter 

private 
    alias_method :configure_connection_without_strict_mode, :configure_connection 

    def configure_connection 
    configure_connection_without_strict_mode 
    strict_mode = "SQL_MODE=''" 
    execute("SET #{strict_mode}", :skip_logging) 
    end 
end 

Если добавить это, мой тестовый костюм появляется на работу (для большинства тестов, но не все), но любые модели, которые создаются, имеют ИД нуля.

Снова в режиме производства через веб-страницу все работает отлично, а модели получают идентификатор auto_increment, как ожидалось.

У кого-нибудь есть идеи о том, что я могу сделать, чтобы мой тестовый набор работал правильно в этой настройке?

+0

Не использовал бы первичный ключ UUID более надежный, чем этот? – tadman

+0

Не уверен в UUID PK. Это действительно просто еще один суррогатный ПК, похожий на идентификационную последовательность. Я действительно не хочу начинать обсуждение кластеризации MySQL, но, имея PK в user_id, feed_id, это означает, что даже когда пользователи создают каналы в течение длительного периода времени, все они будут храниться рядом друг с другом на диске, позволяя всем читать по одной БД или двум, а не многим. Его также является естественным ключом на столе, так как таблица должна быть уникальной для этой пары. –

+0

Почему бы не добавить уникальное ограничение/индекс на пару '(user_id, feed_id)' и оставить только ПК? Это, вероятно, будет проще с Rails, чем пытаться объединиться с ПК. –

ответ

0

Я понял, что происходит.

То, что я не помню, заключается в том, что база данных разработки создается путем запуска миграции по базе данных, которая также генерирует файл schema.rb. Затем файл schema.rb используется для загрузки тестовой базы данных.

Так что, хотя моя база данных разработки выглядела так, как я ожидал, тестовая база данных выглядела по-другому - казалось бы, код, который генерирует файл schema.rb, не может понять формат базы данных, который я создал, и не создает schema.rb, который отражает мои миграции правильно.

Если я загружаю мою тестовую базу данных с:

$ rake db:migrate RAILS_ENV=test 

А потом запустить свой набор тестов с:

$ rake test:all 

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

Так что я описал в вопросе о создании альтернативного первичного ключа при сохранении ключа ID рельсов, за исключением части schema.rb.

Смежные вопросы