I feel like I'm doing the same thing by adding a Not Null constraint in the migration file and adding validation to the model, but what's the difference? I was wondering, so I looked it up.
I found an easy-to-understand article on Qiita, so I would like to introduce it.
[Rails] Difference in behavior between "Not Null constraint defined in table column" and "Validation defined in model (presence: true)".
According to this article
|Put a Not Null constraint on the DB itself||Reject nill(rollback)|
|Validation to model(presence: true)||nill &&Empty string(“”)Reject(rollback)|
It seems that ... In short, the Not Null constraint rejects nil, but not empty strings.
The result is exactly the same as the site you referred to, but I will try it myself.
class CreateTasks < ActiveRecord::Migration[5.2] def change create_table :tasks do |t| t.string :task_name, null: false end end end
When I run it on the console, the result is as expected. I get stuck in a Not Null constraint.
irb(main):002:0> Task.create(task_name: nil) (Omission) ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR: null value in column "task_name" violates not-null constraint)
However. Try making the element of task_name an empty string instead of nil.
irb(main):003:0> Task.create(task_name: "") (0.3ms) BEGIN Task Create (2.4ms) INSERT INTO "tasks" ("task_name", "created_at", "updated_at") VALUES ($1, $2, $3） RETURNING "id" [["task_name", ""], ["created_at", "2020-12-17 03:57:38.946999"], ["updated_at", "2020-12-17 03:57:38.946999"]] (4.3ms) COMMIT
You can save it normally. It was confirmed that the Not Null constraint of the migration file is rejected by nil, but not the empty string.
Now let's add validation to the model file.
class Task < ApplicationRecord validates :task_name, presence: true end
Check with irb.
irb(main):001:0> Task.create(task_name: "") (0.1ms) BEGIN (0.2ms) ROLLBACK => #<Task id: nil, task_name: "", created_at: nil, updated_at: nil> irb(main):002:0>
This time it was rolled back and couldn't be saved.
Then all you have to do is set the validation in the model file! It seems that it is not such a thing when I look it up. For example, in the Rails tutorial this article.
Below is a quote from the Rails tutorial.
But there is still one problem here. The problem is that Active Record does not guarantee uniqueness at the database level. I will explain the problem using a concrete scenario.
Alice registers with the sample application. The email address is [email protected]. Alice accidentally clicks “Submit” twice quickly. Therefore, two requests are sent in a row. The following things happen in sequence: Request 1 creates a user in memory that passes the validation. The same thing happens with request 2. The user for request 1 is saved, and the user for request 2 is also saved.
This results in two user records with the same email address, even though uniqueness has been verified.
The above scenario may seem unbelievable, but please believe it. Rails websites can have this kind of problem when there is a lot of traffic (I also had a hard time understanding this). Fortunately, the solution is easy to implement. In fact, this problem can be solved by just enforcing uniqueness even at the database level. Specifically, the solution is to add an index to the email column on the database (column 6.2) so that the index is unique.
The explanation here explains the uniqueness of the email address (the same email address cannot be registered more than once) with an example, but "On the Rails website, such a problem occurs when there is a lot of traffic. As explained in "There is a possibility", it seems that the validation of the model file may slip through when there is a lot of traffic.
This means that even if a Null value goes through the validation of the model file, it can be played by setting a Not Null constraint on the column on the database.
· Not Null constraint in database rejects nil but does not reject empty string -Validation setting (presence: true) of model file rejects nil and empty string -For model file validation, invalid values may slip through when there is a lot of traffic, so it is best to set both Not Null constraint to database and validation setting to model file for the time being.