RailsでRSSリーダーを作るチュートリアルです。
Railsで簡易RSSリーダーを作ってみました。 参考サイトはこれです。
Building an RSS Reader in Rails Is Easy
プロジェクト開始
rails new feedreader
gem
使うgemはfeedjiraです。ゴジラとフィードをあわせたみたいです。
rubygemsを見てみてもrssパーサーで一番人気があるみたいです。
https://www.ruby-toolbox.com/categories/feed_parsing
実際のプロダクトのgemでも使われているみたいです!これは信頼できる。
# Gemfile gem 'feedjira' gem 'twitter-bootstrap-rails'
bootstrap導入
今回見た目をちょっとよくするためにcssフレームワークのbootstrapを使います。
rails generate bootstrap:install static
モデル作成
feedモデルとテーブルを作成します。 これにrssのurlなどを入れていきます。
rails g scaffold feed name url description:text rake db:migrate
rootをfeedのindexにしましょう。
# config/routes.rb root 'feeds#index
更新されていくentryモデルを作成します。 これはfeedに連なる形になりますね。
rails g model entry title published:datetime content:text url author feed_id:integer rake db:migrate
アソシエーションを定義していきます。
## models/feed.rb class Feed < ActiveRecord::Base has_many :entries, dependent: :destroy end ## models/entry.rb class Entry < ActiveRecord::Base belongs_to :feed end
RSSを引っ張ってくるためのrakeタスク
RSSは自分から見に行かないと取得できません。そのため、rakeタスクにして、cronなどで定期的に取得する必要があります。 実際はwheneverとかgemを使って定期的にrakeタスクを、実行してあげればいいと思います。
# lib/tasks/sync.rake namespace :sync do task feeds: [:environment] do Feed.all.each do |feed| content = Feedjira::Feed.fetch_and_parse feed.url content.entries.each do |entry| local_entry = feed.entries.where(title: entry.title).first_or_initialize local_entry.update_attributes(content: entry.content, author: entry.author, url: entry.url, published: entry.published) p "Synced Entry - #{entry.title}" end p "Synced Feed - #{feed.name}" end end end
実行するには
rake sync:feeds
と入力します。
適当なサイトのrssのurlを登録して、タスクを走らせて見て下さい。 配信されている記事数とコンソールの結果が一緒になっていればOKです!
rails c Entry.count
何回もrakeタスク走らせて記事被らないの?
この記事でも言及されているのですが、rssフィードを取得する際に、更新頻度とタイミングによっては、記事がかぶってしまいます。
そこのところの処理どうするの?って思っていましたが、このrakeタスクはfirst_or_initialize
でテーブルに同じ記事があるかどうか探して、なければ作成、あれば呼び出しという処理をしています。そのため記事が重複してレコードが作成されることはないし、記事が更新されていればupdateしてくれます。
こうやって処理を書くんだと参考になりました。
controllerとview
簡易的なviewを作成していきます。
rails g controller entries index show
# config/routes.rb resources :feeds do member do resources :entries, only: [:index, :show] end end
# app/controllers/entries_controller.rb class EntriesController < ApplicationController before_action :set_feed, only: :index def index @entries = @feed.entries.order('published desc') end def show @entry = Entry.find(params[:id]) end private def set_feed @feed = Feed.find(params[:id]) end end
# app/views/entries/index.html.erb <div class="container"> <% @entries.each do |entry| %> <div class="panel panel-default"> <div class="panel-body"> <%= link_to entry.title, entry %> - <i> published <%= time_ago_in_words(entry.published) %> ago.</i> </div> </div> <% end %> </div> # app/views/entries/show.html.erb <div class="container"> <h3><%= link_to @entry.title, @entry.url %></h3> <i>published on <%= @entry.published %> by <%= @entry.author %></i> <p> <%= @entry.content.html_safe %> </p> </div>
アクセスすると下記のように表示されるはずです。
rssの機能自体はかなり簡単に作れますね。