I made a reply function for the Rails Tutorial extension (Part 5):

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.

Checking changes in user's view

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.

Change user's view

7.1 Change the user's view. On the screen, we'll put an @ at the beginning to identify this as a unique_name.


        <%= gravatar_for @user %>
        <%= @user.name%>
        @<%= @user.unique_name%>

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.


    <%= 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.


    def user_params
        params.require(:user).permit(:name, :email, :password, 
                                     :password_confirmation, :unique_name)

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

User registration test

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"} }

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.


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. input_form.png show.png

User update test

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.


  name: Michael Example
  email: [email protected]
  password_digest: <%= User.digest('password') %>
  admin: true
  activated: true
  activated_at: <%= Time.zone.now %>  
  unique_name: Michael1

  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 "successful edit" do
    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
    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."
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."

User list test

10.3 Read "Show Show All Users". Make unique_name appear next to name.


  <%= 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

All tests

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
        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.


  def create
    @micropost = current_user.microposts.build(micropost_params)
      #Check for reply
      if reply_id =  @micropost.content.scan(/@\w+/)[0]
        @micropost.in_reply_to = User.find_by(unique_name: reply_id).id


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.


  def create
    @micropost = current_user.microposts.build(micropost_params)
      #Check for reply
      if reply_id =  @micropost.content.scan(/@\w+/)[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.


def create
    @micropost = current_user.microposts.build(micropost_params)
      #Check for reply
      if reply_id =  @micropost.content.scan(/@\w+/)[0]
        if reply_user = User.find_by(unique_name: reply_id)  
          @micropost.in_reply_to = reply_user.id

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
    content = "@#{@other.unique_name} reply test content"

Test from screen

Start the server and test it from the screen. unique_error.png Figure. Testing for unique user duplication

index.png Figure. List of users @ unique_user has been added

I will try to enter a reply. Sender: @Example Recipient: @testb

reply_test1.png Figure. Enter reply

The reply post is displayed on the sender's Home screen. reply_test2.png 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. reply_test3.png 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. reply_test4.png Figure. Reply is hidden on the show screen of the recipient of the reply

Check the specifications of the show screen

The reply does not appear on the recipient's show screen. Think about why and see if you're not using the feed method.


 def show
    @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
    redirect_to root_url and return unless @user.activated == true

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 "feed on Home page" do
    get root_path
    @user.feed.paginate(page: 1).each do |micropost|
      assert_match CGI.escapeHTML(micropost.content), response.body

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.


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.

Time required

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

I made a reply function for the Rails Tutorial extension (Part 1)
I made a reply function for the Rails Tutorial extension (Part 5):
I made a reply function for Rails Tutorial extension (Part 2): Change model
I made a reply function for the Rails Tutorial extension (Part 4): A function that makes the user unique
I tried to make a reply function of Rails Tutorial extension (Part 3): Corrected a misunderstanding of specifications
Rails Tutorial Extension: I created a follower notification function
I tried to make a message function of Rails Tutorial extension (Part 1): Create a model
I tried to make a message function of Rails Tutorial extension (Part 2): Create a screen to display
[Rails] I made a draft function using enum
I made a check tool for the release module
Tutorial to create a blog with Rails for beginners Part 1
Tutorial to create a blog with Rails for beginners Part 2
Tutorial to create a blog with Rails for beginners Part 0
I made a simple recommendation function.
I made a Ruby container image and moved the Lambda function
Rails Tutorial Extension: I tried to create an RSS feed function
I made a plugin for IntelliJ IDEA
I rewrote the Rails tutorial test with RSpec
I made a Ruby extension library in C
I summarized the naming conventions for each Rails
I made a LINE bot with Rails + heroku
I made a portfolio with Ruby On Rails
I made a Docker image of SDAPS for Japanese
I made a method to ask for Premium Friday
A note for Initializing Fields in the Java tutorial
What should I use for the testing framework [Rails]
I want to define a function in Rails Console
I made a library for displaying tutorials on Android.
I made a function to register images with API in Spring Framework. Part 1 (API edition)
I want to add a delete function to the comment function
I made a function to register images with API in Spring Framework. Part 2 (Client Edition)
I made a Japanese version of Rails / devise automatic email
I tried to introduce Bootstrap 4 to the Rails 6 app [for beginners]
I made a development environment with rails6 + docker + postgreSQL + Materialize.
[Rails] I tried using the button_to method for the first time
I want to implement a product information editing function ~ part1 ~
Rails: I've summarized the model and database for a moment.
A note about the seed function of Ruby on Rails
I tried JAX-RS and made a note of the procedure
I want to create a form to select the [Rails] category
[Rails] Implemented a pull-down search function for Active Hash data
Modeling a Digimon with DDD for the first time Part 1
Rails ~ Understanding the message function ~
I tried the Docker tutorial!
[Rails] Implementation of tutorial function
When I made a bar graph with MPAndroidChart, the x-axis label was misaligned for some reason
I made a SPA with Rails + Nuxt.js for half a year of self-study, so please take a look.
[Rails] I made a simple calendar mini app with customized specifications.
Implement a refined search function for multiple models without Rails5 gem.
I want to create a chat screen for the Swift chat app!
I want to add a browsing function with ruby on rails
I tried to implement the image preview function with Rails / jQuery
I recently made a js app in the rumored Dart language
I got a warning message with the rails _6.0.3_ new hello_myapp command
I made a gem to post the text of org-mode to qiita
I made a question that can be used for a technical interview
I made a method to ask for Premium Friday (Java 8 version)
[Rails] How to put a crown mark on the ranking function
Rails Tutorial (6th Edition) -Explanation of background operation for each function-
I made a tool to output the difference of CSV file
[Self-study] Creating a portfolio (original app) after completing the Rails tutorial