diff --git a/app/controllers/feed_controller.rb b/app/controllers/feed_controller.rb new file mode 100644 index 00000000..e7a28ecc --- /dev/null +++ b/app/controllers/feed_controller.rb @@ -0,0 +1,14 @@ +class FeedController < ApplicationController + skip_before_action :authenticate_user! + + # GET /feed.rss + # GET /feed.atom + def index + @talks = Talk.all.order(created_at: :desc).includes(:speakers).limit(100) + + respond_to do |format| + format.rss { render layout: false } + format.atom { render layout: false } + end + end +end diff --git a/app/views/feed/index.atom.builder b/app/views/feed/index.atom.builder new file mode 100644 index 00000000..7fde818b --- /dev/null +++ b/app/views/feed/index.atom.builder @@ -0,0 +1,16 @@ +atom_feed do |feed| + feed.title("Ruby Videos") + feed.updated(@talks.first.updated_at) + + @talks.each do |talk| + feed.entry(talk) do |entry| + entry.title(talk.title) + entry.summary(talk.description) if talk.description.present? + entry.link(href: talk_url(talk.slug)) + entry.author do |author| + author_names = talk.speakers.pluck(:name).join(", ") + author.name(author_names.present? ? author_names : "Unknown") + end + end + end +end diff --git a/app/views/feed/index.rss.builder b/app/views/feed/index.rss.builder new file mode 100644 index 00000000..e5e3ef3e --- /dev/null +++ b/app/views/feed/index.rss.builder @@ -0,0 +1,18 @@ +xml.instruct! :xml, version: "1.0" +xml.rss version: "2.0" do + xml.channel do + xml.title "Ruby Videos" + xml.description "A collection of talks of Ruby conferences around the world" + xml.link root_url + + @talks.each do |talk| + xml.item do + xml.title talk.title + xml.description talk.description + xml.pubDate DateTime.parse(talk.date.to_s).rfc822 + xml.link talk_url(talk.slug) + xml.guid talk_url(talk.slug) + end + end + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index b27d3578..c7dac1c8 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -10,6 +10,10 @@ <%= vite_client_tag %> <%= vite_javascript_tag "application" %> <%= vite_stylesheet_tag "application.css" %> + + <%= auto_discovery_link_tag :rss, feed_url(format: :rss) %> + <%= auto_discovery_link_tag :atom, feed_url(format: :atom) %> + <%= yield :head %> diff --git a/config/routes.rb b/config/routes.rb index 721a7fab..387fcaf7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,9 @@ get "sign_up", to: "registrations#new" post "sign_up", to: "registrations#create" + # rss feed + get "feed", to: "feed#index" + resources :sessions, only: [:index, :show, :destroy] resource :password, only: [:edit, :update] namespace :identity do diff --git a/test/controllers/feed_controller_test.rb b/test/controllers/feed_controller_test.rb new file mode 100644 index 00000000..72e17547 --- /dev/null +++ b/test/controllers/feed_controller_test.rb @@ -0,0 +1,29 @@ +require "test_helper" + +class FeedControllerTest < ActionDispatch::IntegrationTest + setup do + @talks = talks(:one, :two) + frozen_date_time = DateTime.new(2022, 1, 15, 10, 0, 0) + @talks.each do |talk| + talk.update!(created_at: frozen_date_time, updated_at: frozen_date_time) + end + end + + test "should get rss format" do + get feed_url(format: :rss) + + assert_response :success + assert_equal "/feed.rss", path + assert_equal "application/rss+xml; charset=utf-8", response.content_type + assert_equal File.read("test/fixtures/files/feed.rss"), response.parsed_body + end + + test "should get atom format" do + get feed_url(format: :atom) + + assert_response :success + assert_equal "/feed.atom", path + assert_equal "application/atom+xml; charset=utf-8", response.content_type + assert_equal File.read("test/fixtures/files/feed.atom"), response.parsed_body + end +end diff --git a/test/fixtures/files/feed.atom b/test/fixtures/files/feed.atom new file mode 100644 index 00000000..15230e64 --- /dev/null +++ b/test/fixtures/files/feed.atom @@ -0,0 +1,32 @@ + + + tag:www.example.com,2005:/feed + + + Ruby Videos + 2022-01-15T10:00:00Z + + tag:www.example.com,2005:Talk/298486374 + 2022-01-15T10:00:00Z + 2022-01-15T10:00:00Z + + talk title 2 + talk descritpion 2 + + + Obie Fernandez + + + + tag:www.example.com,2005:Talk/980190962 + 2022-01-15T10:00:00Z + 2022-01-15T10:00:00Z + + talk title 1 + talk descritpion 1 + + + Obie Fernandez + + + diff --git a/test/fixtures/files/feed.rss b/test/fixtures/files/feed.rss new file mode 100644 index 00000000..4f8c7c40 --- /dev/null +++ b/test/fixtures/files/feed.rss @@ -0,0 +1,22 @@ + + + + Ruby Videos + A collection of talks of Ruby conferences around the world + http://www.example.com/ + + talk title 2 + talk descritpion 2 + Sat, 1 Jan 2022 00:00:00 +0000 + http://www.example.com/talks/talk-title-2 + http://www.example.com/talks/talk-title-2 + + + talk title 1 + talk descritpion 1 + Sat, 1 Jan 2022 00:00:00 +0000 + http://www.example.com/talks/talk-title-1 + http://www.example.com/talks/talk-title-1 + + + diff --git a/test/fixtures/talks.yml b/test/fixtures/talks.yml index 9a0b59f1..f69b9633 100644 --- a/test/fixtures/talks.yml +++ b/test/fixtures/talks.yml @@ -24,9 +24,13 @@ one: description: talk descritpion 1 slug: talk-title-1 year: 2022 + speakers: one + date: 2022-01-01 two: title: talk title 2 description: talk descritpion 2 slug: talk-title-2 year: 2022 + speakers: one + date: 2022-01-01