#はじめに
Mastodonインスタンスの一つ、Creatodonを普段は運営しています。
メインのユーザー層としては創作活動をされている方々で、絵を描かれる人や物書きが使われていますねー(かくいう私もフリーゲーム作ってます)
去年の五月に、さくらのクラウドを使ってインスタンスを建てました。
が、メディアストレージを結構使ってて辛かったり(Pawooとかと繋がっている為)、
一回ストレージ関連でインスタンスが正常に動作しなかったこともあり(cronでのキャッシュの削除が上手くいっていなかった)
そういうこともありCreatodon Folioという画像投稿サービスを作りました。
基本的には、インスタンスのユーザーが絵や漫画を気軽に投稿できる場所として公開していますねー。
まあ、Creatodon Folio 作った後に AWS S3 へメディアストレージを移したので作った意味があったかといわれると……。
まあ、いろいろとRailsの勉強になったのでOKだと思ってます。
今回の記事では、実際に「Mastodonでログインする機能」を実装するところを解説していきます。
#実際に作ったもの
で、実際に作ったものはこちらになります。
ちなみに、ソースコードはこちら
Railsの教科書を参考にさせていただきながら制作させて頂きました。
環境としては Heroku + AWS S3 を使って構築しています。
そのため、Heroku dyno の再起動の影響もなく画像を表示できていますねー。
おまけに AWS を使っているのでコストもはるかに安く済んでいます。
あと、今回の記事用に「Mastoonでのログインする機能」のみを実装したサンプルを作っておきました。
本記事のみで、分かりにくいようでしたらそちらを参照されると良いかと思います。
#作る手順
##制作環境
OS:Windows 10 Pro
Ruby: 2.3.3
Rails : 5.1.4
上記の環境にてサンプルを制作しました。
ですので、対象はWindowsユーザーになります。ご了承くださいませ。
また既にHerokuアカウントを持っているものとして話を進めていきます。
アカウントを持っていない方はこちらの記事を参考にされると良いと思います。
なお、このほかHeoku CLI
を使う場面もありますのでこちらより実行ファイルをダウンロードしてインストールしておいてください。
##Herokuでの下準備
まず、コマンドプロンプト又はPowerShell
を起動し、以下のコマンドを実行して Heroku 上にアプリケーションを作成します。
heroku apps:create -a <アプリ名>
これで、Heroku での下準備は終了
##Mastodonでの下準備
自分のアカウントがあるMastoonインスタンスにて
「ユーザー設定」をクリックし、「開発」という項目をクリックします。
「新規アプリ」をクリックし、「アプリ名」を入力の上「送信」をクリックします。
その後、作成したアプリをクリックすると「クライアントキー」と「シークレットキー」を取得できます。
この二つは後々で使いますのでわかるようにメモしておきます(ただし、第三者とは絶対に共有しないでください!)
Mastoonでの下準備はこれで終了です。
##Railsでの実装
###Railsアプリケーションのひな型作成
それでは、いよいよRailsでの実装といきましょう。
まず、コマンドプロンプト又はPowerShell
を起動し、以下のコマンドを実行して アプリケーションを作成します。
rails new <アプリ名>`
その後、下記のコマンドでディレクトリを移動します。
cd <アプリ名>
それから、以下のコマンドを実行。
rails g controller MastodonLogin index
今回はログインする機能とログインできたかが確認できればいいので、view に関してはindex
のみを作ります。
index.html.erb
が作成された後、config/routes.rb
に root_path
を設定します
root 'mastodon_login#index'
次に、Gemfile を編集します。
まず、以下のように必要なgemを追記します
gem 'coffee-script-source', '1.8.0'
gem 'devise'
gem 'mastodon-api', require: 'mastodon'
gem 'omniauth-mastodon'
gem 'omniauth'
その後、sqlite3
を下記のように開発環境でしか利用しないように設定します。
group :development do
gem 'sqlite3'
end
また本番環境用に以下のように記述を追記しておきます。
group :production do
gem 'pg'
end
Gemfile の編集が終わったら、bundle update
bundle install
の順にコマンドを実行してください。
Devise のインストール
今回のログイン機能を実装するにあたってDevise とよばれる gem を使用します。
詳しいことはこちらに書いてあるので参照してください。
以下のコマンドを実行してDviseをインストールします。
rails g devise:install
rails g devise:views
rails g devise user
上記のコマンドをサラッと説明すると
rails g devise:install
は Devise のインストール。
rails g devise:views
は Devise 用の view の作成
rails g devise user
は Devise で使用するmodelの作成
となっています。
その後、rails db:migrate
を実行し、DBに適用します。
Mastodonアカウントでのログイン機能の実装
まず、今のままではUserモデルの中にMastodonでのidなどを記憶できないので
rails g migration AddColumnsToUsers uid:string provider:string
上記のコマンドを実行してカラムを追加します。
次に、Mastodonのドメイン情報などを記憶するモデル:MastodonClient を以下のコマンドで作成します。
rails generate model MastodonClient domain:string client_id:string client_secret:string
次に、config/initializers/devise.rb
に先ほど取得したアクセスキーなどを記述していきます。
実際の記述例としては以下のようになります。
Devise.setup do |config|
#(中略)
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :mastodon, 'ACCESS_KEY', 'SECRET_KEY'
config.omniauth :mastodon, scope: 'read follow', credentials: lambda { |domain, callback_url|
client = MastodonClient.where(domain: domain).first_or_initialize(domain: domain)
return [client.client_id, client.client_secret] unless client.new_record?
new_client = Mastodon::REST::Client.new(base_url: "https://#{domain}").create_app('MastodonLoginSample', callback_url, 'read follow')
client.client_id = new_client.client_id
client.client_secret = new_client.client_secret
client.save
[client.client_id, client.client_secret]
}
#(中略)
end
で、'ACCESS_KEY', 'SECRET_KEY' に先ほど取得したクライアントキーなどを記述します(本当はdotenvあたりを使って実際のソースコードに記述しない方が良い)
お次は、app/controllers/users/omniauth_callbacks_controller.rb
を作成して以下のように記述します。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def mastodon
callback_from :mastodon
end
private
def callback_from(provider)
provider = provider.to_s
@user = User.find_for_oauth(request.env['omniauth.auth'])
if @user.persisted?
flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
sign_in_and_redirect @user, event: :authentication
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end
このコードがないと、Mastodonで認証した後にWebアプリまで戻ってくることができませんので注意。あと、Userデータなども保存されません。
そして、models/user.rb
に以下のように:omniauthable
を追記します。
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
そして、ログイン時に既にアカウントデータが作成されているかを判断するfindメソッドを記述します。
その為、最終的には以下のようになっています。
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
def self.find_for_oauth(auth)
user = User.where(uid: auth.uid, provider: auth.provider).first
unless user
user = User.create(
uid: auth.uid,
provider: auth.provider,
email: User.dummy_email(auth),
password: Devise.friendly_token[0, 20]
)
user.save!
end
current_user = user
end
private
def self.dummy_email(auth)
"#{auth.uid}"
end
end
そして、config/routes.rb
に
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
を設定します。
下記のようになっていればOKです。
Rails.application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
root 'mastodon_login#index'
end
あとは、index.html.erb
を以下のように記述してログイン用のリンクとログインした後に表示される文字を設定します。
<h1>MastodonLogin#index</h1>
<p>Find me in app/views/mastodon_login/index.html.erb</p>
<%= link_to "Log In for Mastodon Account", user_mastodon_omniauth_authorize_path %>
<br>
<% if user_signed_in? %>
Your Welcome !
<% end %>
ログインされていると、「Your Welcome !」 という文章が表示されるようになっています。
これで、とりあえずは「Mastodonでログインする機能」は実装されました。
##Herokuへのデプロイ
それでは、最後に実際の本番環境で試してみましょう。
まず、Heroku 上のアプリケーションのリポジトリとローカルにあるRailsのリポジトリを以下のコマンドで繋げます。
heroku git:remote -a <アプリ名>
で、次に以下のコマンドでHeroku上のリポジトリにpushします。
git add .
git commit -am "mastodon login test"
git push heroku master
そして、最後に以下のコマンドを実行してやれば、「Mastodonでログイン」できるようになります。
heroku run rails db:migrate -a <アプリ名>
あとは、以下のコマンドで実際のWebサプリを開いて
heroku run app:open -a <アプリ名>
「Log In for Mastodon Account」をクリックして、実際に使っているMastodonアカウントを入力するだけ
#さいごに
とりあえず、今までの手順でRailsのWebアプリケーションで「Masotodonでログインする機能」を使えるようになります。
正月休み中ずっと実装のために格闘していたので、ようやくのんびりできそうです。
#参考文献
RailsなサービスでMastodonとのOauth連携を実装する
またMastodonでのログイン機能実装にあたっては kenchiki 氏からアドバイスなどをいただきました。
この場を借りて感謝申し上げます。