Rails validates_uniqueness_of 및 MySQL UNIQUE 키 제약 조건
5631 단어 MySQLRailsActiveRecord
이 근처에 상세하게 쓰여져 있습니다.
↓
Rails 6.0에서 "Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1."라는 경고가 나왔을 때의 대처법 - Qiita
소개
Rails + MySQL 로 조금 빠지기 때문에 조금 정리해 보았습니다.
Rails의 validation 기능은 매우 편리하지만, uniqueness 는 presence 나 length 보다 조금 신경을 써야 합니다.
우선, 「무엇을 가지고 독특(일의)로 할까?」의 의식을 해야 합니다.
「대문자・소문자를 동일시할까?」나 「공백의 취급은 어떻게 할까?」등입니다.
여기에서는 대문자·소문자에 대해 생각해 보겠습니다. 또한 전각 문자도 고려하면 너무 복잡해지므로 여기에서는 생각하지 않기로 합니다. 빈 문제도 마찬가지로 여기에서는 생각하지 않기로 합니다.
우선, 알아 두어야 할 것은 「디폴트의 대문자·소문자의 취급은 Rails 라고 구별해 MySQL 는 구별하지 않는다」라고 하는 것입니다. 나는 이 차이를 잊고 여러 번 실수를 했다.
여기서는 Team 모델의 name 속성을 생각해 봅시다.
이후, 팀 이름 Dragon
의 1 레코드가 이미 들어 있다고 생각해 보겠습니다.
대문자·소문자를 동일시하는 경우
예를 들어 팀 이름에 Dragon
가 있으면 DRAGON
또는 dragon
가 허용되지 않는 경우입니다. 이것은 다음과 같이 대응할 수 있습니다.
이하에서 RDBMS(MySQL)측에 UNIQUE 제약을 붙이고 있습니다.
$ rails new uniqueness_test -d mysql
$ rails db:create
$ rails g scaffold Team name:uniq # ← UNIQUE キー制約付けてるよ
$ rails db:migrate
$ rails server
이하로 case_sensitive: false
로 하는 것으로 동일시하고 있습니다.
app/models/team.rbclass Team < ApplicationRecord
validates_uniqueness_of :name, case_sensitive: false # デフォルトは `true` だよ
end
덧붙여서 여기서 case_sensitive: true
로 했을 경우, DRAGON
를 등록하면 이하와 같이 에러가 됩니다. 나는 이때, 「어라? 제대로 validation 쓰고 있는데 어째서? 체크 빠져나갔어?
대문자·소문자를 동일시하지 않는 경우
예를 들면 팀명으로 Dragon
와 DRAGON
를 별물로 하는 경우입니다.
MySQL 측을 괴롭히지 않으면 안되기 때문에 귀찮습니다.
이전 환경에 마이그레이션을 추가합니다.
여기에서는 MySQL 에서는 컬럼에 대해 BINARY 지정을 합니다. 1
db/migrate/20180108034452_change_column_name_of_team.rbclass ChangeColumnNameOfTeam < ActiveRecord::Migration[5.1]
def up
execute("ALTER TABLE teams MODIFY name varchar(255) BINARY")
end
def down
execute("ALTER TABLE teams MODIFY name varchar(255)")
end
end
개인적으로는 여기서 MySQL에 의존하는 형태가 되어 버리므로 범용성이 없어지는 것이 싫습니다. Rails 측에서 더 잘 쓰는 방법 있나요?
그리고 모델을 다음과 같이 DB와 일치시킵니다.
app/models/team.rbclass Team < ApplicationRecord
validates_uniqueness_of :name, case_sensitive: true # case_sensitive はデフォルト true なので省略可
end
덧붙여서 필드가 BINARY 로 되어 있는지 어떤지는 db/schema.rb 를 보면 알 수 있습니다. (collation 부분이 추가됩니다)
db/schema.rb 발췌 t.string "name", collation: "utf8_bin"
결론
validation 의 부분은 Rails 에서는 부담없이 쓸 수 있으므로 편리하네요. 이번에는 DB에 의존하는 부분이 크다고 느꼈기 때문에 써 보았습니다.
일반적으로는 예를 들면 validates_length_of 왠지 엄밀하게 정의해 Rails 의 모델과 DB측을 일치시키는 것일까?그렇다면 변경에 대응하기 어려우므로 DB측의 문자열 길이는 디폴트. Rails 모델로 조정. 등으로하고 있습니다.
그리고 이번 테마에서는 공백의 취급에 대해서도 주의가 필요하다고 느끼고 있습니다.
다음 데이터는 팀 이름과 동일합니까? 아니면 다른가요? 등록을 허용합니까?
データ1: "Cat's EYE" ← 半角スペースが間に1つ
データ2: " Cat's EYE " ← 半角スペースが先頭と後方と単語中に1つずつ
データ3: " Cat's EYE " ← 半角スペースが沢山混ざってる
이것에 대해서는 별도로 나 나름의 생각을 써볼까(기분이 좋으면...)
그 밖에도 COLLATE 를 사용하는 등의 방법이 있습니다. 자세한 내용은 MySQL 설명서를 참조하십시오. ↩
Reference
이 문제에 관하여(Rails validates_uniqueness_of 및 MySQL UNIQUE 키 제약 조건), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/naopontan@github/items/6e18a568ac58fc6bad05
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
예를 들어 팀 이름에
Dragon
가 있으면 DRAGON
또는 dragon
가 허용되지 않는 경우입니다. 이것은 다음과 같이 대응할 수 있습니다.이하에서 RDBMS(MySQL)측에 UNIQUE 제약을 붙이고 있습니다.
$ rails new uniqueness_test -d mysql
$ rails db:create
$ rails g scaffold Team name:uniq # ← UNIQUE キー制約付けてるよ
$ rails db:migrate
$ rails server
이하로
case_sensitive: false
로 하는 것으로 동일시하고 있습니다.app/models/team.rb
class Team < ApplicationRecord
validates_uniqueness_of :name, case_sensitive: false # デフォルトは `true` だよ
end
덧붙여서 여기서
case_sensitive: true
로 했을 경우, DRAGON
를 등록하면 이하와 같이 에러가 됩니다. 나는 이때, 「어라? 제대로 validation 쓰고 있는데 어째서? 체크 빠져나갔어?대문자·소문자를 동일시하지 않는 경우
예를 들면 팀명으로 Dragon
와 DRAGON
를 별물로 하는 경우입니다.
MySQL 측을 괴롭히지 않으면 안되기 때문에 귀찮습니다.
이전 환경에 마이그레이션을 추가합니다.
여기에서는 MySQL 에서는 컬럼에 대해 BINARY 지정을 합니다. 1
db/migrate/20180108034452_change_column_name_of_team.rbclass ChangeColumnNameOfTeam < ActiveRecord::Migration[5.1]
def up
execute("ALTER TABLE teams MODIFY name varchar(255) BINARY")
end
def down
execute("ALTER TABLE teams MODIFY name varchar(255)")
end
end
개인적으로는 여기서 MySQL에 의존하는 형태가 되어 버리므로 범용성이 없어지는 것이 싫습니다. Rails 측에서 더 잘 쓰는 방법 있나요?
그리고 모델을 다음과 같이 DB와 일치시킵니다.
app/models/team.rbclass Team < ApplicationRecord
validates_uniqueness_of :name, case_sensitive: true # case_sensitive はデフォルト true なので省略可
end
덧붙여서 필드가 BINARY 로 되어 있는지 어떤지는 db/schema.rb 를 보면 알 수 있습니다. (collation 부분이 추가됩니다)
db/schema.rb 발췌 t.string "name", collation: "utf8_bin"
결론
validation 의 부분은 Rails 에서는 부담없이 쓸 수 있으므로 편리하네요. 이번에는 DB에 의존하는 부분이 크다고 느꼈기 때문에 써 보았습니다.
일반적으로는 예를 들면 validates_length_of 왠지 엄밀하게 정의해 Rails 의 모델과 DB측을 일치시키는 것일까?그렇다면 변경에 대응하기 어려우므로 DB측의 문자열 길이는 디폴트. Rails 모델로 조정. 등으로하고 있습니다.
그리고 이번 테마에서는 공백의 취급에 대해서도 주의가 필요하다고 느끼고 있습니다.
다음 데이터는 팀 이름과 동일합니까? 아니면 다른가요? 등록을 허용합니까?
データ1: "Cat's EYE" ← 半角スペースが間に1つ
データ2: " Cat's EYE " ← 半角スペースが先頭と後方と単語中に1つずつ
データ3: " Cat's EYE " ← 半角スペースが沢山混ざってる
이것에 대해서는 별도로 나 나름의 생각을 써볼까(기분이 좋으면...)
그 밖에도 COLLATE 를 사용하는 등의 방법이 있습니다. 자세한 내용은 MySQL 설명서를 참조하십시오. ↩
Reference
이 문제에 관하여(Rails validates_uniqueness_of 및 MySQL UNIQUE 키 제약 조건), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/naopontan@github/items/6e18a568ac58fc6bad05
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class ChangeColumnNameOfTeam < ActiveRecord::Migration[5.1]
def up
execute("ALTER TABLE teams MODIFY name varchar(255) BINARY")
end
def down
execute("ALTER TABLE teams MODIFY name varchar(255)")
end
end
class Team < ApplicationRecord
validates_uniqueness_of :name, case_sensitive: true # case_sensitive はデフォルト true なので省略可
end
t.string "name", collation: "utf8_bin"
validation 의 부분은 Rails 에서는 부담없이 쓸 수 있으므로 편리하네요. 이번에는 DB에 의존하는 부분이 크다고 느꼈기 때문에 써 보았습니다.
일반적으로는 예를 들면 validates_length_of 왠지 엄밀하게 정의해 Rails 의 모델과 DB측을 일치시키는 것일까?그렇다면 변경에 대응하기 어려우므로 DB측의 문자열 길이는 디폴트. Rails 모델로 조정. 등으로하고 있습니다.
그리고 이번 테마에서는 공백의 취급에 대해서도 주의가 필요하다고 느끼고 있습니다.
다음 데이터는 팀 이름과 동일합니까? 아니면 다른가요? 등록을 허용합니까?
データ1: "Cat's EYE" ← 半角スペースが間に1つ
データ2: " Cat's EYE " ← 半角スペースが先頭と後方と単語中に1つずつ
データ3: " Cat's EYE " ← 半角スペースが沢山混ざってる
이것에 대해서는 별도로 나 나름의 생각을 써볼까(기분이 좋으면...)
그 밖에도 COLLATE 를 사용하는 등의 방법이 있습니다. 자세한 내용은 MySQL 설명서를 참조하십시오. ↩
Reference
이 문제에 관하여(Rails validates_uniqueness_of 및 MySQL UNIQUE 키 제약 조건), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/naopontan@github/items/6e18a568ac58fc6bad05텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)