This is a continuation of Creating Extensions in Chapter 14 of the Rails Tutorial.
This time we will create an RSS feed function.
In the tutorial
Implement the ability to RSS feed microposts for each user. Next, implement the ability to RSS feed the status feed, and if you can afford it, try adding an authentication scheme to the feed to restrict access.
The requirements are written.
I've used RSS, but I'm not sure how it works. I will check on the net if there is a person who made it.
There seems to be a builder function that comes standard with feed.rss.builder.
Next is the authentication scheme in the feed, but I understood that it means that you can not follow unless you are logged on. Check online to see if there are any examples.
Check online to see if Twitter is authenticated. Twitter itself does not deliver RSS, and it seems that it is getting RSS from another site. Facebook used to provide RSS as an official function, but it has been discontinued.
Reference: How to get RSS on a certified site http: // username: password @ RSS feed URL
I found that it can be done with a fairly old net article, but it seems that there is a high risk of password leakage if it is described in the URL.
The requirements are summarized from the results of the investigation.
We will reduce the requirements to specific functions.
Ability to output your own post as an RSS feed Accessing xxx/rss in the url returns an RSS file.
Create a topic branch.
ubuntu:~/environment/sample_app (master) $ git checkout -b rss
http://miner.hatenablog.com/entry/2017/07/20/142532 I will refer to.
Add the routing.
config/routes.rb
get :rss, to: 'rss#index', defaults: { format: :rss }
Generate a controller.
ubuntu:~/environment/sample_app (rss) $ rails generate controller Rsss
create app/controllers/rsss_controller.rb
create app/views/rsss
create test/controllers/rsss_controller_test.rb
create app/helpers/rsss_helper.rb
create app/assets/javascripts/rsss.coffee
create app/assets/stylesheets/rsss.scss
Add to the controller by referring to the user's show.
app/controllers/rsss_controller.rb
class RsssController < ApplicationController
layout false
def index
@user = User.find(params[:id])
@microposts = @user.microposts.limit(10)
respond_to do |format|
format.rss
format.atom
end
end
end
Create a view.
Create an app/views/rsss/index.rss.builder file.
app/views/rsss/index.rss.builder
cache 'feed_cache_key', expires_in: 30.minutes do
xml.instruct! :xml, :version => "1.0"
xml.rss :version => "2.0" do
xml.channel do
xml.title "Rails Tutorial sample site"
xml.description "Rails Tutorial sample site"
xml.link root_url
@microposts.each do |b|
xml.item do
xml.title b.title
xml.description strip_tags(b.rich_text_body.to_s.gsub(/\r\n|\r|\n|\s|\t/, "")).truncate(120)
xml.image image_url(url_for(b.image))
xml.pubDate b.time.to_s(:rfc822)
xml.link blog_url(b)
xml.guid blog_url(b)
end
end
end
end
end
https://pgmg-rails.com/blogs/24 I will refer to.
The cloud9 syntax check is no longer colored. I didn't know if it was an extension or not.
ruby:app/views/rsss/index.rss.builder
xml.title b.content
xml.description b.content
xml.image image_url(url_for(b.picture)) if b.picture?
xml.pubDate b.updated_at.to_s(:rfc822)
Let's check if RSS is output.
On the rails server, go to/rss. https://XXXXXXXXXXXXXXX.amazonaws.com/rss
An error was output.
ActionController::RoutingError (uninitialized constant RssController):
Check routes.
buntu:~/environment/sample_app (rss) $ rails routes
Prefix Verb URI Pattern Controller#Action
root GET / static_pages#home
...
rss GET /rss(.:format) rss#index {:format=>:rss}
I wondered if the problem was that the plural form and the file name did not match. The file name static_pages_controller.erb corresponds to static_pages # home in routes. So I thought that the file name rss_controller.erb corresponds to rss # index. If so, routes should be rsss # index, so fix it.
config/routes.rb
get :rss, to: 'rsss#index', defaults: { format: :rss }
A different error was output.
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=):
app/controllers/rsss_controller.rb:5:in `index'
The previous error was resolved and I proceeded to the controller. Because you are not logged in, you do not have a user id.
I tried to log in and then access it, but the same error occurred.
The cause is why the id cannot be obtained from the parameter Since you are not logged in when you get RSS in the first place, refer to user # show.
GET /users/:id(.:format) users#show
It has become. When you access xxx/users/1 with url, 1 is passed for id. I thought it would be good to add /: id to routes, so I'll fix it.
Find out how to write routes on the net. https://www.sejuku.net/blog/13078
config/routes.rb
get 'rss/:id', to: 'rsss#index', defaults: { format: :rss }
ubuntu:~/environment/sample_app (rss) $ rails routes
Prefix Verb URI Pattern Controller#Action
root GET / static_pages#home
GET /rss/:id(.:format) rsss#index {:format=>:rss}
I got a different error.
ActionView::Template::Error (undefined method `blog_url' for #<#<Class:0x000056130c6fb330>:0x000056130c6f9648>
Did you mean? login_url):
I found that the article I referred to as an example does not work as it is. Find out what should be displayed in the link and guid.
xml.link blog_url(b)
xml.guid blog_url(b)
The article I referred to was an example of a blog, and I specified the URL of each article. Correspondingly, there is no URL for each micropost, so I will give the URL of the user. The difference between path and URL was ambiguous, so I checked it online. https://qiita.com/higeaaa/items/df8feaa5b6f12e13fb6f
ruby:app/views/rsss/index.rss.builder
xml.link user_url(b.user)
xml.guid user_url(b.user)
When I modified it and accessed the url, a dialog to open or save was displayed.
When I opened the saved file with Notepad, xml was output.
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Rails Tutorial sample site</title>
<description>Rails Tutorial sample site</description>
<link>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/</link>
<item>
<title>@Elvis1 reply test</title>
<description>@Elvis1 reply test</description>
<pubDate>Wed, 11 Nov 2020 23:27:05 +0000</pubDate>
<link>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</link>
<guid>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</guid>
</item>
<item>
<title>Est et placeat voluptates et alias.</title>
<description>Est et placeat voluptates et alias.</description>
<pubDate>Wed, 11 Nov 2020 23:27:04 +0000</pubDate>
<link>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</link>
<guid>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</guid>
</item>
..
<item>
<title>Sint porro molestiae corporis quidem eligendi.</title>
<description>Sint porro molestiae corporis quidem eligendi.</description>
<pubDate>Wed, 11 Nov 2020 23:27:03 +0000</pubDate>
<link>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</link>
<guid>https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com/users/1</guid>
</item>
</channel>
</rss>
I tried adding this URL to Feedly, but it wasn't recognized as RSS.
We were not able to find an RSS feed for https://xxxxxxx.amazonaws.com/rss/1.
Please contact the website and ask them if they offer a valid RSS feed.
I searched online to see if it was an RSS problem, but I wasn't sure.
https://qiita.com/amymd/items/bb4a9e008af061c89ea9
https://pgmg-rails.com/blogs/24 Let's change how to write the controller with reference to.
app/controllers/rsss_controller.rb
respond_to do |format|
format.html
format.rss { render :layout => false }
end
The behavior of the file open dialog did not change. I looked it up on the net, but I didn't understand it, so I'll leave it as it is.
Now that I'm outputting what I posted, I'll change the status feed, that is, the post that includes the people I follow, to the ability to output as an RSS feed.
Refer to the place where the status feed is displayed on the screen. Since it was the home screen, I will add a static_pages controller.
app/controllers/static_pages_controller.rb
@feed_items = current_user.feed.paginate(page: params[:page])
And you can see that you can output it with the feed method. When I tried it on the console, it did return a micropost. Change the controller.
app/controllers/rsss_controller.rb
class RsssController < ApplicationController
def index
@user = User.find(params[:id])
@microposts = @user.feed.limit(10)
respond_to do |format|
format.html
format.rss { render :layout => false }
end
end
end
Let's run it on rails server. A file will be output, so check the contents.
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Rails Tutorial sample site</title>
<description>Rails Tutorial sample site</description>
<link>https://https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com.amazonaws.com/</link>
<item>
<title>@Elvis1 reply test</title>
<description>@Elvis1 reply test</description>
<pubDate>Wed, 11 Nov 2020 23:27:05 +0000</pubDate>
<link>https://https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com.amazonaws.com/users/1</link>
<guid>https://https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com.amazonaws.com/users/1</guid>
</item>
<item>
<title>Est et placeat voluptates et alias.</title>
<description>Est et placeat voluptates et alias.</description>
<pubDate>Wed, 11 Nov 2020 23:27:04 +0000</pubDate>
<link>https://https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com.amazonaws.com/users/6</link>
<guid>https://https://xxxxxxxxxxxxxxxxxxxxx.amazonaws.com.amazonaws.com/users/6</guid>
</item>
</channel>
</rss>
When I compared it with the home screen, the second post was posted by another user and matched.
It turns out that RSS doesn't tell who posted the micropost. I will leave it as it is this time and leave it as an improvement point in the future.
Now that it works, I'll write a test. I didn't know how to handle the RSS output result, so I searched online but couldn't find it. So I will write it in the same way as the screen.
test/integration/rss_test.rb
require 'test_helper'
class RssTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "rss show" do
get rss_path(@user)
assert_template 'rsss/index'
end
end
I got an error.
NoMethodError: NoMethodError: undefined method `rss_path' for #<RssTest:0x000055fc3d47d0f8>
ubuntu:~/environment/sample_app (rss) $ rails routes
Prefix Verb URI Pattern Controller#Action
new_dm GET /dms/new(.:format) dms#new
dm DELETE /dms/:id(.:format) dms#destroy
GET /rss/:id(.:format) rsss#index {:format=>:rss}
In the routing of rss_path, there is no name in Prefix and there is no space, so let's give it a name. https://www.sejuku.net/blog/13078 I will refer to.
config/routes.rb
get 'rss/:id', to: 'rsss#index', as: 'rss', defaults: { format: :rss }
ubuntu:~/environment/sample_app (rss) $ rails routes
Prefix Verb URI Pattern Controller#Action
dm DELETE /dms/:id(.:format) dms#destroy
rss GET /rss/:id(.:format) rsss#index {:format=>:rss}
It became GREEN.
Add to check if the content is displayed with assert_match. When I ran the test, it was GREEN. This completes it.
test/integration/rss_test.rb
test "rss show" do
get rss_path(@user)
assert_template 'rsss/index'
@user.feed.limit(10).each do |micropost|
assert_match micropost.content, response.body
end
end
I will upload it to heroku as usual.
ubuntu:~/environment/sample_app (rss) $ git add -A
ubuntu:~/environment/sample_app (rss) $ git commit -m "Add RSS"
ubuntu:~/environment/sample_app (rss) $ git checkout master
ubuntu:~/environment/sample_app (master) $ git merge rss
ubuntu:~/environment/sample_app (master) $ git push
ubuntu:~/environment/sample_app (master) $ git push heroku
I tried to access the RSS URL on Heroku. The behavior of the file open dialog was unchanged.
It is 8.0 hours of 13 working days from 12/21 to 1/11. It took me a while to look it up online. It takes less than half the time to write and test.
http://miner.hatenablog.com/entry/2017/07/20/142532
https://pgmg-rails.com/blogs/24
https://qiita.com/klriutsa/items/6662ef75e804c4323228
https://madogiwa0124.hatenablog.com/entry/2019/02/24/234610
http://maepachi.com/entries/94
Recommended Posts