Использование миграций в Ruby on Rails - PullRequest
2 голосов
/ 23 сентября 2008

Я хотел бы подтвердить правильность следующего анализа:

Я создаю веб-приложение в RoR. У меня есть структура данных для моей базы данных postgres (около 70 таблиц; эта конструкция может нуждаться в изменениях и дополнениях во время разработки, чтобы отразить способы работы Rails. Например, я разработал несколько таблиц пользователей и ролей - но если есть смысл использовать Restful Аутентификация, я буду чистить их и заменять на все, что требуется RA.).

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

например:

CREATE TABLE towns (
  id         integer PRIMARY KEY DEFAULT nextval ('towns_seq'),
  county_id  integer REFERENCES counties ON DELETE RESTRICT ON UPDATE CASCADE,
  country_id integer REFERENCES countries ON DELETE RESTRICT ON UPDATE CASCADE NOT NULL,
  name       text    NOT NULL UNIQUE
);

Предложение 0: данные работают дольше, чем приложения, поэтому я убежден, что я хочу, чтобы ссылочная целостность применялась на уровне БД, а также проверки в моих моделях RoR, несмотря на отсутствие DRYNESS.

Предложение 1. Если я заменю сценарий и файлы sql на Миграции, в настоящее время невозможно сообщить моей базе данных Postgres о внешнем ключе и других ограничениях, которые я в настоящее время устанавливаю в файлах SQL DDL в коде миграции.

Предложение 2: рекламируемое преимущество миграций состоит в том, что изменения в схеме имеют версии вместе с кодом модели RoR. Но если я храню свои скрипты и файлы .sql в railsapp / db, я могу так же легко их версии.

Предложение 3. Учитывая, что в миграциях отсутствует функциональность, которую я хочу, и предоставляются преимущества, которые я могу воспроизвести, у меня нет особых оснований рассматривать их использование. Поэтому я должен --skipmigrations во время сценария / генерации модели.

Мой вопрос: если предложение 0 принято, являются предложения 1,2,3 верными или ложными и почему?

Спасибо!

Ответы [ 4 ]

10 голосов
/ 23 сентября 2008

Предложение 1 ложно по крайней мере в двух ситуациях - вы можете использовать плагины, такие как foreign_key_migrations , чтобы сделать следующее:

def self.up
  create_table :users do |t|
    t.column :department_id, :integer, :references => :departments
  end
end

, который создает соответствующее ограничение внешнего ключа в вашей БД.

Конечно, у вас могут быть другие вещи, которые вы хотите сделать в своем DDL, и в этом случае вторая ситуация становится более убедительной: вы не обязаны использовать Ruby DSL в миграциях. Попробуйте метод execute вместо:

def self.up
  execute 'YOUR SQL HERE'
end

Таким образом, вы можете сохранять содержимое ваших сценариев SQL в миграциях, получая преимущества последних (наиболее заметно это методы down, которые вы не рассмотрели в исходном вопросе) и сохраняя нижний уровень управление вы предпочитаете.

4 голосов
/ 23 сентября 2008

Предложение 1 ошибочно: вы определенно можете определить ссылочную целостность, используя миграции, если только используя прямой SQL внутри миграции, см. этот пост для получения дополнительной информации.

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

Вы должны быть осторожны с порядком, в котором вы создаете / изменяете вещи, но вы можете это сделать.

Стоит помнить одну вещь: рельсы лучше подходят для разработки приложений. в Rails Way (tm) доступ к базе данных возможен только через слой активной записи приложения и предоставляется внешним данным с помощью веб-сервисов

1 голос
/ 23 сентября 2008

1: вы можете попробовать этот плагин . Я сам не пробовал, но, похоже, он может добавить ограничения внешнего ключа посредством миграции.

2: настоящим преимуществом миграции является возможность переходить назад и вперед в истории вашей базы данных. Это не так просто с вашими файлами .sql.

3: посмотрите, работает ли вышеупомянутый плагин для вас, а затем решите :) В любом случае, если вы не используете их, это не смертный грех!

0 голосов
/ 01 марта 2009

Поскольку вы используете Postgres и, возможно, не хотите устанавливать плагин foreign_key_migrations, вот что я делаю, когда хочу использовать как миграции, так и ограничения внешнего ключа.

Я добавляю метод SchemaStatements в ActiveRecord :: SchemaStatements под названием «add_fk_constraint». Это может быть в каком-то централизованном файле, но в приведенном ниже примере файла миграции я просто поместил его в строку.


module ActiveRecord
  module ConnectionAdapters # :nodoc:
    module SchemaStatements
      # Example call:
      # add_fk_constraint 'orders','advertiser_id','advertisers','id'
      # "If you want add/alter a 'orders' record, then its 'advertiser_id' had
      #   better point to an existing 'advertisers' record with corresponsding 'id'"
      def add_fk_constraint(table_name, referencing_col, referenced_table, referenced_col)
        fk_name = "#{table_name}_#{referencing_col}"
        sql = <<-ENDSQL
          ALTER TABLE #{table_name}
            ADD CONSTRAINT #{fk_name}
            FOREIGN KEY (#{referencing_col}) REFERENCES #{referenced_table} (#{referenced_col})
            ON UPDATE NO ACTION ON DELETE CASCADE; 
          CREATE INDEX fki_#{fk_name} ON #{table_name}(#{referencing_col});
        ENDSQL
        execute sql
      end
    end
  end
end

class AdvertisersOrders < ActiveRecord::Migration
  def self.up
    create_table :advertisers do |t|
      t.column :name,               :string,  :null => false
      t.column :net_id,             :integer, :null => false
      t.column :source_service_id,  :integer, :null => false, :default => 1
      t.column :source_id,          :integer, :null => false 
    end

    create_table :orders do |t|
      t.column :name,               :string,  :null => false
      t.column :advertiser_id,      :integer, :null => false
      t.column :source_id,          :integer, :null => false
    end
    add_fk_constraint 'orders','advertiser_id','advertisers','id'
  end

  def self.down
    drop_table :orders
    drop_table :advertisers
  end
end

Надеюсь, это кому-нибудь поможет. Это было очень полезно для меня, поскольку мне нужно загружать много внешних данных с помощью вызовов SQL «COPY», но система миграции очень удобна.

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