Rails Tutorial Extension: I created a follower notification function

This is a continuation of Creating Extensions in Chapter 14 of the Rails Tutorial.

This time we will create a follower notification function.

Define requirements

The tutorial has requirements.

Let's implement a function to notify users by email when they have new followers. Next, let's make the email notification function optional and turn off notifications if you don't need them.

Find out if Twitter has a similar feature. -There was a "Notification" screen. The message "Followed by Mr. xxx" is displayed. -There is a screen where you can turn "email notification" on or off.

These two requirements are required.

Design specifications

We will reduce the requirements to specific functions.

    1. Notify me by email when I have more followers

Adds to the controller to send an email when you press the follow button. Let's see if it can be made in the controller.

app/controllers/relationships_controller.rb


  def create
      @user = User.find(params[:followed_id])
      current_user.follow(@user)
      respond_to do |format|
        format.html { redirect_to @user }
        format.js
      end
  end

It seems that the follow method is executing the detailed contents of the follow, so it seems that you should add an email transmission to the line after that.

To send an email, refer to "Chapter 11 Account Activation" in the tutorial.

    1. "Email notification" can be turned on or off There are two main types, one is that you can enter settings, and the other is that you can change the behavior whether to send an email or not with those settings.

2.1 Operation change function It seems that the latter behavior change can be made by judging with an if statement when sending an email.

2.2 Functions that can be set Breaking down the former settings that can be entered, one is a screen for entering settings and the other is a model for holding the entered values.

2.2.1 Setting screen Since I want to check if the screen for entering the settings was entered correctly after entering, I also need a screen to display. Similar to the Twiiter example, it is a per-user setting. The settings are limited so that only you can do it. It seems that it can be done by adding an item to the existing user change screen.

2.2.2 Model that retains settings It seems that it can be done by adding an item to the existing user model.

    1. Other On Twitter, notifications can be confirmed not only by email but also on the notification screen.

From the creator's point of view, it can be created without any problem as a function.

From the user's point of view, even if you don't have it, you can see it by looking at past emails in your mailbox, so there is no problem.

From the above, I will not make it this time.

Add model

Check the current user model on the console.

>> User.first
  User Load (1.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-11-11 23:26:45", updated_at: "2020-11-11 23:26:45", password_digest: "$2a$10$7XL.tADLyZ5OdhbHWb6Eh.MVIbc1QpHR.cuu9yqe5or...", remember_digest: nil, admin: true, activation_digest: "$2a$10$ZXWhU/7mCD5JjJXuGHDnPeHIEXVzlmNVAvSj2h3fIXx...", activated: true, activated_at: "2020-11-11 23:26:45", reset_digest: nil, reset_sent_at: nil, unique_name: "Example">

Since the last column is unique_name, you can see that the latest version was changed by the reply function. https://qiita.com/sadao2005/items/cc94d1f8673c14d198f1 Read and add columns as shown below.

Column name attribute
id integer
name string
email string
.. ..
unique_name string
follow_notify boolean

Figure. User model with follow notification columns added

Create a topic branch.

ubuntu:~/environment/sample_app (master) $ git checkout -b follow_notify

Generate a migrate that adds columns to the model.

buntu:~/environment/sample_app (reply-micropost) $ rails generate migration add_unique_name_to_users unique_name:string

Write a migrate to add a column.

db/migrate/20201215115547_add_follow_notify_to_users.rb


class AddFollowNotifyToUsers < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :follow_notify, :boolean, default: false, null: false
  end
end
ubuntu:~/environment/sample_app (follow_notify) $ rails db:migrate

Check with console.

> user = User.first
>> user.follow_notify
=> false

The model is ready.

Create a mailer

Then read "11.2 Sending an Account Activation Email" in the tutorial on how to send an email. Generate a Notify mailer.

ubuntu:~/environment/sample_app (follow_notify) $ rails generate mailer NotifyMailer follow_notify
Running via Spring preloader in process 2828
      create  app/mailers/notify_mailer.rb
      create    app/views/notify_mailer
      create    app/views/notify_mailer/follow_notify.text.erb
      create    app/views/notify_mailer/follow_notify.html.erb
      create    test/mailers/notify_mailer_test.rb
      create    test/mailers/previews/notify_mailer_preview.rb

A file was generated with view and test.

Change the email template. Set the destination and subject. Use the variable @user used by the controller.

app/mailers/notify_mailer.rb


  def follow_notify
    mail to: current_user.email, subject: "follow notification"
  end

Create the email body.

html:app/views/notify_mailer/follow_notify.html.erb


<h1>You are followed</h1>

<p>Hi <%= current_user.name %>,</p>

<p>You are followed by <%= @user.name %>.</p>

Update the mailer preview file for testing. I didn't know if it needed to be set, so I won't change it.

Access the preview from your browser.

http://localhost:3000/rails/mailers/notify_mailer/follow_notify

I got an error.

NameError in Rails::MailersController#preview
undefined local variable or method `current_user' for #<NotifyMailer:0x00007f64b45086e0>

I found that I still need to set the value in the preview file.

Change to pass current_user and the followed user as a method variable.

test/mailers/previews/notify_mailer_preview.rb


  def follow_notify
    user = User.first
    followed_user = User.second
    NotifyMailer.follow_notify(user, followed_user)
  end

app/mailers/notify_mailer.rb


  def follow_notify(user, followed_user)
    @user = user
    @followed_user = followed_user
    mail to: user.email, subject: "follow notification"
  end

html:app/views/notify_mailer/follow_notify.html.erb


You are followed

Hi <%= @user.name %>,

You are followed by <%= @followed_user.name %>.

I was able to display it in the preview.

notify1.png

notify2.png

Create test

Make a test. Read Listing 11.19: User Mailer Tests (automatically generated by Rails).

 test/mailers/notify_mailer_test.rb


  test "follow_notify" do
    user = users(:michael)
    followed_user = users(:archer)
    mail = NotifyMailer.follow_notify(user, followed_user)
    assert_equal "follow notification", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["[email protected]"], mail.from
    assert_match user.name,          mail.body.encoded
    assert_match followed_user.name, mail.body.encoded
  end

It became GREEN.

Changed action to send an email when following

Change the action to send an email when you follow. Where to make the changes is relationships_controller.rb as described above.

app/controllers/relationships_controller.rb


  def create
      @user = User.find(params[:followed_id])
      current_user.follow(@user)
      if @user.follow_notify 
        NotifyMailer.follow_notify(current_user, @user).deliver.now
      end
      respond_to do |format|
        format.html { redirect_to @user }
        format.js
      end
  end

Follow it on rails server and see the log to see if the email was sent. Change the user's follow_notify to true for testing. Do it on the console.

python


>> user = User.first
>> user.follow_notify = true
>> user.follow_notify
=> true
>> user.save

I noticed that @user and current_user are the opposite, so I'll fix it.

app/controllers/relationships_controller.rb


      @user = User.find(params[:followed_id])
      current_user.follow(@user)
      if @user.follow_notify 
        NotifyMailer.follow_notify(@user, current_user).deliver_now
      end

The email has been created.

Sent mail to [email protected]utorial.org (9.1ms)
Date: Sat, 19 Dec 2020 02:26:38 +0000
From: [email protected]
To: [email protected]
Subject: follow notification

You are followed

Hi Example User,

You are followed by Vivianne Sporer.

Create an integration test. Add to the follow test.

test/integration/following_test.rb


  def setup
    @user  = users(:michael)
    @other = users(:archer)
    log_in_as(@user)
    ActionMailer::Base.deliveries.clear

  test "should follow a user the standard way" do
    assert_difference '@user.following.count', 1 do
      post relationships_path, params: { followed_id: @other.id }
    end
    assert_equal 1, ActionMailer::Base.deliveries.size
  end
 test_should_follow_a_user_the_standard_way#FollowingTest (0.82s)
        Expected: 1
          Actual: 0
        test/integration/following_test.rb:34:in `block in <class:FollowingTest>'

Since follow_notify of archer which is @other is false, it becomes RED. Change the fixture's follow_notify to true.

test/fixtures/users.yml


archer:
  name: Sterling Archer
  email: [email protected]
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>  
  unique_name: Archer1
  follow_notify: true

It became GREEN.

Create a setting function for "email notification"

Create a function to turn "email notification" on or off. As we looked at earlier, we'll add an item to an existing user change screen. View the user-edited view.

ruby:app/views/users/edit.html.erb


    <%= render 'form' %>  

I'm calling form, so I'll see it.

Recall that the checkbox was on the screen that remembers the user. "9.2 [Remember me] checkbox"

python


      <%= f.label :remember_me, class: "checkbox inline" do %>
        <%= f.check_box :remember_me %>
        <span>Remember me on this computer</span>
      <% end %>

Check the net how to specify the boolean column in form_for. https://qiita.com/tanutanu/items/b86c4adc26ae464c71fd

I found that when I had a related model, I used the checkbox method.

By the way, if you use f.check_box instead of check_box (that is, if you use it in form_with or form_for, the first argument (object) can be omitted.

There was.

ruby:app/views/users/_form.html.erb


   <%= form_for(@user, url: yield(:url_path) ) do |f|%>
    
...
    <%= f.label :password_confirmation %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>

    <%= f.label :follow_notify %>
    <%= f.check_box :follow_notify, class: 'form-control' %>


    <%= f.submit yield(:button_text), class: "btn btn-primary" %>
    <% end %>    

I will display it on the screen. notify3.png

When I updated it, there was no error on the screen, but there was something that looked like an error in the log.

Started PATCH "/users/1" for 133.106.33.48 at 2020-12-20 01:34:53 +0000
Processing by UsersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"m2dZ6rvG6WmcX4kasgUW6qZzSngJNHZpszjdEOyaIfUXp5xpihm7OhBWm9USAUmA1t2VfXn9JSixF5MO26lHYg==", "user"=>{"name"=>"Example User", "email"=>"[email protected]", "unique_name"=>"Example", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "follow_notify"=>"1"}, "commit"=>"Save changes", "id"=>"1"}
Unpermitted parameter: :follow_notify

I remember setting the permit somewhere, so I'll look it up. I wondered if it was a user update, so I will add it.

app/controllers/users_controller.rb


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

Clear the check box for updates. It was a success.

Check the data on the console to see if it was updated.

>> User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-11-11 23:26:45", updated_at: "2020-12-20 02:04:03", password_digest: "$2a$10$7XL.tADLyZ5OdhbHWb6Eh.MVIbc1QpHR.cuu9yqe5or...", remember_digest: nil, admin: true, activation_digest: "$2a$10$ZXWhU/7mCD5JjJXuGHDnPeHIEXVzlmNVAvSj2h3fIXx...", activated: true, activated_at: "2020-11-11 23:26:45", reset_digest: nil, reset_sent_at: nil, unique_name: "Example", follow_notify: false>

It was updated to false.

Change the check box layout so that it is centered for clarity.

app/assets/stylesheets/custom.scss


   <%= f.label :follow_notify %>
    <%= f.check_box :follow_notify, class: 'checkbox inline' %>


  #user_follow_notify {
    width: auto;
    margin-left: 0;
  }
  
  
  #session_remember_me {
    width: auto;
    margin-left: 0;
  }

ruby:app/views/users/_form.html.erb


    <%= f.label :follow_notify %>
    <%= f.check_box :follow_notify, class: 'checkbox inline' %>

notify4.png

I couldn't put the label and the checkbox on the same line, but that's okay.

Create test

Make a test. Add an item to the user's edit test. It became GREEN.

test/integration/users_edit_test.rb


 test "successful edit" do
... 
   follow_notify = false
    patch user_path(@user), params: { user: { name: name,
                                              email: email,
                                              password:              "",
                                              password_confirmation: "",
                                              unique_name: unique_name,
                                              follow_notify: follow_notify } }

This completes the "follower notification" function.

Time required

8.0 hours from 12/13 to 12/20

Recommended Posts

Rails Tutorial Extension: I created a follower notification function
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 tried to make a message function of Rails Tutorial extension (Part 1): Create a model
I tried to make a reply function of Rails Tutorial extension (Part 3): Corrected a misunderstanding of specifications
Rails Tutorial Extension: I tried to create an RSS feed function
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 4): A function that makes the user unique
[Rails] Notification function
[Rails] I made a draft function using enum
[Rails] Implementation of tutorial function
[Rails DM] Let's create a notification function when DM is sent!
Add a search function in Rails.
I want to add a browsing function with ruby on rails
[Rails Tutorial Chapter 5] Create a layout
I tried to make a group function (bulletin board) with Rails
[Rails withdrawal] Create a simple withdrawal function with rails
Make a login function with Rails anyway
I created a Rails post form, but I can't post it (form tag) / No error occurs
[Rails / JavaScript / Ajax] I tried to create a like function in two ways.
rails tutorial
rails tutorial
rails tutorial
rails tutorial
rails tutorial
rails tutorial
Where I got stuck in today's "rails tutorial" (2020/10/08)
A summary of only Rails tutorial setup related
Add a tag function to Rails. Use acts-as-taggable-on
Where I got stuck in today's "rails tutorial" (2020/10/05)
Where I got stuck in today's "rails tutorial" (2020/10/06)
I made a Ruby extension library in C
Let's make a search function with Rails (ransack)
Where I got stuck in today's "rails tutorial" (2020/10/04)
[Rails tutorial] A memorandum of "Chapter 11 Account Activation"
I made a LINE bot with Rails + heroku
How to make a follow function in Rails
Simple notification function in Rails (only when followed)
Where I got stuck in today's "rails tutorial" (2020/10/07)
I made a portfolio with Ruby On Rails
When I created a user my page, the user editing function of devise became strange.
[Rails 6.0] I implemented a tag search function (a function to narrow down by tags) [no gem]