This is a continuation of creating a reply function in Chapter 14 of the Rails Tutorial. Up to the last time, we have created and tested a model that makes the user unique. Next, add functions to user updates / changes.
Think about where and how to add unique_name. Read back Chapter 7 of the tutorial. 7.1 Display users Add unique_name to the items to be displayed 7.2 User registration form Add unique_name to the input items 7.3 User registration failure Added to error message, added to test 7.4 Successful user registration added to the test when successful
Read back Chapter 10 User Update / Display / Delete. 10.1 Update user Add unique_name to the input items 10.3 Display all users Added unique_name to the displayed items
I think this covers it.
7.1 Change the user's view. On the screen, we'll put an @ at the beginning to identify this as a unique_name.
ruby:views/users/show.html.erb
<h1>
<%= gravatar_for @user %>
<%= @user.name%>
@<%= @user.unique_name%>
</h1>
7.2 Add to the user registration form. I searched for which file and looked at new.html.erb and found that it was render'form'. I knew I should add it to the form.
ruby:views/users/_form.html.erb
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :unique_name %>
<%= f.text_field :unique_name, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
Next, look at the contourler.
I looked at 7.3.2 Strong Parameters and found out where to add it.
controllers/users_controller.rb
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :unique_name)
end
7.3.3 Read back the error message. For the error message in Figure 7.18, we know that unique_name should also output an error. Unique name can't be blank Unique name has already been taken
Listing 7.23: Add tests as well as tests for invalid user registrations.
ubuntu:~/environment/sample_app (reply-micropost) $ rails test test/integration/users_signup_test.rb
FAIL["test_valid_signup_information_with_account_activation", UsersSignupTest, 1.2921500019999712]
test_valid_signup_information_with_account_activation#UsersSignupTest (1.29s)
"User.count" didn't change by 1.
Expected: 36
Actual: 35
test/integration/users_signup_test.rb:29:in `block in <class:UsersSignupTest>'
I tried running the test before adding it and it turned out to be RED. I thought that adding a user was an error because there was no unique_name in the test test_valid_signup_information_with_account_activation that registered normally. Add unique_name.
test/integration/users_signup_test.rb GREEN
test "valid signup information with account activation" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: {name: "Example User",
email: "[email protected]",
password: "password",
password_confirmaiton: "password",
unique_name: "Example1"} }
end
Since the test was successful, I decided to launch the server and register the user from the screen.
First, repopulate the database to remove the users you entered in the test.
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:migrate:reset
ubuntu:~/environment/sample_app (reply-micropost) $ rails db:seed
I also got a duplicate error. As a debug, when I tried to output unique_name with puts, Jeramy was output twice. Faker thinks that first_name alone is not unique, so he decides to add a number after first_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}#{n+1}"
It went well. Let's look at some data in the console.
>> User.last
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ? [["LIMIT", 1]]
=> #<User id: 100, name: "Dorian Greenfelder", email: "[email protected]", created_at: "2020-10-24 02:06:54", updated_at: "2020-10-24 02:06:54", password_digest: "$2a$10$syodSOoCtHmdP/vi20.LgOou95cxRnHino0IhRRcxQN...", remember_digest: nil, admin: false, activation_digest: "$2a$10$LAs1aWDvwZIS0UPWhTR47.9BIGQPQ4eY16qFJT148dY...", activated: true, activated_at: "2020-10-24 02:06:54", reset_digest: nil, reset_sent_at: nil, unique_name: "Alejandrin99">
When I started the server and registered the user from the screen, I was able to register successfully.
Read 10.1 “Update User” in the tutorial. When I tried updating the user from the screen, there was no error and the update was successful.
The test is likely to be RED as it was when registering, so I'll give it a try.
ubuntu:~/environment/sample_app (reply-micropost) $ rails test test/integration/users_edit_test.rb
FAIL["test_successful_edit", UsersEditTest, 1.2000509099998453]
test_successful_edit#UsersEditTest (1.20s)
Expected true to be nil or false
test/integration/users_edit_test.rb:33:in `block in <class:UsersEditTest>'
Thinking about the cause, I noticed that I didn't add unique_name to the fixture user.
test/fixtures/users.yml
michael:
name: Michael Example
email: [email protected]
password_digest: <%= User.digest('password') %>
admin: true
activated: true
activated_at: <%= Time.zone.now %>
unique_name: Michael1
archer:
name: Sterling Archer
email: [email protected]
password_digest: <%= User.digest('password') %>
activated: true
activated_at: <%= Time.zone.now %>
unique_name: Archer1
Also add the unique_name change to the test for successful changes.
test/integration/users_edit_test.rb
test "successful edit" do
log_in_as(@user)
get edit_user_path(@user)
assert_template 'users/edit'
name = "Foo Bar"
email = "[email protected]"
unique_name = "Foo1"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "",
unique_name: unique_name} }
Add the unique_name change to the failure test as well.
test/integration/users_edit_test.rb RED
test "unsuccessful edit" do
log_in_as(@user)
#log_in(@user)
get edit_user_path(@user)
assert_template 'users/edit'
patch user_path(@user), params: { user: {name: "",
email: "foo@invalid",
password: "foo",
password_confirmation: "bar",
unique_name: "" } }
assert_template 'users/edit'
assert_select "div.alert", "The form contains 4 errors."
end
test_unsuccessful_edit#UsersEditTest (0.94s)
<The form contains 4 errors.> expected but was
<The form contains 5 errors.>..
Expected 0 to be >= 1.
test/integration/users_edit_test.rb:20:in `block in <class:UsersEditTest>'
Since the error of unique_name is increased by one, it became RED as expected. When I increased the number of errors from 4 to 5, it became GREEN.
test/integration/users_edit_test.rb GREEN
test "unsuccessful edit" do
assert_select "div.alert", "The form contains 5 errors."
end
10.3 Read "Show Show All Users". Make unique_name appear next to name.
ruby:app/views/users/_user.html.erb
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<%= "@" + user.unique_name %>
I ran the index test and it was GREEN. test/integration/users_index_test.rb
Try running all the tests.
FAIL["test_profile_display", UsersProfileTest, 0.9564320010000529]
test_profile_display#UsersProfileTest (0.96s)
<Michael Example> expected but was
<Michael Example
@Michael1>..
Expected 0 to be >= 1.
There is an error in the profile test. The h1 string is not "exactly match name" Change to "Include name". I searched the net and found that regular expressions can be used for asserts. https://zariganitosh.hatenablog.jp/entry/20080405/1207455670
assert_select "title", /Welcome/ #Success if "Welcome" is included in the title tag string.
Refer to the article and change it.
test/integration/users_profile_test.rb GREEN
test "profile display" do
get user_path(@user)
assert_template 'users/show'
assert_select 'title', full_title(@user.name)
assert_select 'h1', /#{@user.name}/
assert_select 'h1', /#{@user.unique_name}/
Change the place where name was used in reply to use unique_name.
controllers/microposts_controller.rb
def create
@micropost = current_user.microposts.build(micropost_params)
#Check for reply
if reply_id = @micropost.content.scan(/@\w+/)[0]
reply_id.slice!(0)
@micropost.in_reply_to = User.find_by(unique_name: reply_id).id
end
Test
test/controllers/microposts_controller_test.rbubuntu:~/environment/sample_app (reply-micropost) $ rails test
ERROR["test_reply_to_user_", ReplyTest, 2.186517049000031]
test_reply_to_user_#ReplyTest (2.19s)
NoMethodError: NoMethodError: undefined method `id' for nil:NilClass
app/controllers/microposts_controller.rb:10:in `create'
test/integration/reply_test.rb:14:in `block in <class:ReplyTest>'
I was wondering if test would result in an error caused by using name for reply and not changing it yet, but I got a different error. The message says that User.find_by (unique_name: reply_id) is nil. I think it's because find_by is Not Found. Debug with puts.
controllers/microposts_controller.rb
def create
@micropost = current_user.microposts.build(micropost_params)
#Check for reply
if reply_id = @micropost.content.scan(/@\w+/)[0]
reply_id.slice!(0)
puts (User.find_by(unique_name: reply_id) == nil)
Since the output of puts was true, change the controller so that it does nothing if it is Not Found.
controllers/microposts_controller.rb
def create
@micropost = current_user.microposts.build(micropost_params)
#Check for reply
if reply_id = @micropost.content.scan(/@\w+/)[0]
reply_id.slice!(0)
if reply_user = User.find_by(unique_name: reply_id)
@micropost.in_reply_to = reply_user.id
end
end
When I tested it, the previous error disappeared and I got another error.
ubuntu:~/environment/sample_app (reply-micropost) $ rails test
FAIL["test_reply_to_user_", ReplyTest, 1.5751866470000095]
test_reply_to_user_#ReplyTest (1.58s)
Expected /@Bob\ reply\ test\ content/ to match "<!DOCTYPE html> ...
<h3>Micropost Feed</h3>\n \n </div>\n </div>\n\n
The error is that the post of the reply is not displayed in the feed.
I realized that I didn't change the reply posted in the test from name to unique_name. When I changed it, it became GREEN.
test/integration/reply_test.rb GREEN
test "reply to user " do
log_in_as(@user)
content = "@#{@other.unique_name} reply test content"
Start the server and test it from the screen. Figure. Testing for unique user duplication
Figure. List of users @ unique_user has been added
I will try to enter a reply. Sender: @Example Recipient: @testb
Figure. Enter reply
The reply post is displayed on the sender's Home screen. Figure. Shown to the sender of the reply
Log in again as the recipient of the reply and display the home screen. The post of reply is displayed. Figure. reply is displayed on the Home screen of the recipient of the reply
The reply post is not displayed on the recipient's show screen. Figure. Reply is hidden on the show screen of the recipient of the reply
The reply does not appear on the recipient's show screen. Think about why and see if you're not using the feed method.
app/controllers/users_controller.rb
def show
@user = User.find(params[:id])
@microposts = @user.microposts.paginate(page: params[:page])
redirect_to root_url and return unless @user.activated == true
end
I didn't use the feed method. Consider whether this specification meets your requirements. The point is that show can be used by people who are not logged in.
Looking back when I decided on the requirements,
-When a third party displays the recipient's feed screen, reply is not displayed
I had decided the requirements. So I found that there was no problem.
Then check the requirements to see if they should be visible to the followers. Looking back when I decided on the requirements,
The followers of the reply sender are visible. The followers of the reply recipient are not visible.
was. It seems to be confirmed in the follow test, so confirm it.
test/integration/following_test.rb
test "feed on Home page" do
get root_path
@user.feed.paginate(page: 1).each do |micropost|
assert_match CGI.escapeHTML(micropost.content), response.body
end
end
I was able to confirm it because I used feed.
Actually check on the screen. Find @Example followers as sender followers. Looking at seeds, users [3..40] are following. Log in with one of them. name:Gladys Kuhlman email:[email protected] The reply was displayed.
Check the screen of the followers of the recipient of the reply. There were no followers of @testb. It is user [2] who is not following the sender. name:Horacio Kautzer email:[email protected] Log in with. Follow @testb from the screen. I returned to the Home screen, and since reply was not displayed, I was able to confirm that the operation was correct.
I noticed that the old specification @ was written in seeds and fixed it. It's just a cosmetic issue, so it doesn't affect the test, but I don't like it if I don't understand it later, so I fixed it.
/sample_app/db/seeds.rb
sender = users.first
receiver = users.second
reply_content = "@#{receiver.unique_name} reply test"
sender.microposts.create!(content: reply_content,
in_reply_to: receiver.id)
This completes the reply function.
5.5 hours from 10/23 to 10/26. In the whole reply function, 9 / 27-10 / 26, the working day is 29 days, totaling 22 hours.
Recommended Posts