distinctメソッド
distinctメソッドとは重複レコードを1つにまとめるためのメソッドです。もともとはuniqというメソッドが同じ機能で使えていたようですがRails5になってからはdistinctメソッドを使うように決められているようです。(uniqメソッドは非推奨もしくは使用不可に変更されているようです。)
Railsのdistinctの使い方に関してはっきり分からなかったので自分で検証して確認してみることにします。今回はrails cを使ってモデルを作成して検証します。前準備として、
rails new distinct_app
rails g model User last_name:string first_name:string birthday:date age:integer
として、アプリケーションを作成してモデルも作成します。その後、rails cでコンソールモードにしてコマンドでデータを作成していきます。
User.create(last_name: "Toda", first_name: "Hiroyuki", birthday: "1988-08-17", age:31)
User.create(last_name: "Suzuki", first_name: "Hiroyuki", birthday: "1988-08-17", age:31)
User.create(last_name: "Woda", first_name: "Hiroyuki", birthday: "1988-08-17", age:31)
User.create(last_name: "Toda", first_name: "Hiroyuki", birthday: "1988-06-01", age:31)
User.create(last_name: "Toda", first_name: "Taro", birthday: "1988-06-01", age:31)
User.create(last_name: "Toda", first_name: "Ichiro", birthday: "1988-06-01", age:31)
User.create(last_name: "Toda", first_name: "Hanako", birthday: "1988-06-01", age:31)
というようにUserモデルを作成します。その後、コマンドで
User.select(:first_name, :age).distinct
とすると、
=> #<ActiveRecord::Relation
[#<User id: nil, first_name: "Hiroyuki", age: 31>,
#<User id: nil, first_name: "Taro", age: 31>,
#<User id: nil, first_name: "Ichiro", age: 31>,
#<User id: nil, first_name: "Hanako", age: 31>]
>
という結果が返ってきて問題なさそうです。
distinctはselectしなくても問題ないか?
User.distinct(:first_name)
のように書いて、first_nameカラムが重複しないようになるか試してみました。結果は
=> #<ActiveRecord::Relation [
#<User id: 1, last_name: "Toda", first_name: "Hiroyuki", birthday: "1988-08-17", age: 31, created_at: "2019-09-13 01:49:32", updated_at: "2019-09-13 01:49:32">,
#<User id: 2, last_name: "Suzuki", first_name: "Hiroyuki", birthday: "1988-08-17", age: 31, created_at: "2019-09-13 01:49:44", updated_at: "2019-09-13 01:49:44">,
#<User id: 3, last_name: "Woda", first_name: "Hiroyuki", birthday: "1988-08-17", age: 31, created_at: "2019-09-13 01:49:54", updated_at: "2019-09-13 01:49:54">,
#<User id: 4, last_name: "Toda", first_name: "Hiroyuki", birthday: "1988-06-01", age: 31, created_at: "2019-09-13 01:50:46", updated_at: "2019-09-13 01:50:46">,
#<User id: 5, last_name: "Toda", first_name: "Taro", birthday: "1988-06-01", age: 31, created_at: "2019-09-13 01:52:16", updated_at: "2019-09-13 01:52:16">,
#<User id: 6, last_name: "Toda", first_name: "Ichiro", birthday: "1988-06-01", age: 31, created_at: "2019-09-13 01:52:24", updated_at: "2019-09-13 01:52:24">,
#<User id: 7, last_name: "Toda", first_name: "Hanako", birthday: "1988-06-01", age: 31, created_at: "2019-09-13 01:52:33", updated_at: "2019-09-13 01:52:33">]>
となりました。これだと重複が防げてないですね。。どうやら一度selectしてからdistinctを実行する必要があるみたいです。
まとめ
distinctコマンドは内部的にはSQLのDISTINCTコマンドを呼び出しています。個人的に何となくselectしなくても重複を避けられると思っていたので、今回の検証の結果は意外なものでした。distinctする場合は、selectとしてから...忘れないようにします。