[RUBY] (Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 11]


・ Rails tutorial is the 4th edition ・ This study is the 3rd lap (2nd lap after Chapter 9) ・ The author is a beginner who has done all of Progate.

Basic policy

・ If you read it, you will not understand it. ・ Search and summarize terms that you do not understand (at the bottom of the article, glossary). ・ Dive into what you do not understand. ・ Work on all exercises. ・ Do not copy chords as much as possible.

Authentication system development ・ Enter the 6th stage, Chapter 11. From the perspective of enhancing security, we will include steps to activate the account. It's a common one that you receive an email after registration and follow the link to complete the registration.   Click here for today's BGM. Tatuki Seksu "Hanazawa EP" I like the fact that I packaged various suspicious things with Shoegazing sound.

[11.1.1 Account Activations Controller Exercise]

  1. Let's check that the test suite turns green at this point. → It is GREEN because I have not written a test at this time.

2. The named route in Table 11.2 states that \ _url should be used instead of \ _path. Why? Think about it. Tip: We will now use the named route in emails. → path is a relative path (/ or abbreviated form), url is an absolute path (https: ~~ or complete form). I think that the absolute path which is the complete form of url is necessary for the processing outside rails called mail.

[11.1.2 Account Activation data model memos and exercises]

In the callback, a specific method can be executed just before the action of before_〇〇, 〇〇. It is called a method reference. This is recommended rather than passing a block. (Review) By defining a method below private, it can be kept private to the outside.

  1. After making the changes in this section, let's make sure that the test suite remains green. → GREEN

2. Create an instance of the User class from the console and check that NoMethodError occurs when you try to call the create_activation_digest method from that object (because it is a Private method). Also, let's check the value of the digest from that User object. → This kind of feeling

>> user = User.third
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 2]]
=> #<User id: 3, name: "Mr. Sage Hartmann", email: "[email protected]", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.HyqPb.DwmFICve62DsYte1alLAVihIdeS2F8Rjndry...", remember_digest: nil, admin: false, activation_digest: "$2a$10$9VKv/p9kYrz84SdMs/7s/uzEV3mqzGMmTubIq7.Vz4b...", activated: true, activated_at: "2020-09-17 08:34:09">
>> user.create_activation_digest
Traceback (most recent call last):
        1: from (irb):2
NoMethodError (private method `create_activation_digest' called for #<User:0x000000000426b7a0>)
Did you mean?  restore_activation_digest!
>> user.activation_digest
=> "$2a$10$9VKv/p9kYrz84SdMs/7s/uzEV3mqzGMmTubIq7.Vz4bbIb.ZeLDRy"

3. In Listing 6.34, I learned that there is a method called email.downcase! (You don't have to assign it) to lowercase email addresses. Use this method to improve the downcase_email method in Listing 11.3. Also, if you can change it successfully, make sure that the test suite remains successful. → Just change it to email.downcase !.


    def downcase_email

[11.2.1 Exercise of sending an email for account activation]

  1. Open the console and check that you can escape the email address string with the escape method of the CGI module (Listing 11.15). What is the result of escaping "Don't panic!" With this method? → Below. (Query parameters and CGI are included in the glossary)
>> CGI.escape('[email protected]')
=> "foo%40example.com"
>> CGI.escape("Don't panic!")            
=> "Don%27t+panic%21"

[11.2.2 Preview of sent mail and exercises]

If you are using AWS cloud9, the tutorial uses the old cloud9, so the content you enter in'example.com' looks quite different, so it's confusing, but the content is the same. Start the Rails server and copy all the URLs below https: // of the screen displayed in another tab.

  1. Use the Rails preview function to display the previous email from your browser. What kind of content is displayed in the "Date" column? → Today's date and UTC (Coordinated Universal Time) are displayed. (Isn't Coordinated Universal Time cool? You can tickle your heart)

[11.2.3 Outgoing email test memos and exercises]

The assert_match here doesn't quite fit, but I'm aware that I'm testing the contents of the email for the name, activation token, and escaped email address.

  1. At this point, make sure the test suite is green. → Yes, GREEN !

2. Let's confirm that the test changes to red when the CGI.escape part used in Listing 11.20 is deleted. → Is it because the email address contains meta characters and is not a regular expression unless it is escaped? See this article.

[11.2.4 Update user create action Memo and exercise]

deliver_now: As the name suggests, the email sending process is executed at that moment.

  1. When you register a new user, let's confirm that the redirect destination has changed to an appropriate URL. After that, check the contents of the outgoing mail from the Rails server log. What is the value of the activation token? → I returned to home. Welcome to the Sample App! Click on the link below to activate your account: The random character string included in the URL below is the activation token.

2. Open the console and check that the user has been created on the database. Also, make sure that this user is on the database, but the activation status is still false. → It was activated: false.

[11.3.1 Authenticated? Method abstraction notes and exercises]

I'm confused about what digest I'm talking about. Then look back at Table 11.1 at the beginning of Chapter 11. I have to keep track of what I'm talking about. So, the title of this section seems to be more generalized than abstracted. The authenticated? method can be used with any of the patterns in Table 11.1.

  1. Try creating a new user in the console. What are the new user's memory tokens and activation tokens, and what are the digest values for each token? → It looks like this. The memory system remains nil because it was just created by the user ...
>> user = User.create(name: "muteki", email: "[email protected]", password: "mutekimuteki", password_confirmation: "mutekimuteki")
   (0.1ms)  SAVEPOINT active_record_1
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "[email protected]"], ["LIMIT", 1]]
  SQL (2.5ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest", "activation_digest") VALUES (?, ?, ?, ?, ?, ?)  [["name", "muteki"], ["email", "[email protected]"], ["created_at", "2020-09-17 12:57:50.404544"], ["updated_at", "2020-09-17 12:57:50.404544"], ["password_digest", "$2a$10$eDPAP444JbjJDGucKnoFE.MWFBTAR8dxQ.wXPJfzql9E0TPRVDQfq"], ["activation_digest", "$2a$10$zql927sHRszT.bjitRxBn.slJil.Zvc74AJkztqBZzt7kUiSqBgx."]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 102, name: "muteki", email: "[email protected]", created_at: "2020-09-17 12:57:50", updated_at: "2020-09-17 12:57:50", password_digest: "$2a$10$eDPAP444JbjJDGucKnoFE.MWFBTAR8dxQ.wXPJfzql9...", remember_digest: nil, admin: false, activation_digest: "$2a$10$zql927sHRszT.bjitRxBn.slJil.Zvc74AJkztqBZzt...", activated: false, activated_at: nil>

So, I purposely create a memory system.

>> remember_token = User.new_token
=> "5dyf7BoW9H3H9SYH6VPRYg"
>> remember_digest = User.digest(remember_token)
=> "$2a$10$1CymqXEPzP.b05TblQ3Zye/ukhNblEpGlDxI4kT2VoiLUJK1EHVy2"
>> user.update_attribute(:remember_token, remember_token)
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
>> user.update_attribute(:remember_digest, remember_digest)
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.2ms)  UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ?  [["updated_at", "2020-09-17 13:45:51.944577"], ["remember_digest", "$2a$10$1CymqXEPzP.b05TblQ3Zye/ukhNblEpGlDxI4kT2VoiLUJK1EHVy2"], ["id", 102]]
   (0.0ms)  RELEASE SAVEPOINT active_record_1
=> true

So, each token looks like this. The digest is above.

>> user.remember_token
=> "5dyf7BoW9H3H9SYH6VPRYg"
>> user.activation_token
=> "p5rorOE7trfF4L-YJynnxg"

2. Using the authenticated? Method abstracted in Listing 11.26, let's confirm that the authentication is successful with each token / digest combination. → Just check ... What? ?? NameError in activation_token? ?? I found out and solved it. Is it user.activation_token because it is tied to the user to the last?

>> user.authenticated?(:remember, remember_token)
=> true
>> user.authenticated?(:activation, activation_token)
Traceback (most recent call last):
        1: from (irb):11
NameError (undefined local variable or method `activation_token' for main:Object)

Therefore, it is true below. When creating remember_token, it was better to link it with user.remember_token instead of defining it newly.

>> user.authenticated?(:activation, user.activation_token)
=> true

[11.3.2 Activate with edit action Exercise]

  1. From the console, check the URL included in the email generated in 11.2.4. Where in the URL is the activation token contained? → Same as Exercise 1 of 11.2.4.

2. Paste the URL you found earlier into your browser and check that the user has been successfully authenticated and can be activated. Also, check from the console that the activation status is true. → Authentication was successful and enabled.

[11.3.3 Activation test and refactoring memos and exercises]

-The array deliveries that appears in the test is a variable. So, I cleared it with setup so that it would not interfere with other tests. -Size method: Same as length method. Here, the number of emails (= 1) is confirmed. -Assigns method: You will be able to access the instance variable (@user) in the corresponding action (here we are testing signup, so create action). -Where method: Returns all records that match the given conditions. Here was a comparison with find and find_by.

  1. The activate method in Listing 11.35 calls update_attribute twice, which means that it queries the database once for each row. Let's combine the update_attribute calls into a single update_columns call using the template shown in Listing 11.39 (this will allow us to query the database once). Also, run the test after the change and make sure it turns green. → Below


  def activate
    update_columns(activated: true, activated_at: Time.zone.now)

2. Currently, all users are displayed when the user index page of / users is opened, and individual users can be displayed by specifying an ID such as / users /: id. But when you think about it, it doesn't make sense to show users who aren't valid. So let's change this behavior using the template in Listing 11.40 9. The Active Record where method used here will be explained in a little more detail in 13.3.3. → Below


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

3. Let's create an integration test for both / users and / users /: id to test the code modified in the exercises so far. The update method skips without performing any callbacks and validations, so be careful if you need to apply callbacks or validations. → It's difficult here. The idea is that "unenabled users (@non_activated) are not displayed in the index" and that if you try to access the unenabled user's page (user_path (@non_activated)), you will be skipped to home. " I just need to make sure ... I was worried because I didn't understand the former assertion. After all, when I checked it, I should confirm that "the link of user_path (@non_activated) is not displayed (it is 0)". I see. So it is below. I finally added the test name. Also, I added @non_activated to setup after rewriting the third user in uses.yml to activated: false.


  def setup
    @admin     = users(:michael)
    @non_admin = users(:archer)
    @non_activated = users(:lana)

  test "index as admin including pagination and delete links, 
  not to show non activated user" do
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
    first_page_of_users = User.where(activated: true).paginate(page: 1)
    first_page_of_users.each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
      assert_select 'a[href=?]', user_path(@non_activated), count: 0
      unless user == @admin
        assert_select 'a[href=?]', user_path(user), text: 'delete'
    assert_difference 'User.count', -1 do
      delete user_path(@non_admin)
    get user_path(@non_activated)
    assert_redirected_to root_url

[11.4 Sending emails in a production environment, croakers and exercises]

** Finally came! !! SendGrid! !! ** ** Isn't this terrible? Even if I register, my account will be frozen immediately and I will not be able to skip emails. After taking time for this guy last time, it seems that I have to contact support to solve it after all, so I left it as if I could do it. Don't use it for such a tutorial ... So, I tried various methods to introduce other means, but none of them worked ... I'm dissatisfied, but this time I'll just use sendgrid. This is a topic for the future. ...... After all, it was frozen softly. Yeah.

  1. Let's actually register as a user in the production environment. Did the email arrive at the email address you entered when you registered as a user? → Yeah, it was impossible.

2. When you receive the email, actually click on the email to activate your account. Also, check the logs on Heroku to see what's happening with the activation logs. Tip: Try running the heroku logs command from your terminal. → I want to do it, but I can't.

Chapter 11 Summary

・ If the end is bad, everything is bad. I hate SendGrid. ・ In the future, I would like to work purely on sending emails with Action Mailer. -Include the activation token and escaped email address in the URL.

I wanted to solve the SendGrid problem somehow ... It's a waste to spend more time, so I'll move on. I will definitely do something in the future! Now, next is Chapter 12, resetting the password. This is the final chapter of authentication system development!

Go to Chapter 12! Click here for Chapter 10 Click here for premise and author status for learning

A glossary that somehow captures the image

-Query parameters A question mark "?" Followed by a key / value pair at the end of the URL. It is possible to analyze where the user came from (passive parameter) and change the content according to the specified variable (active parameter). Including all queries Click here for details.

・ CGI (Common Gateway Interface) A mechanism in which a web server calls an external program in response to a request from the client's web browser, and the execution result is sent to the client's web browser via HTTP. Bulletin boards, access counters, questionnaire forms, etc. can be implemented.

・ Assert_mutch If the given string matches the given regular expression, pass the check.

-SMTP (Simple Mail Transfer Protocol) A protocol for forwarding email over the Internet.

Recommended Posts

(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 11]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 1]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 14]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 12]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 5]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 3]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 4]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 8]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 6]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 13]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 9]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 10]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 7]
(Giri) A local government employee in his twenties works on a Rails tutorial [Chapter 2]
(Giri) A local government employee in his twenties works on a Rails tutorial [Introduction]
[Ruby on Rails Tutorial] Error in the test in Chapter 3
[Rails Tutorial Chapter 5] Create a layout
[Rails Struggle/Rails Tutorial] What you learned in Rails Tutorial Chapter 6
[Rails Struggle/Rails Tutorial] What you learned in Rails Tutorial Chapter 3
(Ruby on Rails6) Creating data in a table
[Rails tutorial] A memorandum of "Chapter 11 Account Activation"
rails tutorial Chapter 6
rails tutorial Chapter 1
rails tutorial Chapter 7
rails tutorial Chapter 5
rails tutorial Chapter 10
rails tutorial Chapter 9
rails tutorial Chapter 8
[Rails Tutorial Chapter 2] What to do when you make a mistake in the column name
Rails Tutorial Chapter 5 Notes
Rails Tutorial Chapter 10 Notes
Rails Tutorial Chapter 3 Notes
Rails Tutorial Chapter 3 Learning
Rails Tutorial Memorandum (Chapter 3, 3.1)
Rails Tutorial Chapter 4 Notes
Rails Tutorial Chapter 4 Learning
Rails Tutorial Chapter 1 Learning
Rails Tutorial Chapter 2 Learning
Rails Tutorial Chapter 8 Notes
Rails Tutorial Memorandum (Chapter 3, 3.3.2)
Difficulties in building a Ruby on Rails environment (Windows 10) (SQLite3)
How to display a graph in Ruby on Rails (LazyHighChart)
Apply CSS to a specific View in Ruby on Rails