This is a continuation of the task of creating a message function in Chapter 14 of the Rails Tutorial.
The model was made up to the last time. Make a screen to display.
Create a way to display DM. Read 13.2 "Displaying Microposts" in the tutorial.
Instead of displaying it according to the User's screen like Micropost, we will display it on a separate page. Similar to Twitter.
Make a mockup. Since there are multiple senders, refer to Figure 14.5 as a mockup showing the senders.
DM(3) Image 1 Thomas Hobbes Lorem ipsum sent 1 day ago. Image 2 Sasha Smith Also poor, nasty, sent 2 days ago. Image 3 John Calvin Excepteur sint sent 3 days ago.
Previous 1 2 3 next
Figure DM page mockup
Generate a controller to create a controller and a view.
ubuntu:~/environment/sample_app (create-dm) $ rails generate controller Dms
Make a view. Refer to Listings 13.22 and 13.24.
ruby:app/views/dms/show.html.erb
<% provide(:title, @user.name)%>
<div class="row">
<div class="col-md-8">
<% if @user.send_dms.any? %>
<h3>DMs (<%= @user.sent_dms.count %>)</h3>
<ol class="dms">
<li id="dm-<%= dm.id %>">
<%= link_to gravatar_for(dm.sender, size: 50), dm.sender %>
<span class="user"><%= link_to dm.sender.name, dm.sender%></span>
<span class="content"><%= dm.content %></span>
<span class="timestamp">
Sent <%= time_ago_in_words(dm.created_at) %> ago.
</span>
</li>
</ol>
<% end %>
</div>
</div>
Create a controller to display the new DM page. Read "12.1.1 Password Resets Controller" in the tutorial.
config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users do
member do
get :following, :followers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
resources :dms, only: [:new, :create, :index, :destroy]
end
HTTP request | URL | Action | Named route |
---|---|---|---|
GET | /dms/new | new | new_dm_path |
POST | /dms | create | dms_path |
GET | /dms | index | dms_path |
DELETE | dms/ |
destroy | dm_path |
RESTful routing
Read "10.3.1 User List Page" in the tutorial. There was a link added to the list "10.40: Update the link to the user list page". Add in the same way.
ruby:views/layouts/_header.html.erb
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li><%= link_to "DM", dms_path %></li>
Display the screen to verify that the link has been added to the menu.
I'll create a test to Redirect if I'm not logged in later.
I noticed that the controller is index, but the view is show. Rename the file. show.html.erb -> index.html.erb
app/controllers/dms_controller.rb
class DmsController < ApplicationController
def index
end
end
Let's display it on the screen with rails server. I got an error. The message is undefined method `name' for nil:NilClass So, where the error occurred <% provide(:title, @user.name)%> is. I think @user is nil. To set @user to the logged-in user, refer to the user's show screen and change it in the same way.
app/controllers/dms_controller.rb
class DmsController < ApplicationController
def index
@user = current_user
end
end
I will display it on the screen. I got an error again.
undefined local variable or method `dm' for #<#<Class:0x00005575f57bf2a8>:0x00005575f57deb58>
Where the error occurred
<li id="dm-<%= dm.id %>">
is. I think I need to put data in @dms in my controller. Let's see how to display the micropost on the home screen.
With a controller
@micropost = current_user.microposts.build
@feed_items = current_user.feed.paginate(page: params[:page])
And @feed_items with data.
In view
python
<ol class="microposts">
<%= render @feed_items%>
</ol>
And @feed_items are listed by render. I will change it for reference.
app/controllers/dms_controller.rb
def index
@user = current_user
@dms = @user.sent_dms
end
In Micropost, it seems good to refer to Chapter 13 which makes good use of feed and feed_items. In reading back
render @user
I wasn't sure what that meant, so I'll go back and read it back. To the controller
app/controllers/dms_controller.rb
def index
@user = current_user
@dms = @user.sent_dms.paginate(page: params[:page])
end
In that case, in view
<span class="user"><%= link_to dm.sender.name, dm.sender%></span>
Think about what to write in.
ruby:app/views/dms/index.html.erb
<% provide(:title, @user.name) %>
<h1>DM</h1>
<% if @user.sent_dms.any? %>
<h3>DMs (<%= @user.sent_dms.count %>)</h3>
<ol class= "microposts">
<%= render @dms %>
</ol>
<%= will_paginate @dms %>
<% end %>
ruby:app/views/dms/_dm.html.erb
<li id="dm-<%= dm.id %>">
<%= link_to gravatar_for(dm.sender, size: 50), dm.sender %>
<span class="user"><%= link_to dm.sender.name, dm.sender%></span>
<span class="content"><%= dm.content %></span>
<span class="timestamp">
Sent <%= time_ago_in_words(dm.created_at) %> ago.
</span>
</li>
I will try to display the screen with rails server. There is only one page due to the small amount of data. Increase the data to see if pagnate is done. Let's use Faker :: Hipster.sentence to generate test data for content.
db/seeds.rb
# DM
users = User.order(:created_at).take(6)
receiver = users.second
50.times do
content = Faker::Hipster.sentence
users.each {|user| user.sent_dms.create!(content: content,
receiver_id: receiver.id) }
end
Let's display the screen.
I noticed that the receiver is not coming out, so I will change it from the sender.
ruby:app/views/dms/_dm.html.erb
<li id="dm-<%= dm.id %>">
<%= link_to gravatar_for(dm.receiver, size: 50), dm.receiver %>
<span class="user"><%= link_to dm.receiver.name, dm.receiver%></span>
Create a test of the screen that displays the DM. Refer to "13.2.3 Testing the micropost on the profile screen" in the tutorial.
test/fixtures/dms.yml
...
<% 30.times do |n| %>
dm_<%= n %>:
content: <%= Faker::Hipster.sentence %>
created_at* <%= 42.days.ago %>
sender: michael
receiver: archer
<% end %>
test/integration/dms_test.rb
class DmsTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "dm display" do
log_in_as(@user)
get dms_path
assert_template 'dms/index'
assert_select 'title', full_title(@user.name)
assert_match @user.sent_dms.count.to_s, response.body
assert_select 'div.pagination'
@user.sent_dms.paginate(page: 1).each do |dm|
assert_match CGI.escapeHTML(dm.content), response.body
end
end
As shown in Listing 13.28, symbols such as "'" were output as special characters, so I searched the net for how to escape and corrected it. https://rakuda3desu.net/rakudas-rails-tutorial14-3/
Make a test for the controller. Read "13.3.1 Micropost Access Control" in the tutorial.
test/controllers/dms_controller_test.rb
test "should redirect index when not logged in" do
get dms_path
assert_redirected_to login_url
end
It's RED. Add access restrictions for the index action to the controller.
app/controllers/dms_controller.rb
class DmsController < ApplicationController
before_action :logged_in_user, only: [:index]
The test is now GREEN.
7.0 hours from 11/7 to 11/14.
Recommended Posts