At udvikle en app betyder ikke kun at implementere nye funktioner eller patche den. Nogle gange er man nødt til at gøre ændringerne om og gå tilbage til den tidligere fase af et projekt. Et hyppigt problem, der kan opstå, når man arbejder på flere grene, handler om at opretholde den rette version af en databasestruktur. Programmører, der bruger rails, har færdige løsninger til deres rådighed. Disse løsninger understøtter implementeringen og kontrollen af databaseændringer - det er migreringer. Jeg vil ikke beskrive, hvordan det fungerer, og hvilke muligheder det giver - jeg vil gerne fokusere på problemet med at opretholde den rette version af en databasestruktur, mens man skifter gren.
Databaselaget i en app er et separat væsen og styres kun af migreringer. Når du opretter nye migreringer, skal du huske at gøre den planlagte transformation af en databasestruktur reversibel. I ekstreme tilfælde kan vi selvfølgelig hæve IrreversibelMigration
i ned metode. Dette vil også informere os om, at migreringen ikke kan gøres om. Der er forskellige typer af ændringer, som vi foretager i migreringen - oprettelse, ændring og fjernelse af tabeller, kolonner eller indekser. Sletning og ændring er de operationer, der er mest følsomme over for ændringer. Hvorfor er det sådan? Lad os se på følgende scenarie: Vi arbejder med master-grenen, som er vores primære arbejdssti. I øjeblikket har vi én tabel:
class CreateArticles < ActiveRecord::Migration
def ændre
create_table :articles do |t|
t.string :navn
t.text :beskrivelse
t.string :status, null: false
t.timestamps null: false
slut
slut
end
Vores Artikel
modellen har sådanne valideringer, som kræver tilstedeværelse af Navn, beskrivelse og status attributter.
klasse Artikel < ActiveRecord::Base
validerer :navn, tilstedeværelse: true
validerer :description, tilstedeværelse: true
validerer :status, tilstedeværelse: true
slut
Vi implementerer ændringer i vores artikler bord på funktion udviklingsgren, og vi sletter status kolonne.
class RemoveStatusColumnFromArticles < ActiveRecord::Migration
def ændring
remove_column :articles, :status, :string
end
slut
Vi udfører migreringen:
$ [eksempel/funktion]: bundle exec rake db:migrate
== 20150605120955 RemoveStatusColumnFromArticles: migrering ===================
-- remove_column(:articles, :status, :string)
-> 0.0717s
== 20150605120955 RemoveStatusColumnFromArticles: migreret (0.0718s) ==========
Skemaet for en database ændres:
diff --git a/db/schema.rb b/db/schema.rb
index 2a100a9..76438c1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,14 +11,13 @@ #
Det anbefales på det kraftigste, at du tjekker denne fil ind i dit versionskontrolsystem.
-ActiveRecord::Schema.define(version: 20150605120350) do
+ActiveRecord::Schema.define(version: 20150605120955) do
createtable "articles", force: :cascade do |t|
t.string "navn"
t.text "beskrivelse"
- t.string "status", null: false t.datetime "createdat", null: false
t.datetime "updated_at", null: false
slutning
end
Dernæst overfører vi ændringerne til funktion gren. For at simulere dette problem skifter vi den aktuelle gren til master. Basisstrukturen blev ændret ved migrering, som sletter status kolonne på funktion gren. Lad os prøve at bruge følgende kommando:
Article.create!(navn: "Kaboom", beskrivelse: "Lorem ipsum ...", status: "active")
Hvad vil der ske, når du har udført ovenstående? Kode? Fejlen: ActiveRecord::UnknownAttributeError: ukendt attribut 'status' for artikel
vil blive udløst, og det er på grund af den inkompatible strukturversion af en database. Før vi ændrer grenen til master, bør vi rulle en migrering tilbage, der sletter status kolonne fra Artikel bord.
Hvad kan vi gøre for at tjekke, om vi er nødt til at rulle nogle migreringer tilbage, før vi skifter gren? Med brug af versionsstyringssystemet (her er det git) kan vi kontrollere vores arbejde ved at oprette et nyttigt alias:
~/.gitconfig
[alias]
migrations = "!f() { git diff --name-only $1..$2 db/migrate | tr -d '[A-Za-z/_.]'; }; f"
Udførelse af git migrations master-funktion
kommandoen vil resultere i en liste over migrationsversioner, som er placeret på funktion grene, og som ikke kan findes på mester.
$ [example/feature]: git migrations master-funktion
20150605120955
Takket være disse oplysninger kan vi nemt rulle de ændringer tilbage, der er foretaget i databasestrukturen, før vi skifter til master.
$ [example/feature]: bundle exec rake db:migrate:down VERSION=20150605120955
== 20150605120955 RemoveStatusColumnFromArticles: reverting ===================
-- add_column(:articles, :status, :string)
-> 0.0009s
== 20150605120955 RemoveStatusColumnFromArticles: reverted (0.0045s) ==========
En anden ting, vi bør gøre, når vi har rullet migreringen tilbage, er at gendanne status for et databaseskema.
$ [example/feature]: git status
På gren-funktion
Ændringer, der ikke er iscenesat til commit:
(brug "git add ..." til at opdatere det, der skal committes)
(brug "git checkout -- ..." til at kassere ændringer i arbejdsmappen)
ændret: db/schema.rb
ingen ændringer tilføjet til commit (brug "git add" og/eller "git commit -a")
$ [example/feature]: git checkout db/schema.rb
$ [eksempel/feature]: git status
På gren-funktion
intet at committe, arbejdsmappe ren
Nu kan vi nemt skifte til mester gren.
Det givne eksempel er ikke et kompliceret problem at løse, men det bør hjælpe dig med at indse, hvor vigtigt det er at bevare strukturen i en database, når der sker ændringer i arbejdskonteksten.