This is a continuation of creating a reply function in Chapter 14 of the Rails Tutorial. Up to the last time, I was able to input and display the reply. Next, create a place to make the user unique.
Tips in the tutorial
Add a unique user name to the user registration field so that it can be used with @reply.
Based on that, I will add a column to the model.
Find a way to add columns in the tutorial as well.
It was in Chapter 9 that we added columns to the user model. Just in case, make sure it's up to date compared to the source. sample_app / db / schema.rb Looking at it, admin and reset_sent_at are quite different. There were also some in the folders under migrate. Try searching for "migra" from the back of the text. Then, I got caught in Chapter 12. I was adding a column in Listing 12.6. Figure 12.5 was the latest.
Make the image to which you want to add columns a diagram, similar to the tutorial.
Column name | attribute |
---|---|
id | integer |
name | string |
string | |
.. | .. |
reset_sent_at | datetime |
unique_name | string |
Figure. User model with uniquely named columns
Find the place where you created the unique index in the tutorial. Try searching for "index". Then I got caught in Chapter 6. I was adding an index to my email address in Listing 6.29.
Add a column to 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
Enter the line to create the index by hand, referring to Listing 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
Make changes to the database.
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:migrate
Create a test with a unique name. It may have been better to make it first. Add the test to user_test.rb.
test/models/user_test.rb green
def setup
@user = User.new(name: "Example User", email: "[email protected]",
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
Create a test similar to email. I made a test and found that it was unique but allowed blanks.
The function to prevent blanks was created in the email column as well, so look for it in the tutorial. It was in Listing 6.9. Add in the same way.
app/models/user.rb
validates :password, presence: true, length: {minimum: 6}, allow_nil: true
validates :unique_name, presence: true, length: {maximum: 50}, uniqueness: true
I was able to test that it was unique and did not allow blanks.
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
Let's check the test data on the console.
>> user = User.first
>> user.valid?
=> false
>> user.errors.full_messages
=> ["Unique name can't be blank", "Unique name has already been taken"]
The second person is the same, so modify the test data. Change it to include unique_name. I will take out the first name part of the first and last name from name, and first name in English and put it in 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
Put the data back in the database.
$ 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'
I got an error. Let's see how many data have been entered on the console.
> User.count
(0.2ms) SELECT COUNT(*) FROM "users"
=> 14
There should be 100, but only 14 are included. The error message says "Unique name has already been taken", so I suspect that the unique_name is duplicated. Try it on the console to see why it overlaps.
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.
I was stepping on that I could retrieve the first_name, but the first word of the name was MR. MR. Seems to have various variations such as Mrs, and I think it is difficult to make it unique with simple logic, so I will give up taking it out. Change name and unique_name as irrelevant values.
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
Put the data back in the database. At that time, since the data is already included, initialize it once.
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:migrate:reset
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:seed
No error occurred. Let's look at the data on the console to see if it has entered.
>> 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: "[email protected]", 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 has been set.
3.5 hours from 10/18 to 10/22.
Recommended Posts