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

ПРИМЕЧАНИЕ Если у вас нет mysql и он вам не нужен. Это нормально. Продолжайте двигаться. Если вы не укажете -d mysql, то rails будет использовать встроенный sqlite. Ничего не меняется.

Как начать работу с mysql и создать проект с базой данных

# Generate a rails project called possible using mysql
rails new possible -d mysql
# OR using sqlite
rails new possible 

Обновите файл возможных/config/database.yml, указав свое имя пользователя и пароль. Если вы используете sqlite, делать нечего.

# Generate your databases
rails db:create
  Created database 'possible_development'
  Created database 'possible_test'

db:create берет базы данных, описанные в файле database.yml, и создает их для вас.

Как сгенерировать Migration.

rails generate migration Car
Running via Spring preloader in process 58104
     invoke  active_record
     create    db/migrate/20190622100711_car.rb
# short hand
rails g migration Car 

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

Запустите миграцию

rails db:migrate
== 20190622101002 Car: migrating ==============================================
== 20190622101002 Car: migrated (0.0000s) =====================================

Бам, мы только что запустили пустую миграцию. Позвоним в статус

rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car

Запомни это имя сверху. Отметка времени подчеркивания и имени. Здесь в игру вступает метка времени. Давайте создадим еще одну миграцию.

# Create the motorcycle migration
rails g migration Motorcycle
Running via Spring preloader in process 58787
    invoke  active_record
    create    db/migrate/20190622101829_motorcycle.rb

# Check the Migration Status
rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car
down    20190622101829  Motorcycle

Из db:migrate:status я вижу, что я еще не выполнил эту конкретную миграцию. Вот что я собираюсь сделать.

  1. Я запущу db:migrate для переноса новой миграции.
  2. Потом проверю статус.
  3. Я удалю только миграцию автомобиля и снова проверю статус.
# 1
rails db:migrate
== 20190622101829 Motorcycle: migrating =======================================
== 20190622101829 Motorcycle: migrated (0.0000s) ==============================

# 2
rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car
up     20190622101829  Motorcycle

#3
rails db:migrate:down VERSION=20190622101002
== 20190622101002 Car: reverting ==============================================
== 20190622101002 Car: reverted (0.0096s) =====================================

rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
down    20190622101002  Car
up     20190622101829  Motorcycle

Проверьте это. Я смог выполнить одну миграцию, используя :down и VERSION = отметку времени миграции.

Автомобиль в том виде, в котором он сейчас находится, — довольно хромая миграция. У него только… Ну, ничего. давайте добавим таблицу с несколькими столбцами. Rails не генерирует таблицу автоматически при создании миграции. Так как миграция может быть много вещей. В отличие от модели.

ПРИМЕЧАНИЕ. Обычно добавление/удаление/изменение чего-либо в миграции состоит из создания новой миграции. Что мы и сделаем позже. Ради примеров. Я отредактирую миграцию автомобиля, чтобы добавить в нее несколько полей. Затем мы запустим все наши миграции и снова запустим их вперед.

# Generate the table 
class Car < ActiveRecord::Migration[5.2]
  def change
    create_table :cars do |t|
      # code goes here
    end
  end
end

Давайте создадим несколько столбцов.

  1. Создайте столбец с именем «модель», который представляет собой строку с ограничением в 25 символов. (Долгий путь)
  2. Создайте столбец с именем «Vin», который представляет собой целое число с ограничением в 17 символов и не может быть нулевым (сокращенный способ).
  3. Убедитесь, что в таблицу добавлено время обновления и создания.
class Car < ActiveRecord::Migration[5.2]
  def change
    create_table :cars do |t|
      t.column "model", :string, :limit => 25 # long way
      t.integer "vin", :null => false  # short way
 
      t.timestamps
    end
  end
end

t.column указывает на создание столбца. Имя этого столбца и тип данных, которые он будет содержать. Rails знает, что вы пытаетесь создать столбец. На самом деле вы можете сократить это. t.integer просто создает столбец типа integer. это позволяет вам отказаться от типа, как показано выше.

Теперь у нас есть некоторый контекст для нашей миграции автомобилей. давайте продолжим и запустим миграцию. Я могу просто использовать rails db:migrate для запуска всех миграций в неактивном состоянии, что, если вы помните выше. Мы отказались от миграции автомобилей.

rails db:migrate
== 20190622101002 Car: migrating ==============================================
-- create_table(:cars)
-> 0.0429s
== 20190622101002 Car: migrated (0.0429s) =====================================

ПРИМЕЧАНИЕ. Я хочу уделить секунду и поговорить о функции изменения в миграции, которую мы только что выполнили. Более новый метод «изменения». Что отлично работает для наших простых миграций, может не работать для более сложных миграций. На самом деле я предпочитаю указывать вверх и вниз. Итак, для нашей миграции мотоциклов. Мы собираемся изменить миграцию мотоцикла, чтобы использовать функции вверх и вниз. Затем мы добавим два поля. Модель и vin с нулевой проверкой.

class Motorcycle < ActiveRecord::Migration[5.2]
  def up
    create_table :motorcycles do |t|
      t.string 'modal'
      t.integer 'vin'
      t.timestamps
    end
  end
  def down
    drop_table :motorcycles
  end
end

Теперь мы четко определили наши методы up и down. Как я упоминал ранее. Change знает, как удалить таблицу. Это часть конвенции rails. Вверх и вниз — это то, что происходит за кулисами с методом изменения.

Давайте запустим наши миграции.

rails db:migrate

Что случилось? Ничего такого!

рельсы БД: миграция: статус

database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car
up     20190622101829  Motorcycle

Наши миграции уже запущены. При изменении миграции вы всегда должны создавать новую миграцию, которая изменяет работу предыдущей миграции. Наши миграции были пусты. Так что никаких конфликтов для нас нет. Мы можем откатить наши миграции, что просто ничего не делает. Если бы я создал таблицы и отредактировал файл migration. Скорее всего, они потерпят неудачу. Вот почему я создаю новую миграцию, чтобы внести изменения в существующий код миграции.

Давайте опустим их и поднимем обратно.

rails db:migrate:down VERSION=20190622101829
rails db:migrate:down VERSION=20190622101002
rails db:migrate

На данный момент у нас есть две миграции, каждая из которых состоит из modal и vin. Я показал вам два разных способа написания миграции. Вверх/вниз и изменить. Это не отвечает на вопрос. Что происходит в сложных ситуациях, когда изменения не могут легко понять, как понизить миграцию? На помощь приходит обратимый код. Таким образом, мы можем настроить наши методы up и down внутри метода change. Не волнуйтесь, это настолько сложно, насколько это возможно. Так что, если вы все еще со мной. Так держать.

class Car < ActiveRecord::Migration[5.2]
  def change
    reversible do |dir|
      dir.up do
        create_table :cars do |t|
        puts "creating table with name and vin
        t.column "first_name", :string, :limit => 25 # long way
        t.integer "vin", :null => false  # short way
        t.timestamps
      end
    end
    dir.down do
      puts "Dropping the table cars"
      drop_table :cars
      puts "Dropping succeeded"
    end
   end
  end
end

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

# CHECK STATUS
rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car
up     20190622101829  Motorcycle
BRING DOWN
rails db:migrate:down VERSION=20190622101002
== 20190622101002 Car: reverting ==============================================
Dropping the table cars
-- drop_table(:cars)
-> 0.0106s
Dropping succeeded
== 20190622101002 Car: reverted (0.0197s) =====================================
# BRING UP
rails db:migrate:up VERSION=20190622101002
== 20190622101002 Car: migrating ==============================================
-- create_table(:cars)
creating table with name and vin
-> 0.0457s
== 20190622101002 Car: migrated (0.0458s) =====================================

Это было много, что я знаю. Если вы когда-нибудь напишете миграцию, сложную для рельсов, чтобы выяснить, как вернуться. Теперь вы знаете, как писать настраиваемый код повышения и понижения при миграции изменений. Повезло тебе! Ну и еще, с добавлением операторов puts.

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

rails g migration AddColumnsToCars
Running via Spring preloader in process 60434
    invoke  active_record
    create    db/migrate/20190622111101_add_columns_to_cars.rb
rails g migration ChangeColumnsOnMotorcycles
Running via Spring preloader in process 60448
    invoke  active_record
    create   db/migrate/20190622111105_change_columns_on_motorcycles.rb

Поменяем колонки в машинах.

class AddColumnsToCars < ActiveRecord::Migration[5.2]
  def change
    add_column :cars, :tires, :string
    add_column('cars', 'tireNumber', 'integer') 
  end
end

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

create_table, add_column, add_index, add_foreign_key, add_reference, add_timestamps, rename_table, rename_column, rename_index
drop_table, remove_column, remove_index, remove_foreign_key, remove_reference, remove_timestamps.

Идем дальше, теперь мы добавили столбец с помощью символов и добавили столбец с помощью строк. Вы можете видеть, что не имеет значения, как вы это делаете. Это то же самое. Я сделал это только для того, чтобы показать, что вы можете использовать символы и/или строки.

Давайте запустим эту миграцию, чтобы убедиться, что она работает. Мы всегда должны делать паузы, чтобы часто запускать наши миграции. Гораздо проще устранить неполадки с одной миграцией, чем потом.

rails db:migrate:status
database: possible_development
Status   Migration ID    Migration Name
--------------------------------------------------
up     20190622101002  Car
up     20190622101829  Motorcycle
down    20190622111101  Add columns to cars
down    20190622111105  Change columns on motorcycles

У меня две миграции. Я просто хочу управлять машинами прямо сейчас. Я еще не менял мотоцикл. Итак, давайте запустим его и нацелимся на отметку времени миграции.

rails db:migrate:up VERSION=20190622111101
== 20190622111101 AddColumnsToCars: migrating =================================
-- add_column(:cars, :tires, :string)
-> 0.0402s
-- add_column("cars", "tireNumber", "integer")
-> 0.0111s
== 20190622111101 AddColumnsToCars: migrated (0.0515s) ========================

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

rails g migration AddColsToMotorcycles tires:integer shocks:string
# THIS GENERATES A MIGRATION FOR US WITH THE COLUMNS AND WE DON'T HAVE TO TYPE THEM. 
class AddColsToMotorcycles < ActiveRecord::Migration[5.2]
  def change
    add_column :motorcycles, :tires, :integer
    add_column :motorcycles, :shocks, :string
  end
end

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

Вот и все, надеюсь вы что-то узнали или вспомнили что-то полезное, если покажете ставьте лайк или делитесь.