[RUBY] Difference between Not Null constraint and model validation (presence: true)

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.

Conclusion

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

Case result
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.

I tried it myself

Not Null constraint

The result is exactly the same as the site you referred to, but I will try it myself.

migration.rb


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.

migration.rb


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.

Validation to model (presence: true)

Now let's add validation to the model file.

model.rb


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.

Check with the official reference

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.

Summary

· 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.

Recommended Posts

Difference between Not Null constraint and model validation (presence: true)
Difference between Not Null constraint and model validation (presence: true)
Add Not null constraint after Rails
Rails validation and null: false Personal notes
[Rails] Validation settings and Japanese localization
[Rails] [Memo] When to add = to <%%> and when not
A note about the Rails and Vue process
Difference between vh and%
Difference between i ++ and ++ i
Difference between product and variant
Difference between redirect_to and render
[Java] Difference between == and equals
Difference between puts and print
Difference between redirect_to and render
Difference between CUI and GUI
Difference between variables and instance variables
Difference between mockito-core and mockito-all
Difference between element 0, null and empty string (check in list)
Difference between class and instance
Difference between ArrayList and LinkedList
Difference between List and ArrayList
Difference between .bashrc and .bash_profile
Difference between StringBuilder and StringBuffer
Difference between render and redirect_to
Difference between render and redirect_to
[Ruby] Difference between get and post
Difference between instance method and class method
Difference between render method and redirect_to
Difference between interface and abstract class
Difference between == operator and equals method
[Java] Difference between Hashmap and HashTable
[Terminal] Difference between irb and pry
JavaServlet: Difference between executeQuery and executeUpdate
[Ruby] Difference between is_a? And instance_of?
Difference between == operator and eqals method
Rough difference between RSpec and minitest
Understand the difference between each_with_index and each.with_index
Difference between instance variable and class variable
Relationship between database and model (basic)
[JAVA] Difference between abstract and interface
Difference between Thymeleaf @RestController and @Controller
Difference between Stream map and flatMap
Add Not null constraint after Rails
Difference between primitive type and reference type
Difference between string.getByte () and Hex.decodeHex (string.toCharaArray ())
[Java] Difference between Closeable and AutoCloseable
[Java] Difference between StringBuffer and StringBuilder
[Java] Difference between length, length () and size ()
[rails] Difference between redirect_to and render
[Android] Difference between finish (); and return;
The difference between puts and print in Ruby is not just the presence or absence of line breaks
Note: Difference between Ruby "p" and "puts"
Difference between final and Immutable in Java
Difference between Ruby instance variable and local variable
Difference between pop () and peek () in stack
About the difference between irb and pry
Difference between "|| =" and "instance_variable_defined?" In Ruby memoization
Difference between EMPTY_ELEMENTDATA and DEFAULTCAPACITY_EMPTY_ELEMENTDATA in ArrayList
Difference between addPanel and presentModally of FloatingPanel
[Ruby] Difference between print, puts and p
[Java] Difference between Intstream range and rangeClosed
Difference between int and Integer in Java
Rails validation and null: false Personal notes
[Rails] Difference between redirect_to and render [Beginner]