Madogiwa Blog

主に技術系の学習メモに使っていきます。

railsとruby標準ライブラリで作るRSSリーダー的なやつの作り方Memo📝

はじめに

みなさん、こんばんは。まどぎわです(・∀・)
rubyの標準ライブラリにRSS用のライブラリがあることを最近知り、railsと標準ライブラリを使ってRSSリーダー的なものを作ってみたので、作り方とかをメモしておきます✍

作るもの

はてなブログRSSフィードのエンドポイントを登録したら、そこからRSSをパースして表示出来るようなアプリを作っていきます👀

こんな感じのものをイメージしてもらえれば! f:id:madogiwa0124:20190203232035g:plain

使うもの

作り方

モデルを作る

とりあえずモデルを作ります。作るものを下記の2つです。

  • Feed.rb
  • Entry.rb

Feed.rbにはRSSフィードのタイトルとエンドポイントのURLを登録します。Entry.rbには、フィードから取得したエントリーを登録します。

schemeはこんな感じです。

  create_table "entries", force: :cascade do |t|
    t.bigint "feed_id"
    t.string "title"
    t.string "link"
    t.text "description"
    t.datetime "published_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["feed_id"], name: "index_entries_on_feed_id"
  end

  create_table "feeds", force: :cascade do |t|
    t.string "title", null: false
    t.string "endpoint", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

RSSを読み込んでParseする

それでは、RSSを読み込んでパースする部分は結構簡単で、ruby標準のrssライブラリをrequire 'rss'で読み、Net::HTTP.get(URI.parse(endpoint))xmlドキュメントを取得して、RSS::Parser.parseを使ってParseします。
私は、Feedモデルにparsed_xmlを定義してParseしたxmlを取得出来るようにしてみました👀

class Feed < ApplicationRecord
  require 'rss'

  has_many :entries

  def parsed_xml
    xml = Net::HTTP.get(URI.parse(endpoint))
    RSS::Parser.parse(xml)
  end
end

エントリーを取得して保存する

その後は、Parseしたxmlitemsに記事の一覧が入っているので、下記のようなEntryCreaterクラスを作成して、画面登録時に記事一覧を取得して登録するようにしました🙌

class FeedsController < ApplicationController
  def new
    @feed = Feed.new
  end

  def create
    @feed = Feed.new(feed_params)
    if @feed.save
      Feed::EntryCreater.new(@feed).execute
      redirect_to feed_path(@feed)
    else
      render :new
    end
  end

  private

  def feed_params
    params.require(:feed).permit(:title, :endpoint)
  end
end
class Feed::EntryCreater
  attr_reader :feed

  def initialize(feed)
    @feed = feed
  end

  def execute
    Entry.where(feed: feed).delete_all
    feed.parsed_xml.items.map do |item|
      Entry.create(
        feed: feed,
        title: item.title,
        description: strip_tags(item.description).truncate(300),
        published_at: item.pubDate,
        link: item.link
      )
    end
  end

  private

  def strip_tags(text)
    ActionController::Base.helpers.strip_tags text
  end
end

保存したエントリーを表示する

保存したエントリーを表示するのは普通に表示してあげればOKです🙆‍♂️

class FeedsController < ApplicationController
  def show
    @feed = Feed.includes(:entries).find(params[:id])
  end
end
<div class="feed-show">
  <h1 class="title"><%= @feed.title %></h1>
  <div class="entries">
    <%= render partial: 'entry_collection', collection: @feed.entries, as: 'entry' %>
  </div>
</div>
<div class="card">
  <header class="card-header">
    <p class="card-header-title"><%= entry.title %></p>
  </header>
  <div class="card-content">
    <div class="content">
      <%= entry.description %>
      <%= link_to 'サイトで読む', entry.link %>
    </div>
  </div>
  <footer class="card-footer">
    <p class="card-footer-item">
      <%= link_to entry.feed.title, feed_path(entry.feed) %>
    </p>
    <p class="card-footer-item">
      公開日: <%= l(entry.published_at, format: :long) %>
    </p>
  </footer>
</div>

おわりに

rubyの標準ライブラリを使うとRSSを簡単にParseしてRSSリーダー的なものがすぐ作れるんですねー。
他にも標準ライブラリは結構あるので、いろいろ見てみようかと思いました🙇‍♂️

参考

docs.ruby-lang.org

www.buildinsider.net