· 6 years ago · Aug 12, 2019, 02:24 PM
1# require 'pg'; PG.connect(dbname: 'postgres').exec('create database josh_testing') # <-- uncomment to create the db (only needs to run once)
2
3# ===== Setup ActiveRecord =====
4require 'active_record'
5require 'logger'
6ActiveRecord::Base.establish_connection adapter: 'postgresql', database: 'josh_testing'
7ActiveRecord::Base.logger = Logger.new $stdout
8ActiveSupport::LogSubscriber.colorize_logging = false
9
10# ===== Migration =====
11ActiveRecord::Schema.define do
12 self.verbose = false
13
14 # reset db
15 drop_table :tasks, if_exists: true
16 execute "drop type if exists task_status;"
17
18 # create the type
19 execute "create type task_status as enum ('completed', 'in_progress', 'pending', 'open', 'rescheduled');"
20
21 # create the table
22 create_table :tasks do |t|
23 t.column :status, :task_status, null: false
24 end
25end
26
27# ===== Model =====
28class Task < ActiveRecord::Base
29 enum status: {
30 completed: 'completed',
31 in_progress: 'in_progress',
32 pending: 'pending',
33 open: 'open',
34 rescheduled: 'rescheduled',
35 }
36end
37
38# ===== Create some tasks =====
39Task.create! [
40 {status: 'completed'},
41 {status: 'completed'},
42 {status: 'pending'},
43 {status: 'open' },
44]
45
46# ===== Querying =====
47Task.completed.to_sql
48# => "SELECT \"tasks\".* FROM \"tasks\" WHERE \"tasks\".\"status\" = 'completed'"
49
50Task.completed
51# => [#<Task:0x00007ff3ae0e8090 id: 1, status: "completed">,
52# #<Task:0x00007ff3ae0f3e18 id: 2, status: "completed">]
53Task.pending
54# => [#<Task:0x00007ff3ae10a960 id: 3, status: "pending">]
55Task.open
56# => [#<Task:0x00007ff3ada2bc70 id: 4, status: "open">]
57
58# ===== Invalid Values =====
59# All three of these seem like strange behaviour to me, feels like it should just add a validation
60Task.new(status: 'something_else') rescue $! # => #<ArgumentError: 'something_else' is not a valid status>
61Task.new.valid? # => true
62Task.new.save rescue $! # => #<ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR: null value in column "status" violates not-null constraint\nDETAIL: Failing row co...
63
64# We can address the last two with our own validation
65Task.validates :status, inclusion: { in: Task.statuses.keys }
66
67Task.new(status: 'something_else') rescue $! # => #<ArgumentError: 'something_else' is not a valid status>
68t = Task.new
69t.valid? # => false
70t.errors.full_messages # => ["Status is not included in the list"]
71
72# >> D, [2019-07-31T10:39:04.582684 #89309] DEBUG -- : (4.4ms) DROP TABLE IF EXISTS "tasks"
73# >> D, [2019-07-31T10:39:04.585073 #89309] DEBUG -- : (1.9ms) drop type if exists task_status;
74# >> D, [2019-07-31T10:39:04.588222 #89309] DEBUG -- : (2.7ms) create type task_status as enum ('completed', 'in_progress', 'pending', 'open', 'rescheduled');
75# >> D, [2019-07-31T10:39:04.594838 #89309] DEBUG -- : (5.9ms) CREATE TABLE "tasks" ("id" bigserial primary key, "status" task_status NOT NULL)
76# >> D, [2019-07-31T10:39:04.634232 #89309] DEBUG -- : ActiveRecord::InternalMetadata Load (0.5ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key"...
77# >> D, [2019-07-31T10:39:04.674247 #89309] DEBUG -- : (0.4ms) BEGIN
78# >> D, [2019-07-31T10:39:04.675448 #89309] DEBUG -- : (0.2ms) COMMIT
79# >> W, [2019-07-31T10:39:04.676516 #89309] WARN -- : Creating scope :open. Overwriting existing method Task.open.
80# >> D, [2019-07-31T10:39:04.684591 #89309] DEBUG -- : (0.2ms) BEGIN
81# >> D, [2019-07-31T10:39:04.686838 #89309] DEBUG -- : Task Create (0.7ms) INSERT INTO "tasks" ("status") VALUES ($1) RETURNING "id" [["status", "completed"]]
82# >> D, [2019-07-31T10:39:04.688405 #89309] DEBUG -- : (1.2ms) COMMIT
83# >> D, [2019-07-31T10:39:04.688896 #89309] DEBUG -- : (0.1ms) BEGIN
84# >> D, [2019-07-31T10:39:04.689679 #89309] DEBUG -- : Task Create (0.3ms) INSERT INTO "tasks" ("status") VALUES ($1) RETURNING "id" [["status", "completed"]]
85# >> D, [2019-07-31T10:39:04.691084 #89309] DEBUG -- : (1.2ms) COMMIT
86# >> D, [2019-07-31T10:39:04.691541 #89309] DEBUG -- : (0.1ms) BEGIN
87# >> D, [2019-07-31T10:39:04.692292 #89309] DEBUG -- : Task Create (0.3ms) INSERT INTO "tasks" ("status") VALUES ($1) RETURNING "id" [["status", "pending"]]
88# >> D, [2019-07-31T10:39:04.693792 #89309] DEBUG -- : (1.2ms) COMMIT
89# >> D, [2019-07-31T10:39:04.694248 #89309] DEBUG -- : (0.1ms) BEGIN
90# >> D, [2019-07-31T10:39:04.694988 #89309] DEBUG -- : Task Create (0.3ms) INSERT INTO "tasks" ("status") VALUES ($1) RETURNING "id" [["status", "open"]]
91# >> D, [2019-07-31T10:39:04.696737 #89309] DEBUG -- : (1.5ms) COMMIT
92# >> D, [2019-07-31T10:39:04.698658 #89309] DEBUG -- : Task Load (0.3ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."status" = $1 [["status", "completed"]]
93# >> D, [2019-07-31T10:39:04.699880 #89309] DEBUG -- : Task Load (0.3ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."status" = $1 [["status", "pending"]]
94# >> D, [2019-07-31T10:39:04.700838 #89309] DEBUG -- : Task Load (0.3ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."status" = $1 [["status", "open"]]
95# >> D, [2019-07-31T10:39:04.701720 #89309] DEBUG -- : (0.2ms) BEGIN
96# >> D, [2019-07-31T10:39:04.702980 #89309] DEBUG -- : Task Create (0.6ms) INSERT INTO "tasks" DEFAULT VALUES RETURNING "id"
97# >> D, [2019-07-31T10:39:04.703311 #89309] DEBUG -- : (0.2ms) ROLLBACK