I tried to make a reply function of Rails Tutorial extension (Part 3): Corrected a misunderstanding of specifications

This is a continuation of creating a reply function in Chapter 14 of the Rails Tutorial.

Function to put ID in in_reply_to of model when posted

When a micropost with @reply written is posted, a function to put an ID in in_reply_to of model make.

The only thing to change is to receive the post and save the model. Find out where it is.

Search the net for methods that operate on strings. https://www.sejuku.net/blog/11843 start_with? (Check if it starts with the specified string) http://rubytips86.hatenablog.com/entry/2014/03/28/132953 Read.

It turns out that the specifications are misunderstood

While digging into the features, I realized that it was a misunderstanding that I thought the content would start with @reply. 「@reply exampleuser hogehoge...」 I thought it was, but it should be correct 「@exampleuser hogehoge...」 was.

Even so, if the name contains blanks, you know you have a problem. For example, I came up with the idea that if the name is "Ola Lakin I" and you post it as "@Ola Lakin I", you can only find the name "@Ola".

One possible solution is to add a unique id. Actually, I said the same thing in the text, but at this point I finally got a pinch.

I will think about how to make the following unique because the text also describes the specific method. For the time being, we will assume that @name is unique and does not include blanks. After creating the feature on this premise, we will make some unique changes.

Extract words starting with @ from a string

Try the method you searched on the net on the console.

>> s = "@Example hoge hoge aa"
=> "@Example hoge hoge aa"
>> b = s.scan(/@\w+/)
=> ["@Example"]

Find out what happens when the string does not contain @xx.

>> s2 = "Example hoge hoge aa"
=> "Example hoge hoge aa"
>> b2 = s2.scan(/@\w+/)                                                                                                                            
=> []
>> b2[0]
=> nil

It became nil.

Next, try removing the leading @.

>> b = s.scan(/@\w+/)
=> ["@Example"]
>> b[0].slice!(0)
=> "@"
>> b[0]
=> "Example"

Now you can retrieve the word @xxx.

Change controller

Think the screen doesn't need to be changed and look at the text where to change the controller. I am creating in controllers / microposts_controller.rb.

controllers/microposts_controller.rb


  def create
    @micropost = current_user.microposts.build(micropost_params)
      #Check for reply
      if reply_id =  @micropost.content.scan(/@\w+/)
        @micropost.in_reply_to = reply_id[0].slice![0]
      end
    if @micropost.save
      flash[:succsess] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

Where to write a test of changes

Since we will change the controller, write test first. The test item is that creating a reply micropost will increase the number of recipients by 1. Depending on where you write the test, think about how to separate it from the integration test.

Read back the tutorial for an example of testing the controller. In the microposts in Chapters 13 and 14, the integration test was done after the model test. In 13.3.1, the content of the controller test was to test whether you are logged in.

Let's actually look at the test source. Under the controllers folder. Both were tests to see if you were logged in and displayed the correct page. We found that the integration test was good for verifying the processed results.

Let's write an integration test.

test/integration/reply_test.rb  RED


  test "reply to user " do
    log_in_as(@user)
    content = "@#{@other.name} reply test content"
    post microposts_path, params: { micropost: {content: content }}
    log_in_as(@other)
    get root_path
    assert_not @other.following?(@user)
    assert_match content, response.body
  end

Error in fixture data

When I ran the test, I got an error with the fixture data.

ERROR["test_reply_to_user_", ReplyTest, 0.3831760289999693]
 test_reply_to_user_#ReplyTest (0.38s)
NoMethodError:         NoMethodError: undefined method `id' for nil:NilClass
            test/fixtures/microposts.yml:54:in `get_binding'

It looks like not found. If you look on the net, it depends on the order in which fixtures are called, and if there are external restrictions It seems to be troublesome.

Instead of creating test data with fixture, try to post in model test.

By the way, I will correct the misunderstanding of @ reply's specification when I made the fixture before.

test/models/user_test.rb


  test "feed should have the reply posts" do
    michael = users(:michael)
    malory = users(:malory)
    assert_not malory.following?(michael)
    reply_post = michael.microposts.create!(content: "@malory reply test", 
                                            in_reply_to: malory.id)
    assert michael.feed.include?(reply_post)
    assert malory.feed.include?(reply_post)
  end

The test is now passed.

Change controller

Change the controller.

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(name: reply_id)
      end
    if @micropost.save
      flash[:succsess] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

Correct test data

Correct the test data. Create a user with no space between the first and last name.

test/fixtures/users.yml


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

Correcting mistakes

The test is still Red, so when I debugged with puts, I found a mistake and fixed it. I needed an id.

Before modification @ micropost.in_reply_to = User.find_by (name: reply_id) After modification @ micropost.in_reply_to = User.find_by (name: reply_id) .id

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(name: reply_id).id
      end
    if @micropost.save
      flash[:succsess] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

The test is now GREEN.

Let's test it on the screen. I created a user with no space and confirmed that it works.

Time required

2.5 hours from 10/11 to 10/17.

Recommended Posts

I tried to make a reply function of Rails Tutorial extension (Part 3): Corrected a misunderstanding of specifications
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
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
Rails Tutorial Extension: I tried to create an RSS feed function
I tried to make a group function (bulletin board) with Rails
I made a reply function for the Rails Tutorial extension (Part 4): A function that makes the user unique
[Rails] Implementation of multi-layer category function using ancestry "I tried to make a window with Bootstrap 3"
I tried to make a login function in Java
Rails Tutorial Extension: I created a follower notification function
I tried using Hotwire to make Rails 6.1 scaffold a SPA
I tried to make a client of RESAS-API in Java
I tried to make the "Select File" button of the sample application created in the Rails tutorial cool
I tried to make a machine learning application with Dash (+ Docker) part2 ~ Basic way of writing Dash ~
I tried to make a parent class of a value object in Ruby
How to make a follow function in Rails
I tried to make a machine learning application with Dash (+ Docker) part3 ~ Practice ~
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
[Rails / JavaScript / Ajax] I tried to create a like function in two ways.
Rails6 I want to make an array of values with a check box
I want to define a function in Rails Console
Tutorial to create a blog with Rails for beginners Part 1
[Rails] I tried to create a mini app with FullCalendar
I want to implement a product information editing function ~ part1 ~
I want to make a specific model of ActiveRecord ReadOnly
[Swift] I tried to implement the function of the vending machine
I tried to make the sample application into a microservice according to the idea of the book "Microservice Architecture".
I want to make a function with kotlin and java!
[Rails] Implementation of tutorial function
Tutorial to create a blog with Rails for beginners Part 2
[Ruby on Rails] Since I finished all Rails Tutorial, I tried to implement an additional "stock function"
[Rails] I tried to implement "Like function" using rails and js
Tutorial to create a blog with Rails for beginners Part 0
I want to add a browsing function with ruby on rails
I tried to implement the image preview function with Rails / jQuery
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
I tried to build a simple application using Dockder + Rails Scaffold
[Java] I tried to make a maze by the digging method ♪
Using the face detection function of Watson Visual Recognition, I tried to process a whole body image of a person into an image of only the face part
I tried to make a machine learning application with Dash (+ Docker) part1 ~ Environment construction and operation check ~
I tried to make a sample program using the problem of database specialist in Domain Driven Design
I tried to make a simple face recognition Android application using OpenCV
[Rails] I want to send data of different models in a form
[Rails] I tried to implement a transaction that combines multiple DB processes
[iOS] I tried to make a processing application like Instagram with Swift
I tried to make a Web API that connects to DB with Quarkus
I made a virtual currency arbitrage bot and tried to make money
I tried to make full use of the CPU core in Ruby
I tried to make a talk application in Java using AI "A3RT"
I tried to introduce CircleCI 2.0 to Rails app
Make a login function with Rails anyway
I tried to touch JavaScript Part.2 Object-oriented
[LINE @] I tried to make a Japanese calendar Western calendar conversion BOT [Messaging API]
[Ruby on Rails] How to make the link destination part of the specified id
Amicable numbers, perfect numbers, excess numbers, deficient numbers, palindromic numbers I tried to make various numbers of programs
[First environment construction] I tried to create a Rails 6 + MySQL 8.0 + Docker environment on Windows 10.
A story when I tried to make a video by linking Processing and Resolume
What I tried when I wanted to get all the fields of a bean
I tried to make a simple game with Javafx ① "Let's find happiness game" (unfinished)