-
Notifications
You must be signed in to change notification settings - Fork 0
/
active_record_migrations.html
1590 lines (1513 loc) · 154 KB
/
active_record_migrations.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Migraciones de Active Record — Ruby on Rails Guides</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style-v2.css" data-turbo-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/print-v2.css" media="print">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight-v2.css" data-turbo-track="reload">
<link rel="icon" href="images/favicon.ico" sizes="any">
<link rel="apple-touch-icon" href="images/icon.png">
<script src="javascripts/@hotwired--turbo.js" data-turbo-track="reload"></script>
<script src="javascripts/clipboard.js" data-turbo-track="reload"></script>
<script src="javascripts/guides.js" data-turbo-track="reload"></script>
<meta property="og:title" content="Migraciones de Active Record — Ruby on Rails Guides" />
<meta name="description" content="NO LEA ESTE ARCHIVO EN GITHUB, LAS GUÍAS ESTÁN PUBLICADAS EN https://guides.rubyonrails.org.Migraciones de Active RecordLas migraciones son una característica de Active Record que te permite evolucionar tu esquema de base de datos con el tiempo. En lugar de escribir modificaciones de esquema en SQL puro, las migraciones te permiten usar un Lenguaje Específico de Dominio (DSL) en Ruby para describir cambios en tus tablas.Después de leer esta guía, sabrás: Qué generadores puedes usar para crear migraciones. Qué métodos proporciona Active Record para manipular tu base de datos. Cómo cambiar migraciones existentes y actualizar tu esquema. Cómo se relacionan las migraciones con schema.rb. Cómo mantener la integridad referencial." />
<meta property="og:description" content="NO LEA ESTE ARCHIVO EN GITHUB, LAS GUÍAS ESTÁN PUBLICADAS EN https://guides.rubyonrails.org.Migraciones de Active RecordLas migraciones son una característica de Active Record que te permite evolucionar tu esquema de base de datos con el tiempo. En lugar de escribir modificaciones de esquema en SQL puro, las migraciones te permiten usar un Lenguaje Específico de Dominio (DSL) en Ruby para describir cambios en tus tablas.Después de leer esta guía, sabrás: Qué generadores puedes usar para crear migraciones. Qué métodos proporciona Active Record para manipular tu base de datos. Cómo cambiar migraciones existentes y actualizar tu esquema. Cómo se relacionan las migraciones con schema.rb. Cómo mantener la integridad referencial." />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Ruby on Rails Guides" />
<meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" />
<meta property="og:type" content="website" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Heebo:[email protected]&family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
<meta name="theme-color" content="#C81418">
</head>
<body class="guide">
<nav id="topNav" aria-label="Secondary">
<div class="wrapper">
<strong class="more-info-label">Más en <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong>
<span class="red-button more-info-button">
Más Ruby on Rails
</span>
<ul class="more-info-links s-hidden">
<li class="more-info"><a href="https://rubyonrails.org/blog">Blog</a></li>
<li class="more-info"><a href="https://guides.rubyonrails.org/">Guías</a></li>
<li class="more-info"><a href="https://api.rubyonrails.org/">API</a></li>
<li class="more-info"><a href="https://discuss.rubyonrails.org/">Foro</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">Contribuir en GitHub</a></li>
</ul>
</div>
</nav>
<header id="page_header">
<div class="wrapper clearfix">
<nav id="feature_nav">
<div class="header-logo">
<a href="index.html" title="Regresar a la página principal de Guías para Edge">Guías</a>
<span id="version_switcher">
Versión:
<select class="guides-version">
<option value="https://edgeguides.rubyonrails.org/" selected>Edge</option>
<option value="https://guides.rubyonrails.org/v7.2/">7.2</option>
<option value="https://guides.rubyonrails.org/v7.1/">7.1</option>
<option value="https://guides.rubyonrails.org/v7.0/">7.0</option>
<option value="https://guides.rubyonrails.org/v6.1/">6.1</option>
<option value="https://guides.rubyonrails.org/v6.0/">6.0</option>
<option value="https://guides.rubyonrails.org/v5.2/">5.2</option>
<option value="https://guides.rubyonrails.org/v5.1/">5.1</option>
<option value="https://guides.rubyonrails.org/v5.0/">5.0</option>
<option value="https://guides.rubyonrails.org/v4.2/">4.2</option>
<option value="https://guides.rubyonrails.org/v4.1/">4.1</option>
<option value="https://guides.rubyonrails.org/v4.0/">4.0</option>
<option value="https://guides.rubyonrails.org/v3.2/">3.2</option>
<option value="https://guides.rubyonrails.org/v3.1/">3.1</option>
<option value="https://guides.rubyonrails.org/v3.0/">3.0</option>
<option value="https://guides.rubyonrails.org/v2.3/">2.3</option>
</select>
</span>
</div>
<ul class="nav">
<li><a class="nav-item" id="home_nav" href="https://rubyonrails.org/">Inicio</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">Índice de Guías</a>
<div id="guides" class="clearfix" style="display: none;">
<hr />
<dl class="guides-section-container">
<div class="guides-section">
<dt>Comienza Aquí</dt>
<dd><a href="getting_started.html">Primeros Pasos con Rails</a></dd>
</div>
<div class="guides-section">
<dt>Modelos</dt>
<dd><a href="active_record_basics.html">Conceptos Básicos de Active Record</a></dd>
<dd><a href="active_record_migrations.html">Migraciones de Active Record</a></dd>
<dd><a href="active_record_validations.html">Validaciones de Active Record</a></dd>
</div>
<div class="guides-section">
<dt>Vistas</dt>
<dd><a href="action_view_overview.html">Resumen de Action View</a></dd>
<dd><a href="layouts_and_rendering.html">Diseños y Renderizado en Rails</a></dd>
</div>
<div class="guides-section">
<dt>Controladores</dt>
<dd><a href="action_controller_overview.html">Resumen de Action Controller</a></dd>
<dd><a href="routing.html">Enrutamiento en Rails desde el Exterior</a></dd>
</div>
<div class="guides-section">
<dt>Otros Componentes</dt>
<dd><a href="active_support_core_extensions.html">Extensiones Básicas de Active Support</a></dd>
<dd><a href="action_mailer_basics.html">Conceptos Básicos de Action Mailer</a></dd>
<dd><a href="action_mailbox_basics.html">Conceptos Básicos de Action Mailbox</a></dd>
<dd><a href="action_text_overview.html">Resumen de Action Text</a></dd>
<dd><a href="active_job_basics.html">Conceptos Básicos de Active Job</a></dd>
</div>
<div class="guides-section">
<dt>Políticas</dt>
<dd><a href="maintenance_policy.html">Política de Mantenimiento</a></dd>
</div>
<div class="guides-section">
<dt>Notas de Lanzamiento</dt>
<dd><a href="upgrading_ruby_on_rails.html">Actualizando Ruby on Rails</a></dd>
<dd><a href="7_2_release_notes.html">Versión 7.2 - ?</a></dd>
<dd><a href="7_1_release_notes.html">Versión 7.1 - Octubre 2023</a></dd>
<dd><a href="7_0_release_notes.html">Versión 7.0 - Diciembre 2021</a></dd>
<dd><a href="6_1_release_notes.html">Versión 6.1 - Diciembre 2020</a></dd>
</div>
</dl>
</div>
</li>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribuir</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">Índice de Guías</option>
<optgroup label="Comienza Aquí">
<option value="getting_started.html">Primeros Pasos con Rails</option>
</optgroup>
<optgroup label="Modelos">
<option value="active_record_basics.html">Conceptos Básicos de Active Record</option>
<option value="active_record_migrations.html">Migraciones de Active Record</option>
<option value="active_record_validations.html">Validaciones de Active Record</option>
</optgroup>
<optgroup label="Vistas">
<option value="action_view_overview.html">Resumen de Action View</option>
<option value="layouts_and_rendering.html">Diseños y Renderizado en Rails</option>
</optgroup>
<optgroup label="Controladores">
<option value="action_controller_overview.html">Resumen de Action Controller</option>
<option value="routing.html">Enrutamiento en Rails desde el Exterior</option>
</optgroup>
<optgroup label="Otros Componentes">
<option value="active_support_core_extensions.html">Extensiones Básicas de Active Support</option>
<option value="action_mailer_basics.html">Conceptos Básicos de Action Mailer</option>
<option value="action_mailbox_basics.html">Conceptos Básicos de Action Mailbox</option>
<option value="action_text_overview.html">Resumen de Action Text</option>
<option value="active_job_basics.html">Conceptos Básicos de Active Job</option>
</optgroup>
<optgroup label="Políticas">
<option value="maintenance_policy.html">Política de Mantenimiento</option>
</optgroup>
<optgroup label="Notas de Lanzamiento">
<option value="upgrading_ruby_on_rails.html">Actualizando Ruby on Rails</option>
<option value="7_2_release_notes.html">Versión 7.2 - ?</option>
<option value="7_1_release_notes.html">Versión 7.1 - Octubre 2023</option>
<option value="7_0_release_notes.html">Versión 7.0 - Diciembre 2021</option>
<option value="6_1_release_notes.html">Versión 6.1 - Diciembre 2020</option>
</optgroup>
</select>
</li>
</ul>
</nav>
</div>
</header>
<hr class="hide" />
<section id="feature">
<div class="wrapper">
<p><strong>NO LEA ESTE ARCHIVO EN GITHUB, LAS GUÍAS ESTÁN PUBLICADAS EN <a href="https://guides.rubyonrails.org">https://guides.rubyonrails.org</a>.</strong></p><h1>Migraciones de Active Record</h1><p>Las migraciones son una característica de Active Record que te permite evolucionar tu esquema de base de datos con el tiempo. En lugar de escribir modificaciones de esquema en SQL puro, las migraciones te permiten usar un Lenguaje Específico de Dominio (DSL) en Ruby para describir cambios en tus tablas.</p><p>Después de leer esta guía, sabrás:</p>
<ul>
<li>Qué generadores puedes usar para crear migraciones.</li>
<li>Qué métodos proporciona Active Record para manipular tu base de datos.</li>
<li>Cómo cambiar migraciones existentes y actualizar tu esquema.</li>
<li>Cómo se relacionan las migraciones con <code>schema.rb</code>.</li>
<li>Cómo mantener la integridad referencial.</li>
</ul>
<nav id="subCol">
<h3 class="chapter">
<picture>
<!-- Using the `source` HTML tag to set the dark theme image -->
<source
srcset="images/icon_book-close-bookmark-1-wht.svg"
media="(prefers-color-scheme: dark)"
/>
<img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" />
</picture>
Chapters
</h3>
<ol class="chapters">
<li><a href="#visión-general-de-las-migraciones">Visión General de las Migraciones</a></li>
<li><a href="#generación-de-archivos-de-migración">Generación de Archivos de Migración</a>
<ul>
<li><a href="#creación-de-una-migración-independiente">Creación de una Migración Independiente</a></li>
<li><a href="#creación-de-una-nueva-tabla">Creación de una Nueva Tabla</a></li>
<li><a href="#agregar-columnas">Agregar Columnas</a></li>
<li><a href="#eliminación-de-columnas">Eliminación de Columnas</a></li>
<li><a href="#creación-de-asociaciones">Creación de Asociaciones</a></li>
<li><a href="#otros-generadores-que-crean-migraciones">Otros Generadores que Crean Migraciones</a></li>
<li><a href="#pasando-modificadores">Pasando Modificadores</a></li>
</ul></li>
<li><a href="#actualización-de-migraciones">Actualización de Migraciones</a>
<ul>
<li><a href="#creación-de-una-tabla">Creación de una Tabla</a></li>
<li><a href="#creación-de-una-tabla-de-unión">Creación de una Tabla de Unión</a></li>
<li><a href="#cambiando-tablas">Cambiando Tablas</a></li>
<li><a href="#cambiando-columnas">Cambiando Columnas</a></li>
<li><a href="#modificadores-de-columna">Modificadores de Columna</a></li>
<li><a href="#referencias">Referencias</a></li>
<li><a href="#claves-externas">Claves Externas</a></li>
<li><a href="#claves-primarias-compuestas">Claves Primarias Compuestas</a></li>
<li><a href="#ejecutar-sql">Ejecutar SQL</a></li>
<li><a href="#usando-el-método-change">Usando el Método <code>change</code></a></li>
<li><a href="#usando-reversible">Usando <code>reversible</code></a></li>
<li><a href="#usando-los-métodos-up-down">Usando los Métodos <code>up</code>/<code>down</code></a></li>
<li><a href="#lanzar-un-error-para-evitar-reversiones">Lanzar un error para evitar reversiones</a></li>
<li><a href="#revertir-migraciones-anteriores">Revertir Migraciones Anteriores</a></li>
</ul></li>
<li><a href="#ejecución-de-migraciones">Ejecución de Migraciones</a>
<ul>
<li><a href="#retroceso">Retroceso</a></li>
<li><a href="#configuración-de-la-base-de-datos">Configuración de la Base de Datos</a></li>
<li><a href="#preparación-de-la-base-de-datos">Preparación de la Base de Datos</a></li>
<li><a href="#restablecimiento-de-la-base-de-datos">Restablecimiento de la Base de Datos</a></li>
<li><a href="#ejecución-de-migraciones-específicas">Ejecución de Migraciones Específicas</a></li>
<li><a href="#ejecución-de-migraciones-en-diferentes-entornos">Ejecución de Migraciones en Diferentes Entornos</a></li>
<li><a href="#cambiando-la-salida-de-las-migraciones">Cambiando la Salida de las Migraciones</a></li>
<li><a href="#control-de-versión-de-migraciones-de-rails">Control de Versión de Migraciones de Rails</a></li>
</ul></li>
<li><a href="#cambiar-migraciones-existentes">Cambiar Migraciones Existentes</a></li>
<li><a href="#volcado-de-esquema-y-tú">Volcado de Esquema y Tú</a>
<ul>
<li><a href="#¿para-qué-son-los-archivos-de-esquema-questionmark">¿Para qué son los Archivos de Esquema?</a></li>
<li><a href="#tipos-de-volcados-de-esquema">Tipos de Volcados de Esquema</a></li>
<li><a href="#volcados-de-esquema-y-control-de-versiones">Volcados de Esquema y Control de Versiones</a></li>
</ul></li>
<li><a href="#active-record-e-integridad-referencial">Active Record e Integridad Referencial</a></li>
<li><a href="#migraciones-y-datos-de-semillas">Migraciones y Datos de Semillas</a></li>
<li><a href="#migraciones-antiguas">Migraciones Antiguas</a>
<ul>
<li><a href="#migraciones-desde-engines">Migraciones desde Engines</a></li>
</ul></li>
<li><a href="#miscelánea">Miscelánea</a>
<ul>
<li><a href="#usando-uuids-en-lugar-de-ids-para-claves-primarias">Usando UUIDs en lugar de IDs para Claves Primarias</a></li>
<li><a href="#migraciones-de-datos">Migraciones de Datos</a></li>
</ul></li>
</ol>
</nav>
<hr>
</div>
</section>
<main id="container">
<div class="wrapper">
<div id="mainCol">
<h2 id="visión-general-de-las-migraciones"><a class="anchorlink" href="#visión-general-de-las-migraciones"><span>1</span> Visión General de las Migraciones</a></h2><p>Las migraciones son una forma conveniente de <a href="https://en.wikipedia.org/wiki/Schema_migration">evolucionar tu esquema de base de datos con el tiempo</a> de manera reproducible. Usan un <a href="https://en.wikipedia.org/wiki/Domain-specific_language">DSL</a> en Ruby para que no tengas que escribir <a href="https://en.wikipedia.org/wiki/SQL">SQL</a> a mano, permitiendo que tu esquema y cambios sean independientes de la base de datos. Recomendamos que leas las guías de <a href="active_record_basics.html">Conceptos Básicos de Active Record</a> y <a href="association_basics.html">Asociaciones de Active Record</a> para aprender más sobre algunos de los conceptos mencionados aquí.</p><p>Puedes pensar en cada migración como una nueva 'versión' de la base de datos. Un esquema comienza sin nada en él, y cada migración lo modifica para agregar o eliminar tablas, columnas o índices. Active Record sabe cómo actualizar tu esquema a lo largo de esta línea de tiempo, llevándolo desde cualquier punto en la historia hasta la última versión. Lee más sobre <a href="#control-de-versión-de-migraciones-de-rails">cómo Rails sabe qué migración en la línea de tiempo ejecutar</a>.</p><p>Active Record actualiza tu archivo <code>db/schema.rb</code> para que coincida con la estructura actualizada de tu base de datos. Aquí tienes un ejemplo de una migración:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># db/migrate/20240502100843_create_products.rb</span>
<span class="k">class</span> <span class="nc">CreateProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">text</span> <span class="ss">:description</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateProducts < ActiveRecord::Migration[7.2]
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
">Copy</button>
</div>
<p>Esta migración agrega una tabla llamada <code>products</code> con una columna de tipo string llamada <code>name</code> y una columna de tipo texto llamada <code>description</code>. También se agregará implícitamente una columna de clave primaria llamada <code>id</code>, ya que es la clave primaria predeterminada para todos los modelos de Active Record. La macro <code>timestamps</code> agrega dos columnas, <code>created_at</code> y <code>updated_at</code>. Estas columnas especiales son gestionadas automáticamente por Active Record si existen.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># db/schema.rb</span>
<span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Schema</span><span class="p">[</span><span class="mf">7.2</span><span class="p">].</span><span class="nf">define</span><span class="p">(</span><span class="ss">version: </span><span class="mi">2024_05_02_100843</span><span class="p">)</span> <span class="k">do</span>
<span class="c1"># Estas son extensiones que deben estar habilitadas para soportar esta base de datos</span>
<span class="n">enable_extension</span> <span class="s2">"plpgsql"</span>
<span class="n">create_table</span> <span class="s2">"products"</span><span class="p">,</span> <span class="ss">force: :cascade</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="s2">"name"</span>
<span class="n">t</span><span class="p">.</span><span class="nf">text</span> <span class="s2">"description"</span>
<span class="n">t</span><span class="p">.</span><span class="nf">datetime</span> <span class="s2">"created_at"</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">t</span><span class="p">.</span><span class="nf">datetime</span> <span class="s2">"updated_at"</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="ActiveRecord::Schema[7.2].define(version: 2024_05_02_100843) do
# Estas son extensiones que deben estar habilitadas para soportar esta base de datos
enable_extension "plpgsql"
create_table "products", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
">Copy</button>
</div>
<p>Definimos el cambio que queremos que ocurra avanzando en el tiempo. Antes de que se ejecute esta migración, no habrá tabla. Después de que se ejecute, la tabla existirá. Active Record también sabe cómo revertir esta migración; si retrocedemos en esta migración, eliminará la tabla. Lee más sobre cómo retroceder migraciones en la <a href="#retroceso">sección de Retroceso</a>.</p><p>Después de definir el cambio que queremos que ocurra avanzando en el tiempo, es esencial considerar la reversibilidad de la migración. Mientras Active Record puede gestionar la progresión hacia adelante de la migración, asegurando la creación de la tabla, el concepto de reversibilidad se vuelve crucial. Con migraciones reversibles, no solo la migración crea la tabla cuando se aplica, sino que también permite una funcionalidad de retroceso suave. En caso de revertir la migración anterior, Active Record maneja inteligentemente la eliminación de la tabla, manteniendo la consistencia de la base de datos a lo largo del proceso. Consulta la <a href="#revertir-migraciones-anteriores">sección de Reversión de Migraciones</a> para más detalles.</p><h2 id="generación-de-archivos-de-migración"><a class="anchorlink" href="#generación-de-archivos-de-migración"><span>2</span> Generación de Archivos de Migración</a></h2><h3 id="creación-de-una-migración-independiente"><a class="anchorlink" href="#creación-de-una-migración-independiente"><span>2.1</span> Creación de una Migración Independiente</a></h3><p>Las migraciones se almacenan como archivos en el directorio <code>db/migrate</code>, uno para cada clase de migración.</p><p>El nombre del archivo tiene la forma <code>YYYYMMDDHHMMSS_create_products.rb</code>, contiene una marca de tiempo UTC que identifica la migración seguida de un guion bajo seguido del nombre de la migración. El nombre de la clase de la migración (versión CamelCased) debe coincidir con la última parte del nombre del archivo.</p><p>Por ejemplo, <code>20240502100843_create_products.rb</code> debe definir la clase <code>CreateProducts</code> y <code>20240502101659_add_details_to_products.rb</code> debe definir la clase <code>AddDetailsToProducts</code>. Rails usa esta marca de tiempo para determinar qué migración debe ejecutarse y en qué orden, así que si estás copiando una migración de otra aplicación o generando un archivo tú mismo, ten en cuenta su posición en el orden. Puedes leer más sobre cómo se usan las marcas de tiempo en la <a href="#control-de-versión-de-migraciones-de-rails">sección de Control de Versión de Migraciones de Rails</a>.</p><p>Al generar una migración, Active Record automáticamente antepone la marca de tiempo actual al nombre del archivo de la migración. Por ejemplo, ejecutar el siguiente comando creará un archivo de migración vacío donde el nombre del archivo está compuesto por una marca de tiempo antepuesta al nombre subrayado de la migración.</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddPartNumberToProducts
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddPartNumberToProducts
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># db/migrate/20240502101659_add_part_number_to_products.rb</span>
<span class="k">class</span> <span class="nc">AddPartNumberToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddPartNumberToProducts < ActiveRecord::Migration[7.2]
def change
end
end
">Copy</button>
</div>
<p>El generador puede hacer mucho más que anteponer una marca de tiempo al nombre del archivo. Basado en convenciones de nombres y argumentos adicionales (opcionales), también puede comenzar a esbozar la migración.</p><p>Las siguientes secciones cubrirán las diversas formas en que puedes crear migraciones basadas en convenciones y argumentos adicionales.</p><h3 id="creación-de-una-nueva-tabla"><a class="anchorlink" href="#creación-de-una-nueva-tabla"><span>2.2</span> Creación de una Nueva Tabla</a></h3><p>Cuando deseas crear una nueva tabla en tu base de datos, puedes usar una migración con el formato "CreateXXX" seguido de una lista de nombres de columna y tipos. Esto generará un archivo de migración que configura la tabla con las columnas especificadas.</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration CreateProducts name:string part_number:string
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration CreateProducts name:string part_number:string
">Copy</button>
</div>
<p>genera</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:part_number</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateProducts < ActiveRecord::Migration[7.2]
def change
create_table :products do |t|
t.string :name
t.string :part_number
t.timestamps
end
end
end
">Copy</button>
</div>
<p>El archivo generado con su contenido es solo un punto de partida, y puedes agregar o eliminar de él según lo consideres necesario editando el archivo <code>db/migrate/YYYYMMDDHHMMSS_create_products.rb</code>.</p><h3 id="agregar-columnas"><a class="anchorlink" href="#agregar-columnas"><span>2.3</span> Agregar Columnas</a></h3><p>Cuando deseas agregar una nueva columna a una tabla existente en tu base de datos, puedes usar una migración con el formato "AddColumnToTable" seguido de una lista de nombres de columna y tipos. Esto generará un archivo de migración que contiene las declaraciones apropiadas de <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column"><code>add_column</code></a>.</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddPartNumberToProducts part_number:string
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddPartNumberToProducts part_number:string
">Copy</button>
</div>
<p>Esto generará la siguiente migración:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddPartNumberToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span><span class="p">,</span> <span class="ss">:string</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddPartNumberToProducts < ActiveRecord::Migration[7.2]
def change
add_column :products, :part_number, :string
end
end
">Copy</button>
</div>
<p>Si deseas agregar un índice en la nueva columna, también puedes hacerlo.</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddPartNumberToProducts part_number:string:index
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddPartNumberToProducts part_number:string:index
">Copy</button>
</div>
<p>Esto generará las declaraciones apropiadas de <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column"><code>add_column</code></a> y <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_index"><code>add_index</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddPartNumberToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span><span class="p">,</span> <span class="ss">:string</span>
<span class="n">add_index</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddPartNumberToProducts < ActiveRecord::Migration[7.2]
def change
add_column :products, :part_number, :string
add_index :products, :part_number
end
end
">Copy</button>
</div>
<p><strong>No</strong> estás limitado a una columna generada mágicamente. Por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddDetailsToProducts part_number:string price:decimal
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddDetailsToProducts part_number:string price:decimal
">Copy</button>
</div>
<p>Esto generará una migración de esquema que agrega dos columnas adicionales a la tabla <code>products</code>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddDetailsToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span><span class="p">,</span> <span class="ss">:string</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:decimal</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddDetailsToProducts < ActiveRecord::Migration[7.2]
def change
add_column :products, :part_number, :string
add_column :products, :price, :decimal
end
end
">Copy</button>
</div>
<h3 id="eliminación-de-columnas"><a class="anchorlink" href="#eliminación-de-columnas"><span>2.4</span> Eliminación de Columnas</a></h3><p>De manera similar, si el nombre de la migración es de la forma "RemoveColumnFromTable" y es seguido por una lista de nombres de columna y tipos, se creará una migración que contiene las declaraciones apropiadas de <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column"><code>remove_column</code></a>.</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration RemovePartNumberFromProducts part_number:string
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration RemovePartNumberFromProducts part_number:string
">Copy</button>
</div>
<p>Esto generará las declaraciones apropiadas de <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column"><code>remove_column</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">RemovePartNumberFromProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">remove_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span><span class="p">,</span> <span class="ss">:string</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class RemovePartNumberFromProducts < ActiveRecord::Migration[7.2]
def change
remove_column :products, :part_number, :string
end
end
">Copy</button>
</div>
<h3 id="creación-de-asociaciones"><a class="anchorlink" href="#creación-de-asociaciones"><span>2.5</span> Creación de Asociaciones</a></h3><p>Las asociaciones de Active Record se utilizan para definir relaciones entre diferentes modelos en tu aplicación, permitiéndoles interactuar entre sí a través de sus relaciones y facilitando el trabajo con datos relacionados. Para aprender más sobre asociaciones, puedes consultar la <a href="association_basics.html">guía de Conceptos Básicos de Asociaciones</a>.</p><p>Un caso de uso común para las asociaciones es crear referencias de clave externa entre tablas. El generador acepta tipos de columna como <code>references</code> para facilitar este proceso. <a href="#referencias">References</a> son una forma abreviada de crear columnas, índices, claves externas o incluso columnas de asociación polimórfica.</p><p>Por ejemplo,</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddUserRefToProducts user:references
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddUserRefToProducts user:references
">Copy</button>
</div>
<p>genera la siguiente llamada a <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference"><code>add_reference</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddUserRefToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_reference</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddUserRefToProducts < ActiveRecord::Migration[7.2]
def change
add_reference :products, :user, null: false, foreign_key: true
end
end
">Copy</button>
</div>
<p>La migración anterior crea una clave externa llamada <code>user_id</code> en la tabla <code>products</code>, donde <code>user_id</code> es una referencia a la columna <code>id</code> en la tabla <code>users</code>. También crea un índice para la columna <code>user_id</code>. El esquema se ve de la siguiente manera:</p><div class="interstitial code">
<pre><code class="highlight ruby"> <span class="n">create_table</span> <span class="s2">"products"</span><span class="p">,</span> <span class="ss">force: :cascade</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">bigint</span> <span class="s2">"user_id"</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">t</span><span class="p">.</span><span class="nf">index</span> <span class="p">[</span><span class="s2">"user_id"</span><span class="p">],</span> <span class="ss">name: </span><span class="s2">"index_products_on_user_id"</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text=" create_table "products", force: :cascade do |t|
t.bigint "user_id", null: false
t.index ["user_id"], name: "index_products_on_user_id"
end
">Copy</button>
</div>
<p><code>belongs_to</code> es un alias de <code>references</code>, por lo que lo anterior podría escribirse alternativamente como:</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddUserRefToProducts user:belongs_to
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddUserRefToProducts user:belongs_to
">Copy</button>
</div>
<p>generando una migración y esquema que es el mismo que el anterior.</p><p>También hay un generador que producirá tablas de unión si <code>JoinTable</code> es parte del nombre:</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration CreateJoinTableUserProduct user product
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration CreateJoinTableUserProduct user product
">Copy</button>
</div>
<p>producirá la siguiente migración:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateJoinTableUserProduct</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_join_table</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="c1"># t.index [:user_id, :product_id]</span>
<span class="c1"># t.index [:product_id, :user_id]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateJoinTableUserProduct < ActiveRecord::Migration[7.2]
def change
create_join_table :users, :products do |t|
# t.index [:user_id, :product_id]
# t.index [:product_id, :user_id]
end
end
end
">Copy</button>
</div>
<h3 id="otros-generadores-que-crean-migraciones"><a class="anchorlink" href="#otros-generadores-que-crean-migraciones"><span>2.6</span> Otros Generadores que Crean Migraciones</a></h3><p>Además del generador <code>migration</code>, los generadores <code>model</code>, <code>resource</code> y
<code>scaffold</code> crearán migraciones apropiadas para agregar un nuevo modelo. Esta migración ya contendrá instrucciones para crear la tabla relevante. Si le dices a Rails qué columnas deseas, entonces también se crearán declaraciones para agregar estas columnas. Por ejemplo, al ejecutar:</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate model Product name:string description:text
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate model Product name:string description:text
">Copy</button>
</div>
<p>Esto creará una migración que se ve así:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">text</span> <span class="ss">:description</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateProducts < ActiveRecord::Migration[7.2]
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
">Copy</button>
</div>
<p>Puedes agregar tantos pares de nombre de columna/tipo como desees.</p><h3 id="pasando-modificadores"><a class="anchorlink" href="#pasando-modificadores"><span>2.7</span> Pasando Modificadores</a></h3><p>Al generar migraciones, puedes pasar modificadores de tipo comúnmente usados <a href="#modificadores-de-columna">modificadores de columna</a> directamente en la línea de comandos. Estos modificadores, encerrados entre llaves y siguiendo el tipo de campo, te permiten adaptar las características de tus columnas de base de datos sin necesidad de editar manualmente el archivo de migración después.</p><p>Por ejemplo, al ejecutar:</p><div class="interstitial code">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>generate migration AddDetailsToProducts <span class="s1">'price:decimal{5,2}'</span> supplier:references<span class="o">{</span>polymorphic<span class="o">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="bin/rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic}
">Copy</button>
</div>
<p>producirá una migración que se ve así</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddDetailsToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:decimal</span><span class="p">,</span> <span class="ss">precision: </span><span class="mi">5</span><span class="p">,</span> <span class="ss">scale: </span><span class="mi">2</span>
<span class="n">add_reference</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:supplier</span><span class="p">,</span> <span class="ss">polymorphic: </span><span class="kp">true</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddDetailsToProducts < ActiveRecord::Migration[7.2]
def change
add_column :products, :price, :decimal, precision: 5, scale: 2
add_reference :products, :supplier, polymorphic: true
end
end
">Copy</button>
</div>
<p>CONSEJO: Para obtener más ayuda con los generadores, ejecuta <code>bin/rails generate --help</code>. Alternativamente, también puedes ejecutar <code>bin/rails generate model --help</code> o <code>bin/rails generate migration --help</code> para obtener ayuda con generadores específicos.</p><h2 id="actualización-de-migraciones"><a class="anchorlink" href="#actualización-de-migraciones"><span>3</span> Actualización de Migraciones</a></h2><p>Una vez que hayas creado tu archivo de migración usando uno de los generadores de la <a href="#generación-de-archivos-de-migración">sección</a> anterior, puedes actualizar el archivo de migración generado en la carpeta <code>db/migrate</code> para definir más cambios que deseas hacer a tu esquema de base de datos.</p><h3 id="creación-de-una-tabla"><a class="anchorlink" href="#creación-de-una-tabla"><span>3.1</span> Creación de una Tabla</a></h3><p>El método <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table"><code>create_table</code></a> es uno de los tipos de migración más fundamentales, pero la mayoría de las veces, será generado para ti al usar un generador de modelo, recurso o scaffold. Un uso típico sería</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :products do |t|
t.string :name
end
">Copy</button>
</div>
<p>Este método crea una tabla <code>products</code> con una columna llamada <code>name</code>.</p><h4 id="asociaciones"><a class="anchorlink" href="#asociaciones"><span>3.1.1</span> Asociaciones</a></h4><p>Si estás creando una tabla para un modelo que tiene una asociación, puedes usar el tipo <code>:references</code> para crear el tipo de columna apropiado. Por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:category</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :products do |t|
t.references :category
end
">Copy</button>
</div>
<p>Esto creará una columna <code>category_id</code>. Alternativamente, puedes usar <code>belongs_to</code> como un alias para <code>references</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">belongs_to</span> <span class="ss">:category</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :products do |t|
t.belongs_to :category
end
">Copy</button>
</div>
<p>También puedes especificar el tipo de columna y la creación de índices usando la opción <a href="association_basics.html#asociaciones-polimórficas"><code>:polymorphic</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:taggings</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:taggable</span><span class="p">,</span> <span class="ss">polymorphic: </span><span class="kp">true</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :taggings do |t|
t.references :taggable, polymorphic: true
end
">Copy</button>
</div>
<p>Esto creará las columnas <code>taggable_id</code>, <code>taggable_type</code> y los índices apropiados.</p><h4 id="claves-primarias"><a class="anchorlink" href="#claves-primarias"><span>3.1.2</span> Claves Primarias</a></h4><p>Por defecto, <code>create_table</code> creará implícitamente una clave primaria llamada <code>id</code> para ti. Puedes cambiar el nombre de la columna con la opción <code>:primary_key</code>, como se muestra a continuación:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateUsers</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">primary_key: </span><span class="s2">"user_id"</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:username</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateUsers < ActiveRecord::Migration[7.2]
def change
create_table :users, primary_key: "user_id" do |t|
t.string :username
t.string :email
t.timestamps
end
end
end
">Copy</button>
</div>
<p>Esto generará el siguiente esquema:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="s2">"users"</span><span class="p">,</span> <span class="ss">primary_key: </span><span class="s2">"user_id"</span><span class="p">,</span> <span class="ss">force: :cascade</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="s2">"username"</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="s2">"email"</span>
<span class="n">t</span><span class="p">.</span><span class="nf">datetime</span> <span class="s2">"created_at"</span><span class="p">,</span> <span class="ss">precision: </span><span class="mi">6</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">t</span><span class="p">.</span><span class="nf">datetime</span> <span class="s2">"updated_at"</span><span class="p">,</span> <span class="ss">precision: </span><span class="mi">6</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table "users", primary_key: "user_id", force: :cascade do |t|
t.string "username"
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
">Copy</button>
</div>
<p>También puedes pasar un array a <code>:primary_key</code> para una clave primaria compuesta. Lee más sobre <a href="active_record_composite_primary_keys.html">claves primarias compuestas</a>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateUsers</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">primary_key: </span><span class="p">[</span><span class="ss">:id</span><span class="p">,</span> <span class="ss">:name</span><span class="p">]</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateUsers < ActiveRecord::Migration[7.2]
def change
create_table :users, primary_key: [:id, :name] do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
">Copy</button>
</div>
<p>Si no quieres una clave primaria en absoluto, puedes pasar la opción <code>id: false</code>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateUsers</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">id: </span><span class="kp">false</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:username</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateUsers < ActiveRecord::Migration[7.2]
def change
create_table :users, id: false do |t|
t.string :username
t.string :email
t.timestamps
end
end
end
">Copy</button>
</div>
<h4 id="opciones-de-base-de-datos"><a class="anchorlink" href="#opciones-de-base-de-datos"><span>3.1.3</span> Opciones de Base de Datos</a></h4><p>Si necesitas pasar opciones específicas de la base de datos, puedes colocar un fragmento de SQL en la opción <code>:options</code>. Por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">options: </span><span class="s2">"ENGINE=BLACKHOLE"</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :products, options: "ENGINE=BLACKHOLE" do |t|
t.string :name, null: false
end
">Copy</button>
</div>
<p>Esto añadirá <code>ENGINE=BLACKHOLE</code> a la declaración SQL utilizada para crear la tabla.</p><p>Un índice puede ser creado en las columnas creadas dentro del bloque <code>create_table</code> pasando <code>index: true</code> o un hash de opciones a la opción <code>:index</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_table</span> <span class="ss">:users</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">index: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">index: </span><span class="p">{</span> <span class="ss">unique: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">name: </span><span class="s1">'unique_emails'</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_table :users do |t|
t.string :name, index: true
t.string :email, index: { unique: true, name: 'unique_emails' }
end
">Copy</button>
</div>
<h4 id="comentarios"><a class="anchorlink" href="#comentarios"><span>3.1.4</span> Comentarios</a></h4><p>Puedes pasar la opción <code>:comment</code> con cualquier descripción para la tabla que se almacenará en la base de datos misma y puede ser vista con herramientas de administración de bases de datos, como MySQL Workbench o PgAdmin III. Los comentarios pueden ayudar a los miembros del equipo a entender mejor el modelo de datos y a generar documentación en aplicaciones con bases de datos grandes. Actualmente, solo los adaptadores MySQL y PostgreSQL soportan comentarios.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">AddDetailsToProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:decimal</span><span class="p">,</span> <span class="ss">precision: </span><span class="mi">8</span><span class="p">,</span> <span class="ss">scale: </span><span class="mi">2</span><span class="p">,</span> <span class="ss">comment: </span><span class="s2">"El precio del producto en USD"</span>
<span class="n">add_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:stock_quantity</span><span class="p">,</span> <span class="ss">:integer</span><span class="p">,</span> <span class="ss">comment: </span><span class="s2">"La cantidad actual de stock del producto"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class AddDetailsToProducts < ActiveRecord::Migration[7.2]
def change
add_column :products, :price, :decimal, precision: 8, scale: 2, comment: "El precio del producto en USD"
add_column :products, :stock_quantity, :integer, comment: "La cantidad actual de stock del producto"
end
end
">Copy</button>
</div>
<h3 id="creación-de-una-tabla-de-unión"><a class="anchorlink" href="#creación-de-una-tabla-de-unión"><span>3.2</span> Creación de una Tabla de Unión</a></h3><p>El método de migración <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_join_table"><code>create_join_table</code></a> crea una tabla de unión <a href="association_basics.html#the-has-and-belongs-to-many-association">HABTM (has and belongs to many)</a>. Un uso típico sería:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_join_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:categories</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_join_table :products, :categories
">Copy</button>
</div>
<p>Esta migración creará una tabla <code>categories_products</code> con dos columnas llamadas <code>category_id</code> y <code>product_id</code>.</p><p>Estas columnas tienen la opción <code>:null</code> establecida en <code>false</code> por defecto, lo que significa que <strong>debes</strong> proporcionar un valor para poder guardar un registro en esta tabla. Esto puede ser anulado especificando la opción <code>:column_options</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_join_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:categories</span><span class="p">,</span> <span class="ss">column_options: </span><span class="p">{</span> <span class="ss">null: </span><span class="kp">true</span> <span class="p">}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_join_table :products, :categories, column_options: { null: true }
">Copy</button>
</div>
<p>Por defecto, el nombre de la tabla de unión proviene de la unión de los dos primeros argumentos proporcionados a <code>create_join_table</code>, en orden alfabético. En este caso, la tabla se llamaría <code>categories_products</code>.</p><p>Para personalizar el nombre de la tabla, proporciona una opción <code>:table_name</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_join_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:categories</span><span class="p">,</span> <span class="ss">table_name: :categorization</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_join_table :products, :categories, table_name: :categorization
">Copy</button>
</div>
<p>Esto crea una tabla de unión con el nombre <code>categorization</code>.</p><p>Además, <code>create_join_table</code> acepta un bloque, que puedes usar para agregar índices (que no se crean por defecto) o cualquier columna adicional que elijas.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">create_join_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:categories</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">index</span> <span class="ss">:product_id</span>
<span class="n">t</span><span class="p">.</span><span class="nf">index</span> <span class="ss">:category_id</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="create_join_table :products, :categories do |t|
t.index :product_id
t.index :category_id
end
">Copy</button>
</div>
<h3 id="cambiando-tablas"><a class="anchorlink" href="#cambiando-tablas"><span>3.3</span> Cambiando Tablas</a></h3><p>Si deseas cambiar una tabla existente en su lugar, hay <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table"><code>change_table</code></a>.</p><p>Se utiliza de manera similar a <code>create_table</code> pero el objeto generado dentro del bloque tiene acceso a una serie de funciones especiales, por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">change_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">remove</span> <span class="ss">:description</span><span class="p">,</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:part_number</span>
<span class="n">t</span><span class="p">.</span><span class="nf">index</span> <span class="ss">:part_number</span>
<span class="n">t</span><span class="p">.</span><span class="nf">rename</span> <span class="ss">:upccode</span><span class="p">,</span> <span class="ss">:upc_code</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="change_table :products do |t|
t.remove :description, :name
t.string :part_number
t.index :part_number
t.rename :upccode, :upc_code
end
">Copy</button>
</div>
<p>Esta migración eliminará las columnas <code>description</code> y <code>name</code>, creará una nueva columna de tipo string llamada <code>part_number</code> y añadirá un índice en ella. Finalmente, cambia el nombre de la columna <code>upccode</code> a <code>upc_code</code>.</p><h3 id="cambiando-columnas"><a class="anchorlink" href="#cambiando-columnas"><span>3.4</span> Cambiando Columnas</a></h3><p>Similar a los métodos <code>remove_column</code> y <code>add_column</code> que cubrimos <a href="#agregar-columnas">anteriormente</a>, Rails también proporciona el método de migración <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column"><code>change_column</code></a>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">change_column</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:part_number</span><span class="p">,</span> <span class="ss">:text</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="change_column :products, :part_number, :text
">Copy</button>
</div>
<p>Esto cambia la columna <code>part_number</code> en la tabla de productos a un campo de tipo <code>:text</code>.</p><p>NOTA: El comando <code>change_column</code> es <strong>irreversible</strong>. Para asegurar que tu migración se pueda revertir de manera segura, necesitarás proporcionar tu propia migración <code>reversible</code>. Consulta la <a href="#revertir-migraciones-anteriores">sección de Migraciones Reversibles</a> para más detalles.</p><p>Además de <code>change_column</code>, los métodos <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_null"><code>change_column_null</code></a> y <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_default"><code>change_column_default</code></a> se utilizan para cambiar una restricción de nulidad y valores predeterminados de una columna.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">change_column_default</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:approved</span><span class="p">,</span> <span class="ss">from: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">to: </span><span class="kp">false</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="change_column_default :products, :approved, from: true, to: false
">Copy</button>
</div>
<p>Esto cambia el valor predeterminado del campo <code>:approved</code> de true a false. Este cambio solo se aplicará a registros futuros, cualquier registro existente no cambiará. Usa <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_default"><code>change_column_default</code></a> para cambiar una restricción de nulidad.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">change_column_null</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="kp">false</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="change_column_null :products, :name, false
">Copy</button>
</div>
<p>Esto establece el campo <code>:name</code> en productos como una columna <code>NOT NULL</code>. Este cambio se aplica a registros existentes también, por lo que necesitas asegurarte de que todos los registros existentes tengan un <code>:name</code> que no sea nulo.</p><p>Establecer la restricción de nulidad en <code>true</code> implica que la columna aceptará un valor nulo, de lo contrario se aplica la restricción <code>NOT NULL</code> y se debe pasar un valor para persistir el registro en la base de datos.</p><p>NOTA: También podrías escribir la migración <code>change_column_default</code> anterior como <code>change_column_default :products, :approved, false</code>, pero a diferencia del ejemplo anterior, esto haría que tu migración sea irreversible.</p><h3 id="modificadores-de-columna"><a class="anchorlink" href="#modificadores-de-columna"><span>3.5</span> Modificadores de Columna</a></h3><p>Los modificadores de columna pueden aplicarse al crear o cambiar una columna:</p>
<ul>
<li><code>comment</code> Agrega un comentario para la columna.</li>
<li><code>collation</code> Especifica la colación para una columna <code>string</code> o <code>text</code>.</li>
<li><code>default</code> Permite establecer un valor predeterminado en la columna. Ten en cuenta que si estás usando un valor dinámico (como una fecha), el valor predeterminado solo se calculará la primera vez (es decir, en la fecha en que se aplica la migración). Usa <code>nil</code> para <code>NULL</code>.</li>
<li><code>limit</code> Establece el número máximo de caracteres para una columna <code>string</code> y el número máximo de bytes para columnas <code>text/binary/integer</code>.</li>
<li><code>null</code> Permite o no permite valores <code>NULL</code> en la columna.</li>
<li><code>precision</code> Especifica la precisión para columnas <code>decimal/numeric/datetime/time</code>.</li>
<li><code>scale</code> Especifica la escala para las columnas <code>decimal</code> y <code>numeric</code>, representando el número de dígitos después del punto decimal.</li>
</ul>
<p>NOTA: Para <code>add_column</code> o <code>change_column</code> no hay opción para agregar índices. Necesitan ser añadidos por separado usando <code>add_index</code>.</p><p>Algunos adaptadores pueden soportar opciones adicionales; consulta la documentación específica del adaptador para más información.</p><p>NOTA: <code>null</code> y <code>default</code> no pueden especificarse a través de la línea de comandos al generar migraciones.</p><h3 id="referencias"><a class="anchorlink" href="#referencias"><span>3.6</span> Referencias</a></h3><p>El método <code>add_reference</code> permite la creación de una columna apropiadamente nombrada que actúa como la conexión entre una o más asociaciones.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">add_reference</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">:role</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="add_reference :users, :role
">Copy</button>
</div>
<p>Esta migración creará una columna de clave externa llamada <code>role_id</code> en la tabla de usuarios. <code>role_id</code> es una referencia a la columna <code>id</code> en la tabla <code>roles</code>. Además, crea un índice para la columna <code>role_id</code>, a menos que se le indique explícitamente que no lo haga con la opción <code>index: false</code>.</p><div class="interstitial info"><p>Consulta también la guía de <a href="association_basics.html">Asociaciones de Active Record</a> para aprender más.</p></div><p>El método <code>add_belongs_to</code> es un alias de <code>add_reference</code>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">add_belongs_to</span> <span class="ss">:taggings</span><span class="p">,</span> <span class="ss">:taggable</span><span class="p">,</span> <span class="ss">polymorphic: </span><span class="kp">true</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="add_belongs_to :taggings, :taggable, polymorphic: true
">Copy</button>
</div>
<p>La opción polimórfica creará dos columnas en la tabla de etiquetado que pueden usarse para asociaciones polimórficas: <code>taggable_type</code> y <code>taggable_id</code>.</p><div class="interstitial info"><p>Consulta esta guía para aprender más sobre <a href="association_basics.html#asociaciones-polimórficas">asociaciones polimórficas</a>.</p></div><p>Una clave externa puede ser creada con la opción <code>foreign_key</code>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">add_reference</span> <span class="ss">:users</span><span class="p">,</span> <span class="ss">:role</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="add_reference :users, :role, foreign_key: true
">Copy</button>
</div>
<p>Para más opciones de <code>add_reference</code>, visita la <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference">documentación de la API</a>.</p><p>Las referencias también pueden ser eliminadas:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">remove_reference</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">index: </span><span class="kp">false</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="remove_reference :products, :user, foreign_key: true, index: false
">Copy</button>
</div>
<h3 id="claves-externas"><a class="anchorlink" href="#claves-externas"><span>3.7</span> Claves Externas</a></h3><p>Aunque no es obligatorio, podrías querer agregar restricciones de clave externa para <a href="'##active-record-and-referential-integrity">garantizar la integridad referencial</a>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">add_foreign_key</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">:authors</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="add_foreign_key :articles, :authors
">Copy</button>
</div>
<p>La llamada a <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key"><code>add_foreign_key</code></a> añade una nueva restricción a la tabla <code>articles</code>. La restricción garantiza que exista una fila en la tabla <code>authors</code> donde la columna <code>id</code> coincida con el <code>articles.author_id</code> para asegurar que todos los revisores listados en la tabla de artículos sean autores válidos listados en la tabla de autores.</p><p>NOTA: Al usar <code>references</code> en una migración, estás creando una nueva columna en la tabla y tendrás la opción de agregar una clave externa usando <code>foreign_key: true</code> a esa columna. Sin embargo, si deseas agregar una clave externa a una columna existente, puedes usar <code>add_foreign_key</code>.</p><p>Si el nombre de la columna de la tabla a la que estamos agregando la clave externa no se puede derivar de la tabla con la clave primaria referenciada, entonces puedes usar la opción <code>:column</code> para especificar el nombre de la columna. Además, puedes usar la opción <code>:primary_key</code> si la clave primaria referenciada no es <code>:id</code>.</p><p>Por ejemplo, para agregar una clave externa en <code>articles.reviewer</code> que hace referencia a <code>authors.email</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">add_foreign_key</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">:authors</span><span class="p">,</span> <span class="ss">column: :reviewer</span><span class="p">,</span> <span class="ss">primary_key: :email</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="add_foreign_key :articles, :authors, column: :reviewer, primary_key: :email
">Copy</button>
</div>
<p>Esto añadirá una restricción a la tabla <code>articles</code> que garantiza que exista una fila en la tabla <code>authors</code> donde la columna <code>email</code> coincida con el campo <code>articles.reviewer</code>.</p><p>Varias otras opciones como <code>name</code>, <code>on_delete</code>, <code>if_not_exists</code>, <code>validate</code> y <code>deferrable</code> son soportadas por <code>add_foreign_key</code>.</p><p>Las claves externas también pueden ser eliminadas usando <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key"><code>remove_foreign_key</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># dejar que Active Record determine el nombre de la columna</span>
<span class="n">remove_foreign_key</span> <span class="ss">:accounts</span><span class="p">,</span> <span class="ss">:branches</span>
<span class="c1"># eliminar clave externa para una columna específica</span>
<span class="n">remove_foreign_key</span> <span class="ss">:accounts</span><span class="p">,</span> <span class="ss">column: :owner_id</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="# dejar que Active Record determine el nombre de la columna
remove_foreign_key :accounts, :branches
# eliminar clave externa para una columna específica
remove_foreign_key :accounts, column: :owner_id
">Copy</button>
</div>
<p>NOTA: Active Record solo soporta claves externas de una sola columna. <code>execute</code> y <code>structure.sql</code> son necesarios para usar claves externas compuestas. Consulta <a href="#volcado-de-esquema-y-tú">Volcado de Esquema y Tú</a>.</p><h3 id="claves-primarias-compuestas"><a class="anchorlink" href="#claves-primarias-compuestas"><span>3.8</span> Claves Primarias Compuestas</a></h3><p>A veces, el valor de una sola columna no es suficiente para identificar de manera única cada fila de una tabla, pero una combinación de dos o más columnas <em>sí</em> lo identifica de manera única. Esto puede ser el caso cuando se utiliza un esquema de base de datos heredado sin una sola columna <code>id</code> como clave primaria, o al modificar esquemas para particionamiento o multitenencia.</p><p>Puedes crear una tabla con una clave primaria compuesta pasando la opción <code>:primary_key</code> a <code>create_table</code> con un valor de array:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">CreateProducts</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">primary_key: </span><span class="p">[</span><span class="ss">:customer_id</span><span class="p">,</span> <span class="ss">:product_sku</span><span class="p">]</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">integer</span> <span class="ss">:customer_id</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:product_sku</span>
<span class="n">t</span><span class="p">.</span><span class="nf">text</span> <span class="ss">:description</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class CreateProducts < ActiveRecord::Migration[7.2]
def change
create_table :products, primary_key: [:customer_id, :product_sku] do |t|
t.integer :customer_id
t.string :product_sku
t.text :description
end
end
end
">Copy</button>
</div>
<div class="interstitial info"><p>Las tablas con claves primarias compuestas requieren pasar valores de array en lugar de IDs de enteros a muchos métodos. Consulta también la guía de <a href="active_record_composite_primary_keys.html">Claves Primarias Compuestas de Active Record</a> para aprender más.</p></div><h3 id="ejecutar-sql"><a class="anchorlink" href="#ejecutar-sql"><span>3.9</span> Ejecutar SQL</a></h3><p>Si los ayudantes proporcionados por Active Record no son suficientes, puedes usar el método <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-execute"><code>execute</code></a> para ejecutar comandos SQL. Por ejemplo,</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">UpdateProductPrices</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">up</span>
<span class="n">execute</span> <span class="s2">"UPDATE products SET price = 'free'"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">down</span>
<span class="n">execute</span> <span class="s2">"UPDATE products SET price = 'original_price' WHERE price = 'free';"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class UpdateProductPrices < ActiveRecord::Migration[7.2]
def up
execute "UPDATE products SET price = 'free'"
end
def down
execute "UPDATE products SET price = 'original_price' WHERE price = 'free';"
end
end
">Copy</button>
</div>
<p>En este ejemplo, estamos actualizando la columna <code>price</code> de la tabla de productos a 'free' para todos los registros.</p><p>ADVERTENCIA: Modificar datos directamente en migraciones debe abordarse con precaución. Considera si este es el mejor enfoque para tu caso de uso, y ten en cuenta posibles desventajas como la mayor complejidad y el mantenimiento, riesgos para la integridad de los datos y la portabilidad de la base de datos. Consulta la <a href="#migraciones-de-datos">documentación de Migraciones de Datos</a> para más detalles.</p><p>Para más detalles y ejemplos de métodos individuales, consulta la documentación de la API.</p><p>En particular, la documentación para
<a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html"><code>ActiveRecord::ConnectionAdapters::SchemaStatements</code></a> que proporciona los métodos disponibles en los métodos <code>change</code>, <code>up</code> y <code>down</code>.</p><p>Para métodos disponibles en relación con el objeto generado por <code>create_table</code>, consulta
<a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html"><code>ActiveRecord::ConnectionAdapters::TableDefinition</code></a>.</p><p>Y para el objeto generado por <code>change_table</code>, consulta
<a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html"><code>ActiveRecord::ConnectionAdapters::Table</code></a>.</p><h3 id="usando-el-método-change"><a class="anchorlink" href="#usando-el-método-change"><span>3.10</span> Usando el Método <code>change</code></a></h3><p>El método <code>change</code> es la forma principal de escribir migraciones. Funciona para la mayoría de los casos en los que Active Record sabe cómo revertir automáticamente las acciones de una migración. A continuación se muestran algunas de las acciones que <code>change</code> admite:</p>
<ul>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_check_constraint"><code>add_check_constraint</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column"><code>add_column</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key"><code>add_foreign_key</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_index"><code>add_index</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference"><code>add_reference</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_timestamps"><code>add_timestamps</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_comment"><code>change_column_comment</code></a> (debes proporcionar opciones <code>:from</code> y <code>:to</code>)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_default"><code>change_column_default</code></a> (debes proporcionar opciones <code>:from</code> y <code>:to</code>)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_column_null"><code>change_column_null</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table_comment"><code>change_table_comment</code></a> (debes proporcionar opciones <code>:from</code> y <code>:to</code>)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_join_table"><code>create_join_table</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table"><code>create_table</code></a></li>
<li><code>disable_extension</code></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-drop_join_table"><code>drop_join_table</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-drop_table"><code>drop_table</code></a> (debes proporcionar opciones de creación de tabla y bloque)</li>
<li><code>enable_extension</code></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_check_constraint"><code>remove_check_constraint</code></a> (debes proporcionar la expresión de restricción original)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_column"><code>remove_column</code></a> (debes proporcionar el tipo original y opciones de columna)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_columns"><code>remove_columns</code></a> (debes proporcionar el tipo original y opciones de columna)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key"><code>remove_foreign_key</code></a> (debes proporcionar otra tabla y opciones originales)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_index"><code>remove_index</code></a> (debes proporcionar columnas y opciones originales)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_reference"><code>remove_reference</code></a> (debes proporcionar opciones originales)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_timestamps"><code>remove_timestamps</code></a> (debes proporcionar opciones originales)</li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-rename_column"><code>rename_column</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-rename_index"><code>rename_index</code></a></li>
<li><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-rename_table"><code>rename_table</code></a></li>
</ul>
<p><a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table"><code>change_table</code></a> también es reversible, siempre que el bloque solo llame a operaciones reversibles como las enumeradas anteriormente.</p><p>Si necesitas usar cualquier otro método, deberías usar <code>reversible</code> o escribir los métodos <code>up</code> y <code>down</code> en lugar de usar el método <code>change</code>.</p><h3 id="usando-reversible"><a class="anchorlink" href="#usando-reversible"><span>3.11</span> Usando <code>reversible</code></a></h3><p>Si deseas que una migración haga algo que Active Record no sabe cómo revertir, entonces puedes usar <code>reversible</code> para especificar qué hacer al ejecutar una migración y qué más hacer al revertirla.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ChangeProductsPrice</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">reversible</span> <span class="k">do</span> <span class="o">|</span><span class="n">direction</span><span class="o">|</span>
<span class="n">change_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">direction</span><span class="p">.</span><span class="nf">up</span> <span class="p">{</span> <span class="n">t</span><span class="p">.</span><span class="nf">change</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:string</span> <span class="p">}</span>
<span class="n">direction</span><span class="p">.</span><span class="nf">down</span> <span class="p">{</span> <span class="n">t</span><span class="p">.</span><span class="nf">change</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:integer</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class ChangeProductsPrice < ActiveRecord::Migration[7.2]
def change
reversible do |direction|
change_table :products do |t|
direction.up { t.change :price, :string }
direction.down { t.change :price, :integer }
end
end
end
end
">Copy</button>
</div>
<p>Esta migración cambiará el tipo de la columna <code>price</code> a una cadena, o de nuevo a un entero cuando se revierta la migración. Observa el bloque que se pasa a <code>direction.up</code> y <code>direction.down</code> respectivamente.</p><p>Alternativamente, puedes usar <code>up</code> y <code>down</code> en lugar de <code>change</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ChangeProductsPrice</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">up</span>
<span class="n">change_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">change</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:string</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">down</span>
<span class="n">change_table</span> <span class="ss">:products</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">change</span> <span class="ss">:price</span><span class="p">,</span> <span class="ss">:integer</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class ChangeProductsPrice < ActiveRecord::Migration[7.2]
def up
change_table :products do |t|
t.change :price, :string
end
end
def down
change_table :products do |t|
t.change :price, :integer
end
end
end
">Copy</button>
</div>
<p>Además, <code>reversible</code> es útil al ejecutar consultas SQL en bruto o realizar operaciones de base de datos que no tienen un equivalente directo en métodos de ActiveRecord. Puedes usar <a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/Migration.html#method-i-reversible"><code>reversible</code></a> para especificar qué hacer al ejecutar una migración y qué más hacer al revertirla. Por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ExampleMigration</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">7.2</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:distributors</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:zipcode</span>
<span class="k">end</span>
<span class="n">reversible</span> <span class="k">do</span> <span class="o">|</span><span class="n">direction</span><span class="o">|</span>
<span class="n">direction</span><span class="p">.</span><span class="nf">up</span> <span class="k">do</span>
<span class="c1"># crear una vista de distributors</span>
<span class="n">execute</span> <span class="o"><<-</span><span class="no">SQL</span><span class="sh">