0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rails Tutorial 拡張機能の返信機能を作ってみた(その4):ユーザーをユニークにする機能

Posted at

Rails Tutorialの第14章にある、返信機能を作る件の続きです。
前回まででreplyの入力と表示までできました。次にユーザーをユニークにするところを作ります。

###ユーザーをユニークにする機能
####modelの変更 設計
tutorialにあるヒントの

ユーザー登録の項目に一意のユーザー名を追加し、@replyで使えるようにすることです。

を踏まえ、modelに列を追加することにします。

同じように列を追加するやり方を、tutorialで探します。

userモデルに列を追加したのは9章にありました。
念のため、ソースと比べて最新なのか確認します。sample_app/db/schema.rb
を見たところ、adminやreset_sent_atなど大分違います。migrate以下のフォルダにもいくつかありました。
テキストの後ろから「migra」で検索してみます。すると、12章で引っかかりました。リスト12.6で列を追加していました。図12.5が最新でした。

列を追加するイメージを、tutorialと同様に図にします。

列名   属性   
id integer
name string
email string
.. ..
reset_sent_at datetime
unique_name string

図.ユニークな名前のカラムを追加したUserモデル

ユニークなindexを作ったところをtutorialで探します。「index」で検索してみます。すると6章で引っかかりました。リスト6.29でメールアドレスにindexを追加していました。

####modelの変更 コーディング
modelに列を追加します。

ubuntu:~/environment/sample_app (reply-micropost) $ rails generate migration add_unique_name_to_users unique_name:string
Running via Spring preloader in process 2911
      invoke  active_record
      create    db/migrate/20201018232033_add_unique_name_to_users.rb

indexを作る行を、リスト6.29を参考にして手で入力します。

db/migrate/20201018232033_add_unique_name_to_users.rb
class AddUniqueNameToUsers < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :unique_name, :string
    add_index :users, :unique_name, unique: true
  end
end

データベースに変更を加えます。

ubuntu:~/environment/sample_app (reply-micropost) $ rails db:migrate

####modelの変更 テスト
ユニークな名前のテストを作ります。先に作っておいたほうがよかったのかもしれません。
user_test.rbにテストを追加します。

test/models/user_test.rb green
  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar",
                     unique_name: "Example")
  end
test/models/user_test.rb red
   test "unique_name should be present" do
    @user.unique_name = "    "
    assert_not @user.valid?
  end

emailと同様なテストを作ります。
テストを作ってみて、ユニークだがブランクを許していることが分かりました。

ブランクを許さないようにする機能は、email列で同様に作っていたので、tutorialで探します。リスト 6.9にありました。同様に追加します。

app/models/user.rb
  validates :password, presence: true, length: {minimum: 6}, allow_nil: true
  validates :unique_name, presence: true, length: {maximum: 50}, uniqueness: true

ユニークであること、ブランクを許さないことをテストできました。

test/models/user_test.rb green
  test "unique_name shuould be unique" do
    duplicate_user = @user.dup
    duplicate_user.email = @user.email.upcase + "aa"
    @user.save
    assert_not duplicate_user.valid? 
  end

コンソールでテストデータを確認してみます。

>> user = User.first
>> user.valid?
=> false
>> user.errors.full_messages
=> ["Unique name can't be blank", "Unique name has already been taken"]

2人目も同じなのでテストデータを修正します。unique_nameを入れるように変更します。
nameから姓名の名の部分、英語だとfirst nameを取りだしてunique_nameに入れることにします。

db/seeds.rb
99.times do |n|
  name  = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  password = "password"
  unique_name = name.split(' ')[0]
  User.create!( name: name,
                email: email,
                password:              password,
                password_confirmation: password,
                activated: true,
                activated_at: Time.zone.now,
                unique_name: unique_name)
end

データをデータベースに入れ直します。

$ rails db:migrate:reset
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:seed
rails aborted!
ActiveRecord::RecordInvalid: Validation failed: Unique name has already been taken
/home/ubuntu/.rvm/gems/ruby-2.6.3/gems/activerecord-5.1.6/lib/active_record/validations.rb:78:in `raise_validation_error'

エラーが出ました。何件データが入ったのかコンソールで見てみます。

> User.count
   (0.2ms)  SELECT COUNT(*) FROM "users"
=> 14

100件入るはずが、14件しか入っていません。エラー・メッセージに「Unique name has already been taken」とあるので、unique_nameが重複しているのではと考えます。
なぜ重複するのかコンソールで試してみます。

ubuntu:~/environment/sample_app (reply-micropost) $ rails console
>> 99.times do |n|
?> name = Faker::Name.name
>> puts name.split(' ')[0].split(' ')[0]
>> end
Mr.
Forest
Araceli
Mrs.
Cody
Mr.

first_nameを取り出せると踏んでいたのですが、nameの先頭の単語がMR.になっていました。MR.はMrsなどいろいろバリエーションがありそうで、単純なロジックでユニークにするのは難しいと考え、取り出すのは諦めることにします。
nameとunique_nameは関連がない値でよしとして、変更します。

db/seeds.rb
99.times do |n|
  name  = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  password = "password"
  unique_name = Faker::Name.first_name
  User.create!( name: name,
                email: email,
                password:              password,
                password_confirmation: password,
                activated: true,
                activated_at: Time.zone.now,
                unique_name: unique_name)
end

改めてデータをデータベースに入れ直します。その際に、既にデータが入っているので、いったん初期化します。

ubuntu:~/environment/sample_app (reply-micropost) $ rails db:migrate:reset
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:seed

エラーは起きませんでした。データが入ったかコンソールでデータを見てみます。

>> User.last
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 100, name: "Cassandre Cummerata", email: "example-99@railstutorial.org", created_at: "2020-10-21 23:25:17", updated_at: "2020-10-21 23:25:17", password_digest: "$2a$10$5/ddAbowTuZim/atIYzia.jYf5omGvECsfm0AX78v3i...", remember_digest: nil, admin: false, activation_digest: "$2a$10$wMZu8WO6BCWrvYY.oPjMReGiXs0nqJ0TuyA3OZ4QWhu...", activated: true, activated_at: "2020-10-21 23:25:17", reset_digest: nil, reset_sent_at: nil, unique_name: "Julia">

unique_nameが設定されました。

##所要時間

10/18から10/22までの3.5時間です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?