localtower 0.5.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -17
- data/app/controllers/localtower/pages_controller.rb +27 -12
- data/app/views/layouts/localtower/application.html.erb +16 -33
- data/app/views/localtower/pages/_alert_no_models.html.erb +3 -0
- data/app/views/localtower/pages/migrations.html.erb +52 -83
- data/app/views/localtower/pages/models.html.erb +53 -70
- data/app/views/localtower/pages/new_migration.html.erb +103 -0
- data/app/views/localtower/pages/new_model.html.erb +87 -0
- data/config/routes.rb +4 -4
- data/lib/localtower/generators/migration.rb +51 -120
- data/lib/localtower/generators/model.rb +52 -28
- data/lib/localtower/generators/service_objects/insert_array.rb +23 -0
- data/lib/localtower/generators/service_objects/insert_defaults.rb +15 -43
- data/lib/localtower/generators/service_objects/insert_indexes.rb +80 -0
- data/lib/localtower/generators/service_objects/insert_nullable.rb +23 -0
- data/lib/localtower/status.rb +1 -1
- data/lib/localtower/tools.rb +13 -16
- data/lib/localtower/version.rb +1 -1
- data/public/css/app.css +0 -49
- data/public/js/app.js +215 -70
- data/public/screenshots/v1.0.0/migrations.png +0 -0
- data/public/screenshots/v1.0.0/models.png +0 -0
- data/public/screenshots/v1.0.0/new_migration.png +0 -0
- data/public/screenshots/v1.0.0/new_model.png +0 -0
- data/spec/dummy/Gemfile +0 -2
- data/spec/dummy/Gemfile.lock +1 -10
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/models/user.rb +1 -0
- data/spec/dummy/config/environments/development.rb +1 -0
- data/spec/dummy/config/puma.rb +1 -1
- data/spec/dummy/db/migrate/20230119221452_create_users.rb +14 -0
- data/spec/dummy/db/migrate/20230119221751_change_users_at1674166670.rb +7 -0
- data/spec/dummy/db/migrate/20230119222054_create_posts.rb +11 -0
- data/spec/dummy/db/migrate/20230119222106_change_posts_at1674166865.rb +5 -0
- data/spec/dummy/db/schema.rb +20 -8
- data/spec/dummy/log/development.log +15281 -3345
- data/spec/dummy/log/localtower.log +1897 -132
- data/spec/dummy/log/test.log +0 -0
- data/spec/dummy/test/index.html +38 -0
- data/spec/dummy/tmp/pids/server.pid +1 -0
- data/spec/factories/migration.rb +25 -41
- data/spec/factories/model.rb +39 -25
- data/spec/lib/localtower/generators/migration_spec.rb +36 -63
- data/spec/lib/localtower/generators/model_spec.rb +43 -34
- data/spec/lib/localtower/generators/service_objects/insert_array_spec.rb +47 -0
- data/spec/lib/localtower/generators/service_objects/insert_defaults_spec.rb +30 -35
- data/spec/lib/localtower/generators/service_objects/insert_indexes_spec.rb +90 -0
- data/spec/lib/localtower/generators/service_objects/insert_nullable_spec.rb +61 -0
- data/spec/lib/localtower/tools_spec.rb +1 -11
- data/spec/spec_helper.rb +8 -3
- metadata +34 -18
- data/app/views/localtower/pages/_migrations.html.erb +0 -57
- data/app/views/localtower/pages/schema.html.erb +0 -67
- data/spec/dummy/db/migrate/20221115190039_create_users.rb +0 -13
- data/spec/dummy/db/migrate/20221115193020_change_users.rb +0 -8
- data/spec/dummy/db/migrate/20221115193532_change_users_at1668540931.rb +0 -5
- data/spec/dummy/db/migrate/20221115193605_change_users_at1668540964.rb +0 -5
- data/spec/dummy/db/migrate/20221115193637_change_users_at1668540996.rb +0 -5
- data/spec/dummy/db/migrate/20221115193642_change_users_at1668541001.rb +0 -5
- data/spec/lib/localtower/generators/relation_spec.rb +0 -65
data/public/js/app.js
CHANGED
@@ -1,88 +1,187 @@
|
|
1
1
|
window.MainApp = {};
|
2
2
|
|
3
|
+
Array.prototype.unique = function () {
|
4
|
+
return this.filter(function (value, index, self) {
|
5
|
+
return self.indexOf(value) === index;
|
6
|
+
});
|
7
|
+
};
|
8
|
+
|
3
9
|
MainApp = {
|
4
|
-
init: function() {
|
5
|
-
},
|
10
|
+
init: function () {},
|
6
11
|
|
7
|
-
ready: function() {
|
8
|
-
$(
|
9
|
-
itemSelector:
|
12
|
+
ready: function () {
|
13
|
+
$(".grid").masonry({
|
14
|
+
itemSelector: ".grid-item",
|
10
15
|
percentPosition: true,
|
11
|
-
columnWidth:
|
16
|
+
columnWidth: ".grid-sizer",
|
17
|
+
});
|
18
|
+
|
19
|
+
MainApp.whenActionOnElement("click", "duplicateLineNewModel", function (e) {
|
20
|
+
e.preventDefault();
|
21
|
+
|
22
|
+
if (MainApp.modelNameAndAttributesAreFilled()) {
|
23
|
+
MainApp.duplicateLine();
|
24
|
+
} else {
|
25
|
+
MainApp.notFilled();
|
26
|
+
}
|
27
|
+
|
28
|
+
return false;
|
12
29
|
});
|
13
30
|
|
14
|
-
MainApp.whenActionOnElement(
|
31
|
+
MainApp.whenActionOnElement(
|
32
|
+
"click",
|
33
|
+
"duplicateLineNewMigration",
|
34
|
+
function (e) {
|
35
|
+
e.preventDefault();
|
36
|
+
MainApp.duplicateLineMigration();
|
37
|
+
return false;
|
38
|
+
}
|
39
|
+
);
|
40
|
+
|
41
|
+
MainApp.whenActionOnElement("click", "removeLineModel", function (e) {
|
15
42
|
e.preventDefault();
|
16
|
-
MainApp.
|
43
|
+
MainApp.removeLineModel(e.currentTarget);
|
17
44
|
return false;
|
18
45
|
});
|
19
46
|
|
20
|
-
MainApp.whenActionOnElement("click", "
|
47
|
+
MainApp.whenActionOnElement("click", "removeLineMigration", function (e) {
|
21
48
|
e.preventDefault();
|
22
|
-
MainApp.
|
49
|
+
MainApp.removeLineMigration(e.currentTarget);
|
23
50
|
return false;
|
24
51
|
});
|
25
52
|
|
26
|
-
|
53
|
+
// New Model
|
54
|
+
MainApp.whenActionOnElement("click", "submitNewModel", function (e) {
|
55
|
+
if (!MainApp.modelNameAndAttributesAreFilled()) {
|
56
|
+
MainApp.notFilled();
|
57
|
+
e.preventDefault();
|
58
|
+
return false;
|
59
|
+
}
|
60
|
+
|
27
61
|
var current = $(e.currentTarget);
|
28
62
|
$(".full-message").show();
|
29
63
|
|
30
64
|
if (current.val() === "false") {
|
31
65
|
$(".full-message-migrate").show();
|
32
66
|
}
|
67
|
+
});
|
33
68
|
|
69
|
+
// New Migration
|
70
|
+
MainApp.whenActionOnElement("click", "submitNewMigration", function (e) {
|
71
|
+
var current = $(e.currentTarget);
|
72
|
+
$(".full-message").show();
|
73
|
+
|
74
|
+
if (current.val() === "false") {
|
75
|
+
$(".full-message-migrate").show();
|
76
|
+
}
|
34
77
|
});
|
35
78
|
|
36
|
-
MainApp.whenActionOnElement("change", "action", function(e) {
|
79
|
+
MainApp.whenActionOnElement("change", "action", function (e) {
|
37
80
|
MainApp.adaptLines();
|
38
81
|
});
|
39
82
|
|
40
83
|
MainApp.adaptLines();
|
41
84
|
MainApp.sanitizeInputs();
|
42
|
-
|
43
85
|
hljs.highlightAll();
|
44
86
|
},
|
45
87
|
|
46
88
|
// INSTANCE --------------------------------------------------
|
47
|
-
sanitizeInputs: function() {
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
89
|
+
sanitizeInputs: function () {
|
90
|
+
function camelize(str) {
|
91
|
+
return str
|
92
|
+
.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
|
93
|
+
return word.toUpperCase();
|
94
|
+
})
|
95
|
+
.replace(/\s+/g, "");
|
96
|
+
}
|
97
|
+
|
98
|
+
function snakeCase(str) {
|
99
|
+
return str
|
100
|
+
.replace(/\ /g, "_")
|
101
|
+
.replace(/[^a-zA-Z0-9\_]/g, "")
|
102
|
+
.replace(/\_\_/g, "_")
|
103
|
+
.toLowerCase();
|
104
|
+
}
|
105
|
+
|
106
|
+
// Model name
|
107
|
+
MainApp.whenActionOnElement("keyup", "modelName", function (e) {
|
108
|
+
var currentInputValue = $(e.currentTarget).val();
|
109
|
+
var cleanInputValue = currentInputValue.replace(/[^a-zA-Z0-9]/g, "");
|
110
|
+
cleanInputValue = camelize(cleanInputValue);
|
111
|
+
$(e.currentTarget).val(cleanInputValue);
|
112
|
+
});
|
113
|
+
|
114
|
+
// Model attributes
|
115
|
+
MainApp.whenActionOnElement("keyup", "attributeName", function (e) {
|
116
|
+
var currentInputValue = $(e.currentTarget).val();
|
117
|
+
$(e.currentTarget).val(snakeCase(currentInputValue));
|
118
|
+
});
|
119
|
+
|
120
|
+
// Migration
|
121
|
+
MainApp.whenActionOnElement("keyup", "column_text", function (e) {
|
122
|
+
var currentInputValue = $(e.currentTarget).val();
|
123
|
+
$(e.currentTarget).val(snakeCase(currentInputValue));
|
124
|
+
});
|
53
125
|
},
|
54
126
|
|
127
|
+
modelNameAndAttributesAreFilled: function () {
|
128
|
+
// attributes name:
|
129
|
+
var valuesForAttributes = [];
|
130
|
+
MainApp.bySelector("attributeName").each(function (el) {
|
131
|
+
valuesForAttributes.push($(this).val());
|
132
|
+
});
|
133
|
+
// model name:
|
134
|
+
valuesForAttributes.push(MainApp.bySelector("modelName").first().val());
|
135
|
+
|
136
|
+
return (
|
137
|
+
valuesForAttributes.filter(function (n) {
|
138
|
+
return n === "";
|
139
|
+
}).length === 0
|
140
|
+
);
|
141
|
+
},
|
55
142
|
|
143
|
+
notFilled: function () {
|
144
|
+
alert("Please fill all the fields");
|
145
|
+
},
|
56
146
|
|
57
147
|
// This is a little bit dirty but it works well for the moment:
|
58
148
|
// We dynamically show/hide fields
|
59
|
-
adaptLines: function() {
|
60
|
-
$.each(MainApp.bySelector("
|
61
|
-
var $
|
149
|
+
adaptLines: function () {
|
150
|
+
$.each(MainApp.bySelector("table").find("table"), function (table) {
|
151
|
+
var $table = $(this);
|
62
152
|
|
63
|
-
var action_input = $
|
153
|
+
var action_input = $table.find("[data-selector='action']");
|
64
154
|
var action = action_input.val();
|
65
155
|
|
66
|
-
var belongs_to_input = $
|
67
|
-
var belongs_to_label =
|
156
|
+
var belongs_to_input = $table.find("[data-selector='belongs_to']");
|
157
|
+
var belongs_to_label = $table.find("[data-selector='belongs_to_label']");
|
68
158
|
|
69
|
-
var column_text_input = $
|
70
|
-
var
|
159
|
+
var column_text_input = $table.find("[data-selector='column_text']");
|
160
|
+
var column_input = $table.find("[data-selector='column_list']");
|
161
|
+
var column_label = $table.find("[data-selector='column_label']");
|
71
162
|
|
72
|
-
var
|
73
|
-
|
163
|
+
var new_column_name_input = $table.find(
|
164
|
+
"[data-selector='new_column_name']"
|
165
|
+
);
|
166
|
+
var new_column_name_label = $table.find(
|
167
|
+
"[data-selector='new_column_name_label']"
|
168
|
+
);
|
74
169
|
|
75
|
-
var
|
76
|
-
var
|
170
|
+
var column_type_input = $table.find("[data-selector='column_type']");
|
171
|
+
var column_type_label = $table.find(
|
172
|
+
"[data-selector='column_type_label']"
|
173
|
+
);
|
77
174
|
|
78
|
-
var
|
79
|
-
var
|
175
|
+
var index_options_inputs = $table.find("[data-selector='index_options']");
|
176
|
+
var index_options_label = $table.find(
|
177
|
+
"[data-selector='index_options_label']"
|
178
|
+
);
|
80
179
|
|
81
|
-
var
|
82
|
-
var
|
180
|
+
var default_input = $table.find("[data-selector='default_input']");
|
181
|
+
var default_label = $table.find("[data-selector='default_label']");
|
83
182
|
|
84
|
-
var nullable_input = $
|
85
|
-
var nullable_label =
|
183
|
+
var nullable_input = $table.find("[data-selector='nullable_input']");
|
184
|
+
var nullable_label = $table.find("[data-selector='nullable_label']");
|
86
185
|
|
87
186
|
$.each(
|
88
187
|
[
|
@@ -90,8 +189,6 @@ MainApp = {
|
|
90
189
|
belongs_to_label,
|
91
190
|
|
92
191
|
column_text_input,
|
93
|
-
column_text_label,
|
94
|
-
|
95
192
|
column_input,
|
96
193
|
column_label,
|
97
194
|
|
@@ -101,31 +198,32 @@ MainApp = {
|
|
101
198
|
column_type_input,
|
102
199
|
column_type_label,
|
103
200
|
|
104
|
-
|
105
|
-
|
201
|
+
index_options_inputs,
|
202
|
+
index_options_label,
|
203
|
+
|
204
|
+
default_input,
|
205
|
+
default_label,
|
106
206
|
|
107
207
|
nullable_input,
|
108
208
|
nullable_label,
|
109
209
|
],
|
110
|
-
function(i, el) {
|
210
|
+
function (i, el) {
|
111
211
|
el.hide();
|
112
|
-
}
|
212
|
+
}
|
213
|
+
);
|
113
214
|
|
114
215
|
var mapping = {
|
115
216
|
add_column: [
|
116
217
|
column_text_input,
|
117
|
-
|
218
|
+
column_label,
|
118
219
|
column_type_input,
|
119
220
|
column_type_label,
|
120
|
-
|
121
|
-
|
221
|
+
default_input,
|
222
|
+
default_label,
|
122
223
|
nullable_input,
|
123
224
|
nullable_label,
|
124
225
|
],
|
125
|
-
remove_column: [
|
126
|
-
column_input,
|
127
|
-
column_label,
|
128
|
-
],
|
226
|
+
remove_column: [column_input, column_label],
|
129
227
|
rename_column: [
|
130
228
|
column_input,
|
131
229
|
column_label,
|
@@ -138,55 +236,102 @@ MainApp = {
|
|
138
236
|
column_type_input,
|
139
237
|
column_type_label,
|
140
238
|
],
|
141
|
-
belongs_to: [
|
142
|
-
belongs_to_input,
|
143
|
-
belongs_to_label,
|
144
|
-
],
|
239
|
+
belongs_to: [belongs_to_input, belongs_to_label],
|
145
240
|
add_index_to_column: [
|
146
241
|
column_input,
|
147
242
|
column_label,
|
243
|
+
index_options_inputs,
|
244
|
+
index_options_label,
|
148
245
|
],
|
149
|
-
remove_index_to_column: [
|
150
|
-
column_input,
|
151
|
-
column_label,
|
152
|
-
],
|
246
|
+
remove_index_to_column: [column_input, column_label],
|
153
247
|
drop_table: [],
|
154
|
-
}
|
248
|
+
};
|
155
249
|
|
156
250
|
inputs_to_show = mapping[action];
|
157
251
|
|
158
252
|
if (inputs_to_show) {
|
159
|
-
$.each(inputs_to_show, function(i, el) {
|
253
|
+
$.each(inputs_to_show, function (i, el) {
|
160
254
|
el.show();
|
161
255
|
});
|
162
256
|
}
|
163
257
|
});
|
164
258
|
},
|
165
259
|
|
166
|
-
duplicateLine: function() {
|
260
|
+
duplicateLine: function () {
|
167
261
|
var tr = MainApp.bySelector("tbody").find("tr").last().clone();
|
168
262
|
MainApp.bySelector("tbody").append(tr);
|
169
|
-
MainApp.bySelector("tbody")
|
263
|
+
MainApp.bySelector("tbody")
|
264
|
+
.find("tr")
|
265
|
+
.last()
|
266
|
+
.find('[name="model[attributes][][attribute_name]"]')
|
267
|
+
.val("")
|
268
|
+
.focus();
|
170
269
|
},
|
171
270
|
|
172
|
-
|
271
|
+
duplicateLineMigration: function () {
|
272
|
+
var table = MainApp.bySelector("table").find("table").last().clone();
|
273
|
+
MainApp.bySelector("table").append(table);
|
274
|
+
MainApp.adaptLines();
|
275
|
+
|
276
|
+
// Populate select/option for column list:
|
277
|
+
var allAttributes = [];
|
278
|
+
MainApp.bySelector("table")
|
279
|
+
.find('[data-selector="column_text"]')
|
280
|
+
.each(function (i, el) {
|
281
|
+
allAttributes.push(el.value);
|
282
|
+
});
|
283
|
+
allAttributes = allAttributes.unique();
|
284
|
+
|
285
|
+
var columnSelector = MainApp.bySelector("table")
|
286
|
+
.find("table")
|
287
|
+
.last()
|
288
|
+
.find('[data-selector="column_list"]')
|
289
|
+
.last();
|
290
|
+
|
291
|
+
var currentValues = [];
|
292
|
+
columnSelector.find("option").each(function (i, el) {
|
293
|
+
currentValues.push(el.value);
|
294
|
+
});
|
295
|
+
|
296
|
+
currentValues = currentValues.concat(allAttributes).unique().sort();
|
297
|
+
|
298
|
+
columnSelector.empty(); // remove old options
|
299
|
+
$.each(currentValues, function (i, value) {
|
300
|
+
columnSelector.append(
|
301
|
+
$("<option></option>").attr("value", value).text(value)
|
302
|
+
);
|
303
|
+
});
|
304
|
+
|
305
|
+
MainApp.bySelector("table")
|
306
|
+
.find("table")
|
307
|
+
.last()
|
308
|
+
.find('[name="migrations[][column]"]')
|
309
|
+
.val("")
|
310
|
+
.focus();
|
311
|
+
},
|
312
|
+
|
313
|
+
removeLineModel: function (target) {
|
173
314
|
if ($(target).parents("tbody").find("tr").length > 1) {
|
174
315
|
$(target).parents("tr").remove();
|
175
316
|
}
|
176
317
|
},
|
177
318
|
|
319
|
+
removeLineMigration: function (target) {
|
320
|
+
if ($(target).parents(".container-table").find("table").length > 1) {
|
321
|
+
$(target).parents("table").remove();
|
322
|
+
}
|
323
|
+
},
|
324
|
+
|
178
325
|
// PRIVATE
|
179
|
-
bySelector: function(selector) {
|
326
|
+
bySelector: function (selector) {
|
180
327
|
return $("[data-selector='" + selector + "']");
|
181
328
|
},
|
182
329
|
|
183
|
-
whenActionOnElement: function(action, selector, callback) {
|
330
|
+
whenActionOnElement: function (action, selector, callback) {
|
184
331
|
$(document).on(action, "[data-selector='" + selector + "']", callback);
|
185
|
-
}
|
186
|
-
}
|
187
|
-
|
188
|
-
MainApp.init();
|
332
|
+
},
|
333
|
+
};
|
189
334
|
|
190
|
-
$(document).ready(function() {
|
335
|
+
$(document).ready(function () {
|
191
336
|
MainApp.ready();
|
192
337
|
});
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/dummy/Gemfile
CHANGED
data/spec/dummy/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: /Users/damln/Work/localtower
|
3
3
|
specs:
|
4
|
-
localtower (0.
|
4
|
+
localtower (0.5.0)
|
5
5
|
active_link_to (>= 1.0.4)
|
6
6
|
rails (>= 5.2.0)
|
7
7
|
thor (>= 0.18.1)
|
@@ -87,10 +87,6 @@ GEM
|
|
87
87
|
activesupport (>= 5.0)
|
88
88
|
i18n (1.12.0)
|
89
89
|
concurrent-ruby (~> 1.0)
|
90
|
-
jquery-rails (4.5.0)
|
91
|
-
rails-dom-testing (>= 1, < 3)
|
92
|
-
railties (>= 4.2.0)
|
93
|
-
thor (>= 0.14, < 2.0)
|
94
90
|
loofah (2.19.0)
|
95
91
|
crass (~> 1.0.2)
|
96
92
|
nokogiri (>= 1.5.9)
|
@@ -150,9 +146,6 @@ GEM
|
|
150
146
|
rake (13.0.6)
|
151
147
|
thor (1.2.1)
|
152
148
|
timeout (0.3.0)
|
153
|
-
turbolinks (5.2.1)
|
154
|
-
turbolinks-source (~> 5.2)
|
155
|
-
turbolinks-source (5.2.0)
|
156
149
|
tzinfo (2.0.5)
|
157
150
|
concurrent-ruby (~> 1.0)
|
158
151
|
websocket-driver (0.7.5)
|
@@ -164,12 +157,10 @@ PLATFORMS
|
|
164
157
|
ruby
|
165
158
|
|
166
159
|
DEPENDENCIES
|
167
|
-
jquery-rails
|
168
160
|
localtower!
|
169
161
|
pg
|
170
162
|
puma
|
171
163
|
rails (~> 7.0.1)
|
172
|
-
turbolinks (~> 5)
|
173
164
|
tzinfo-data
|
174
165
|
|
175
166
|
BUNDLED WITH
|
@@ -37,6 +37,7 @@ Rails.application.configure do
|
|
37
37
|
# Raise an error on page load if there are pending migrations.
|
38
38
|
# config.active_record.migration_error = :page_load
|
39
39
|
config.active_record.migration_error = false if defined?(Localtower)
|
40
|
+
config.reload_classes_only_on_change = false
|
40
41
|
|
41
42
|
# Debug mode disables concatenation and preprocessing of assets.
|
42
43
|
# This option may cause significant delays in view rendering with a large
|
data/spec/dummy/config/puma.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# the maximum value specified for Puma. Default is set to 5 threads for minimum
|
5
5
|
# and maximum, this matches the default thread size of Active Record.
|
6
6
|
#
|
7
|
-
threads_count = ENV.fetch("RAILS_MAX_THREADS") {
|
7
|
+
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 1 }.to_i
|
8
8
|
threads threads_count, threads_count
|
9
9
|
|
10
10
|
# Specifies the `port` that Puma will listen on to receive requests, default is 3000.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :users do |t|
|
4
|
+
t.string :email, null: false
|
5
|
+
t.integer :login_count, default: 0, null: false
|
6
|
+
t.jsonb :metadata, default: {}, null: false
|
7
|
+
t.string :name
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
add_index :users, :email, unique: true
|
12
|
+
add_index :users, :name
|
13
|
+
end
|
14
|
+
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -10,20 +10,32 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema[7.0].define(version:
|
13
|
+
ActiveRecord::Schema[7.0].define(version: 2023_01_19_222106) do
|
14
14
|
# These are extensions that must be enabled in order to support this database
|
15
15
|
enable_extension "plpgsql"
|
16
16
|
|
17
|
+
create_table "posts", force: :cascade do |t|
|
18
|
+
t.string "title", null: false
|
19
|
+
t.string "content", null: false
|
20
|
+
t.datetime "created_at", null: false
|
21
|
+
t.datetime "updated_at", null: false
|
22
|
+
t.bigint "user_id"
|
23
|
+
t.index ["title"], name: "index_posts_on_title"
|
24
|
+
t.index ["user_id"], name: "index_posts_on_user_id"
|
25
|
+
end
|
26
|
+
|
17
27
|
create_table "users", force: :cascade do |t|
|
18
|
-
t.
|
19
|
-
t.
|
20
|
-
t.
|
28
|
+
t.string "email", null: false
|
29
|
+
t.integer "signin_count", default: 0, null: false
|
30
|
+
t.jsonb "metadata", default: {}, null: false
|
31
|
+
t.string "name"
|
21
32
|
t.datetime "created_at", null: false
|
22
33
|
t.datetime "updated_at", null: false
|
23
|
-
t.string "
|
24
|
-
t.
|
25
|
-
t.index ["
|
26
|
-
t.index ["
|
34
|
+
t.string "city"
|
35
|
+
t.index ["city"], name: "index_users_on_city"
|
36
|
+
t.index ["email"], name: "index_users_on_email", unique: true
|
37
|
+
t.index ["name"], name: "index_users_on_name"
|
27
38
|
end
|
28
39
|
|
40
|
+
add_foreign_key "posts", "users"
|
29
41
|
end
|