とある神戸大生の走り書き

主にプログラミングに関して、学んだことを走り書きとして残していきます。

Herokuで公開しているサービスに独自ドメインをサブドメインなしで設定する(ムームードメインの場合)

railsで作成したアプリケーションをHerokuを使って公開する時に、ムームードメインで取得したドメインサブドメインなしで設定しようとしたのですが、ムームードメインを使ってやっている記事が見つからなかったので簡単にまとめておきます。

Heroku側の設定

⑴まず、Herokuのダッシュボードからドメインを設定したいアプリケーションのSettings画面に行く。

⑵ Settings画面で少しスクロールすると、Domains and certificatesみたいな欄があるので、 そこでAdd Domainをクリックして、出てきたフォームに自分が設定したいドメインを入力する。

(例)example.comみたいにhttps://無しで記述する。

⑶ そうしたらsave changesする。

⑷すると下の方の Domain Nameのところに先ほど追加したドメインが表示されているはずです。 ドメインが追加されていることが確認できたら、Domain Nameの右にあるDNS Targetをコピーします。

DNS Targetは、[ランダムな文字列].herokudns.comみたいになってるはず。

ムームードメイン側の設定

ムームードメインのコントロールパネルに行きます。

すると、左側のサイドバーの一番上にドメイン操作とあるはずなのでそれをクリックして、

ムームDNSををクリックします。

この時点で、自分が取得しているドメインの一覧が出てくるはずです。(出てこない場合はページに記載されている指示通りに進めると表示されるようになります。)

⑶その後、設定したいドメインの処理の欄にある変更ボタンをクリックする。

すると、「カスタム設定のセットアップ情報変更」と書かれたページに行くので、そのページの設定2のサブドメインを空、種別をALIAS、内容に先ほどコピーしたDNS Targetをペーストします。優先度も空にして、

⑷セットアップ情報変更をクリックしたらこれで全ての設定が終了です!

僕の場合は、その後2分ほどでHerokuにドメインが反映されて、接続できるようになりました。 人によって違うようなので、少し待ってみて反映されてないようであれば、もう一度設定を見直してみてください。

面倒な検索作業を他の人に手伝ってもらえるサービス「Linch(リンク)」をリリースした

「助け合って検索する」をテーマにしたサービス「Linch(リンク)」のβ版をリリースしました!

もし良かったら、拡散していただけたら嬉しいです!

リリースしたサービス

Linch(リンク) - 助け合って検索しよう!

追記 2月22日

ご要望をいただいたので、Twitterアカウントでのログインを実装しました! もしよければ、Linchで情報収集してみてください!

サービスの概要

「Linch(リンク)」は、自分の知りたいことについて投稿すると、他のユーザーから関連するサイトのURLを教えてもらえるサービスです。 あるタスクに取り組んでいる時に、次のタスクで必要な情報を事前に手に入れておくなど、検索時間を短縮することに貢献できればと思っています。

参考:Linch(リンク)とは - Linch

トップページ

スクリーンショット 2019-02-19 12.17.15.png

どこがリンクでどこがボタンとなっているかなど、できる限り見やすさを意識したデザインになるように心がけました。

投稿ページ

スクリーンショット 2019-02-19 3.40.34.png

投稿するのは、知りたい情報に関するタイトル・タグ・概要のみです。少しでも画面遷移を少なくするためにポップアップで投稿できるようにしました。

記事表示ページ

スクリーンショット 2019-02-18 20.57.02.png ページ上部には、記事のタイトル・タグ・本文がページトップに表示されています。また、ページ下部には、記事に対して他のユーザーから投稿されたリンクの一覧を表示しています。

ユーザーページ

スクリーンショット 2019-02-19 12.17.30.png

ユーザーが書いた記事に投稿されたリンクの合計いいね数・ストック数と記事の一覧が表示されています。

使用した技術

また、ムームードメインドメインを取得したのですが、ムームードメインで取得したドメインをHerokuで公開しているサービスにルートドメインとして設定する方法に関する情報があまり見つからなかったので、あとで記事を書いて追記したいと思います。

追記:記事を書きました。 Herokuで公開しているサービスに独自ドメインをサブドメインなしで設定する(ムームードメインの場合)

費用面

現在幸運にも大学生という身分なので、GitHub Student Developer Packを利用することができます。 学生の方は下記のリンクから受け取ることができます。 GitHub Student Developer Pack

GitHub Student Developer Packの特典の一つとして、下記のようにHerokuのHobbyプラン二年分($168分)が無料で使えるようです。

Heroku : One free Hobby Dyno for up to two years (valued at $84/year).

そのため、現在は、Herokuに対する費用は一切かかっていません。 また、Amazon S3に関しても無料枠内で収まると思われるので、一年間はドメインの取得料のみが費用になりそうです。

Linchの特徴

非ログインでもリンクの投稿といいねができる

twitterなどSNSに記事を投稿してURLを募集することを考えて、非ログインでもリンクを投稿したり、いいねができるようにしました。 ただし、リンクを募集するにはログインが必要です。

いいねが連打可能

好きなだけいいねが押せたほうが面白そうなので、いいねを連打することができるようにしました。 いいねボタン連打するだけでもいいので使ってみてください! いいねボタンを連打しにいく - Linch

とにかくシンプル

欲しい情報が素早く手に入る状態を目指したかったので、情報を「リンク(URL)」として集めるというシンプルな設計にしました。

リリースしてみての感想

やってみることの大切さ

ある程度の技術を身につけたら取り敢えず、何か作ってみることの大切さを改めて実感しました。例えリリースまで行うことができなくとも、コードと格闘して実装することを繰り返していると知らぬ間に技術は身についていくと感じました。

不安な気持ち

Linchの大部分を開発し終わった時に、あまりsearch engineとの差別化ができてないように思いましたが、完成させてみることが大切だと思ったので、一旦その考えは心の奥底にしまいました。 また、大学では、情報系の学科に通っているわけではないもあって、サービスのフィードバックなどを受け取る機会が非常に少なかったです。これからいろんな方にフィードバックをもらえる機会を増やしていきたいです。

デザインの難しさ

やはり、デザインは非常に難しいです。デザインに凝りすぎると沼にハマりそうだったので、諦めの気持ちも大切だと思いました。cssも勉強したいと思います。

最後に

プログラミングを始めてから八ヶ月という段階でついに自分が作りたいものを形にする段階まで来ることができました。 これからも触れていきたい技術がたくさんありますが、自分が習得したことを臆病にならずにアウトプットしていこうと思います。

現状、自分ひとりで投稿を続けている状態なので、一人目のユーザーお待ちしています! また、バグ・デザインの乱れがあれば、教えていただければありがたいです。

Linch(リンク) - 助け合って検索しよう!

もしよろしければ、いいねボタンを押していただけたら嬉しいです!

ご覧いただきありがとうございました!

追記

①自動更新されるウィークリーいいねランキングに載せていただきました。 https://qiita.com/takeharu/items/bb154a4bc198fb102ff3#_reference-1eb95e9a3ff1e12b75d1

②多くの人にご覧いただけて非常に嬉しいです!もしよろしければ、何か投稿を残していただけれるとさらに嬉しいです!

③2/20 16:10頃からLinchを訪れてもエラーが表示されてしまっていましたが、16:25には復旧しました。

Railsでoauth access tokenなどを暗号化した

目的

  • Railsで外部アプリケーションでのログインなどを導入するときに取得するoauth access tokenなどを暗号化する。

方法

  • gemなど、色々な暗号の方法がある。
  • 結果的に今回は、Rails5.2から導入されたEncrypted Credentialsを利用することにした。

実際やってみる

以下のコマンドを叩く

$ EDITOR=vim bin/rails credentials:edit

EDITORの部分でエディターを指定できるらしいけど、環境変数:EDITORを設定しておかないといけないので、今回はvimで行う。

vimが開いて、下記のようになる。

# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.

secret_key_base: #######################

vimのコマンドをよく忘れるので、下記のURLを貼っておきます。 qiita.com


vimで編集したら、:wq入力して保存。 保存したら、

  • config/credentials.yml.enc
  • config/master.key

が生成される。

この時、master.keyにあるのは暗号化の鍵なので.gitignoreに追加されるようになってる。※

値の取り出し方

secret.yml

hoge: 123

fuga: 
 fuga_id: 345

上記のようになっている場合は、下記のように値を取り出せる。

Rails.application.credentials.hoge # => "123"
Rails.application.credentials.fuga[:fuga_id] # => 345

※何故かmaster.keyがレポジトリに表示されていた

今回、上記のように暗号化をしてみたが、なぜかmaster.keyがレポジトリに上がってしまっていた。 これでは、暗号化の意味がないので、自分で.gitignoreしないといけない。

そんな時は、下記のようにしてから、commitしてpushしたらファイルがGIthub上に表示されなくなる。

$ git rm -r --cached config/master.key

参考

qiita.com

Railsでbundle installしたらnokogiriでエラー出る現象

bundle installしたらnokogiriのインストール中にエラー出た

bundle installすると、途中で下記のようなエラーが出る。

Fetching nokogiri 1.10.1
Installing nokogiri 1.10.1 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

ググってみたら、色々出てきたけど、最終的に公式ページ見るのが一番良いみたい。

nokogiri.org

Macで、公式ページ通りの手順通りに進めていくと、下記のようになる。

gem update --system
xcode-select --install # Then agree to the terms, even if you have done this before!

gemが最新のバージョンかどうか確認して、

gem install nokogiri

これでもう一度bundle installしたらうまくいった!

Railsで複数の外部アプリケーションによるログイン機能を実装する。

外部アプリケーションのアカウントを使ったログイン機能を実装することがあったので、振り返りとしてまとめることにしました。

目的

TwitterGithubなどのアカウントでログインできるような機能の実装を行う。

前提

devise gemによってログイン機能を実装していること。

実装方法 

gemのインストール

下記を追記して、bundle installを実装する。

Gemfile

gem 'omniauth'

gem 'omniauth-facebook'

gem 'omniauth-github'

gem 'omniauth-google-oauth2'

gem 'omniauth-linkedin'

gem 'omniauth-mixi'

gem 'omniauth-twitter'

oauth申請

それぞれのアプリケーションでoauthの申請をしましょう!

「{外部アプリケーションの名前} oauth 申請」と検索したら大体分かると思います。

oauth申請でcallback用のURLが必要な場合は、とりあえず、

https://localhost:3000/user/auth/[provider]/callback

としましょう。

一例として、githubでは下記のリンクから申請できます。

github.com

この申請をすることで、AccessKeyとAccessSecretが得られます。

AccessKeyとAccessSecretをアプリ上に追記

下記のように、それぞれのアプリケーションで得られたAccessKeyとAccessSecretをomniauth.ymlに入れる。

config/omniauth.yml

production: &production
  facebook:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  github:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  google:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  hatena:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  linkedin:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  mixi:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  twitter:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX

development: &development
  <<: *production
  facebook:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  github:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX
  mixi:
    key: xxxxxxxxxxx
    secret: XXXXXXXXXXXXXXXXXXXXXXXXX

test:
  <<: *development

developmentとproductionで分かれているアプリケーションがあるのは、 申請の際にcallback用のURLを一緒に登録しなければならないために、開発環境と本番環境でそれぞれoauthの申請をしなければならないからです。

(開発環境では、「http://localhost:3000/」で本番環境では、「https://hoge.com/」みたいな感じ)

これらkeyやsecretは、本番環境では暗号化しなければなりません。 暗号化の方法については、下記を参考にすると分かりやすいと思います。

qiita.com

受け取る情報の設定

下記のようにします。

devise.rb

OAUTH_CONFIG = YAML.load_file("#{Rails.root}/config/omniauth.yml")[Rails.env].symbolize_keys!

  # https://github.com/mkdynamic/omniauth-facebook
  # https://developers.facebook.com/docs/concepts/login/
  config.omniauth :facebook, OAUTH_CONFIG[:facebook]['key'], OAUTH_CONFIG[:facebook]['secret'], scope: 'email,publish_stream,user_birthday'

  # https://github.com/intridea/omniauth-github
  # http://developer.github.com/v3/oauth/
  # http://developer.github.com/v3/oauth/#scopes
  config.omniauth :github, OAUTH_CONFIG[:github]['key'], OAUTH_CONFIG[:github]['secret'], scope: 'user,public_repo'

  # https://github.com/zquestz/omniauth-google-oauth2
  # https://developers.google.com/accounts/docs/OAuth2
  # https://developers.google.com/+/api/oauth
  config.omniauth :google_oauth2, 
OAUTH_CONFIG[:google]['key'], OAUTH_CONFIG[:google]['secret'], scope: 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.me https://www.google.com/m8/feeds', name: :google

  # https://github.com/mururu/omniauth-hatena
  # http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth
  config.omniauth :hatena, OAUTH_CONFIG[:hatena]['key'], OAUTH_CONFIG[:hatena]['secret']

  # https://github.com/skorks/omniauth-linkedin
  # https://developer.linkedin.com/documents/authentication
  # https://developer.linkedin.com/documents/profile-fields
  config.omniauth :linkedin, OAUTH_CONFIG[:linkedin]['key'], OAUTH_CONFIG[:linkedin]['secret'], scope: 'r_basicprofile r_emailaddress r_network',
    fields: [
      "id", "first-name", "last-name", "formatted-name", "headline", "location", "industry", "summary", "specialties", "positions", "picture-url", "public-profile-url", # in r_basicprofile
      "email-address",  # in r_emailaddress
      "connections"  # in r_network
    ]

  # https://github.com/pivotal-sushi/omniauth-mixi
  # http://developer.mixi.co.jp/connect/mixi_graph_api/api_auth/
  config.omniauth :mixi, OAUTH_CONFIG[:mixi]['key'], OAUTH_CONFIG[:mixi]['secret']

  # https://github.com/arunagw/omniauth-twitter
  # https://dev.twitter.com/docs/api/1.1
  config.omniauth :twitter, OAUTH_CONFIG[:twitter]['key'], OAUTH_CONFIG[:twitter]['secret']

それぞれのアプリケーションで受け取る情報が異なっています。

テーブル

① ターミナルで下記を実行して、SocialProfileテーブルを作成する

rails g model SocialProfile 

② 作成したテーブルのカラムを設定する

①で作成した[作成した日時]_create_social_profiles.rbのchangeメソッドを下記のように編集する。

[作成した日時]_create_social_profiles.rb

  def change
    create_table :social_profiles do |t|
      t.references :user, foreign_key: true
      t.string :provider
      t.string :uid
      t.string :name
      t.string :nickname
      t.string :email
      t.string :url
      t.string :image_url
      t.string :description
      t.text :other
      t.text :credentials
      t.text :raw_info

      t.timestamps
    end
    add_index :social_profiles, [:provider, :uid], unique: true
  end

その後、下記のコマンドを実行する。

rails db:migrate

少し上記のカラムについて説明します。

下記は大体どのアプリケーションでも受け取る情報となるので、必須のカラムです。

  • provider
  • uid
  • email
  • description
  • image_url
  • url

それ以外のカラムは、自分がどの外部アプリケーション認証を導入するかによって少しずつ変化していきます。

どんなカラムを追加すればいいかについては、それぞれの外部アプリケーションアカウントを導入するためのgemのREADME.mdを読めば大体わかるようになっていると思います。 例えば、Twitterであれば、以下のURLのREADME.mdに記載されています。

github.com

モデル

下記のようにsocial_profile.rbに追記します。

social_profile.rb

class SocialProfile < ApplicationRecord
  belongs_to :user
  store :other
  validates_uniqueness_of :uid, scope: :provider

  scope :search_with_providers, ->(provider) { where(provider: provider) }

  def set_values(omniauth)
    return if provider.to_s != omniauth['provider'].to_s || uid != omniauth['uid']
    credentials = omniauth['credentials']
    info = omniauth['info']

    self.access_token = credentials['token']
    self.access_secret = credentials['secret']
    self.credentials = credentials.to_json
    self.email = info['email']
    self.name = info['name']
    self.nickname = info['nickname']
    self.description = info['description'].try(:truncate, 255)
    self.image_url = info['image']
    case provider.to_s
    when 'hatena'
      self.url = "https://www.hatena.ne.jp/#{uid}/"
    when 'github'
      self.url = info['urls']['GitHub']
      self.other[:blog] = info['urls']['Blog']
    when 'google'
      self.nickname ||= info['email'].sub(/(.+)@gmail.com/, '\1')
    when 'linkedin'
      self.url = info['urls']['public_profile']
    when 'mixi'
      self.url = info['urls']['profile']
    when 'twitter'
      self.url = info['urls']['Twitter']
      self.other[:location] = info['location']
      self.other[:website] = info['urls']['Website']
    end

    self.set_values_by_raw_info(omniauth['extra']['raw_info'])
  end

  def set_values_by_raw_info(raw_info)
    case provider.to_s
    when 'google'
      self.url = raw_info['link']
    when 'twitter'
      self.other[:followers_count] = raw_info['followers_count']
      self.other[:friends_count] = raw_info['friends_count']
      self.other[:statuses_count] = raw_info['statuses_count']
    end

    self.raw_info = raw_info.to_json
    self.save!
  end
end

この部分では、それぞれの外部アプリケーションで処理を分けて値を代入しています。 自分が実装したい外部アプリケーション以外の処理の部分だけ追記しましょう。

次に、user.rbを下記のようにします。

user.rb

class User < ActiveRecord::Base
  devise :omniauthable

  has_many :social_profiles, dependent: :destroy
  def social_profile(provider)
    social_profiles.select{ |sp| sp.provider == provider.to_s }.first
  end
end

ルーティング

routes.rbに下記のように追加します。 下記では、コントローラーがusersディレクトリ以下にある場合のルーティングを示しています。自分のディレクトリに変更しましょう。

routes.rb

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks", :registrations => 'users/registrations'  }

コントローラー

deviseでのログイン機能の導入を前提にしているので、現時点で、下記のコントローラーがある場合もあるかもしれません。

  • confirmations_controller.rb
  • passwords_controller.rb
  • registrations_controller.rb
  • sessions_controller.rb
  • unlocks_controller.rb
  • omniauth_callbacks_controller.rb

もし無い場合は、下記のコマンドで作成されます。

ディレクトリ名は好きなようにで入力しましょう。

rails g devise:controllers [ディレクトリ名]

先ほど作成したomniauth_callbacks_controller.rbに下記のように追記します。

omniauth_callbacks_controller.rb

 def facebook; basic_action; end
 def github; basic_action; end
 def google; basic_action; end
 def hatena; basic_action; end
 def linkedin; basic_action; end
 def mixi; basic_action; end
 def hatena; basic_action; end

private
  def basic_action
    @omniauth = request.env['omniauth.auth']
    if @omniauth.present?
      @profile = SocialProfile.where(provider: @omniauth['provider'], uid: @omniauth['uid']).first
      unless @profile
        @profile = SocialProfile.where(provider: @omniauth['provider'], uid: @omniauth['uid']).new
        @profile.user = current_user || User.create!(username: @omniauth['name'], email: dammy_mail, password: dammy_password)
        @profile.save!
      end
      if current_user
        flash[:notice] = "外部アプリケーションとの連携が完了しました" if current_user == @profile.user
        flash[:alert] = "このアカウントは他のユーザーによって連携されています" if current_user != @profile.user
      else
        sign_in(:user, @profile.user)
      end
      @profile.set_values(@omniauth)
    end
    redirect_to user_path(current_user)
  end

  def dammy_mail
    dammy_mail = "hoge@example.com"
    return dammy_mail
  end

  def dammy_password
    dammy_password = "000000"
    return dammy_password
  end

dammy_mail、dammy_passwordとあるのは、deviseのログイン機能でemailとpasswordに対して存在のバリデーションを設けているからです。

参考

qiita.com

以上で終了です。もし、間違っているところなどがあれば教えていただけるとありがたいです!