This is a continuation of Creating Extensions in Chapter 14 of the Rails Tutorial.
This time we will create a follower notification function.
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.
We will reduce the requirements to specific functions.
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.
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.
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.
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 |
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.
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.
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.
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] (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 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.
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' %>
I couldn't put the label and the checkbox on the same line, but that's okay.
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.
8.0 hours from 12/13 to 12/20
Recommended Posts