Madogiwa Blog

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

Ruby:rubyとherokuを使って無料で作るTwitterBot

f:id:madogiwa0124:20170625191213p:plain

はじめに

rubyの勉強を兼ねて、ruby + herokuを使って無料でTwiterBotを作ったので、そのやり方をメモしますφ(..)

作ったもの

ruby勉強bot

ruby(v2.3.0)の主要クラスと、そのメソッドとrubyリファレンスマニュアルの該当ページを1時間に1回呟きます! rubyの勉強にお役に立てれば幸いです。(o・ω・o)

作り方

準備

Twitterアカウントの作成

Bot用に使用するTwitterアカウントの作成を行います。  メールアドレスが必要となりますが、作成がめんどくさい場合は、下記のようは方法を使っても大丈夫です。 http://kantandays.com/twitter-fukusu-account/

Twitter Developperサイトにてアプリを作成

Twitter Developersサイトにてアプリケーションを作成します。

項目 設定値 設定例
Name アプリの名前 ruby_study_bot
Description アプリの説明 ruby勉強用のボットです。
Website 作成したTwitterアカウントのページ https://twitter.com/ruby_study_bot

設定イメージ f:id:madogiwa0124:20170625184641p:plain

他の項目は任意項目のため設定不要です。

アクセストークンの生成

作成したBotアプリのKey and Access Tokenタブに移動し、Create my access tokenから生成します。
生成したAccess TokenAccess Token Secretと既に生成されているConsumer KeyConsumer Secretは、後ほどプログラム内で使用するので、メモしておきます。

Botアプリの作成

作業フォルダの作成

作業用のフォルダを作成します。フォルダ名は任意です。

$ mkdir twitter_bot

git管理下に設定

下記コマンドを実行し、作業フォルダをgit管理下にします。

$ git init

GemFileの作成

作成したフォルダでGemfileを作成します。

$ cd twitter_bot
$ touch Gemfile

作成したGemfileを下記のように変更します。

  • sinatra:Webフレームワークsinatraを使用するためのgem
  • twitter:TwiterAPIを使用するためのgem
  • dotenv:環境変数を.envファイルで管理するためのgem
source 'https://rubygems.org'
ruby '2.3.0'

gem 'sinatra', '1.4.7'
gem 'twitter', '5.16.0'
gem 'dotenv'

編集が完了したら下記コマンドを実行し、gemをインストールします。

$ bundle install

Twitter Botのコードを書くファイルを作成

下記コマンドを実行し、必要なファイルを作成します。

$ touch app.rb tweet.rb config.ru .env
ファイル メモ
app.rb webアプリのメインファイル、routing等を定義
tweet.rb 実際の投稿処理を記述
config.ru webアプリの設定ファイル
.env 環境変数管理用のファイル

環境変数の設定

.envファイルに、生成した各KEY、SECRETを記載します。

CONSUMER_KEY=生成したBotアプリのConsumer Key
CONSUMER_SECRET=生成したBotアプリのConsumer Secret
ACCESS_TOKEN=生成したBotアプリのAccess Token
ACCESS_TOKEN_SECRET=生成したBotアプリのAccess Token Secret

Twitter Botのプログラミング

  1. Twitterクライアントの生成と投稿処理をtweet.rbに記述します。
  2. herokuでsinatraアプリであることを認識されるための設定をconfig.ruに記述します。
  3. ルーティングをapp.rbに記述します。

tweet.rb

require 'date'
require 'twitter'
require 'dotenv/load'

class Tweet

  def initialize
    # 投稿内容の初期化
    @text = ""
    # クライアントの生成
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = ENV['CONSUMER_KEY']
      config.consumer_secret     = ENV['CONSUMER_SECRET']
      config.access_token        = ENV['ACCESS_TOKEN']
      config.access_token_secret = ENV['ACCESS_TOKEN_SECRET']
    end
  end

  # Tweetの投稿処理呼び出し
  def send_tweet
    create_text
    update
  end

  # ツイート本文の生成
  def create_text
    # 投稿内容を設定
    @text = "test" 
    end
  end

  private

  # Tweet投稿処理
  def update
    begin 
      @client.update(@text)
    rescue => e
      p e # エラー時はログを出力
    end
  end
end

# ツイートを実行
if __FILE__ == $0
  Tweet.new.send_tweet
end

config.ru

require_relative 'app.rb'
run Sinatra::Application

app.rb

require 'sinatra'
require_relative 'tweet.rb'

get '/' do
  'under construction'
end

get '/send_tweet' do
   'Closed'
end

herokuにデプロイする

下記コマンドを実行し、今までの変更をローカルリポジトリに反映します。

$ git add -A
$ git commit -m "first commit"

下記コマンドを実行し、herokuのリポジトリを作成しローカルリポジトリの内容を反映します。

$ heroku login
$ heroku create
$ git push heroku master

投稿スケジュールの作成

スケジュール実行は、schedulerアドオンを使います。 下記コマンドを実行して、インストールし設定画面を開きます。

$ heroku addons:create scheduler:standard
$ heroku addons:open scheduler   

下記を参考にスケジュールを設定したら完了です。※1時間おきの設定 f:id:madogiwa0124:20170625184647p:plain

参考にさせて頂いたページ

b0npu.hatenablog.com

http://blog.ruedap.com/2011/02/09/ruby-heroku-twitter-botblog.ruedap.com

ruby:Rubocopの使い方と警告について

最近Rubocopを使いはじめたので、使い方とか警告の意味とかをメモφ(..)

Rubocopとは

RubocopはOSSで開発されているソースコードの静的解析を行うgemです。
RubyStyleGuidソースコードが準拠しているかチェックすることが出来ます。
Githubリポジトリ:https://github.com/bbatsov/rubocop

実際の開発現場でも使われているので、普段の勉強から使っていき綺麗なコードを書く習慣を身に着けたい…!

Rubocopの使い方

インストール

$ gem install rubocop

使い方

ファイルの検証

$ rubocop hoge.rb

rubocopの警告のON / OFFを独自に設定する

rubocopの警告を独自にON / OFFを設定するためには、.rubocop.ymlをプロジェクトのrootディレクトリに配置します。

下記のような形で、.rubocop.ymlに記載することで独自にON / OFFを切り替えることが出来ます。

# クラスにコメントを残さない
Documentation:
  Enabled: false # falseにすることでcheckを無効化

警告欄

文字 意味
. Clean(問題なし)
C Convention(慣習違反)
W Warning
E Error
F Fatal
Inspecting 1 file
C

Offenses:

hoge.rb:28:1: C: Missing top-level class documentation comment.
class Hoge
^^^^^

1 file inspected, 1 offenses detected

警告メッセージMemo

Extra empty line detected at class body end.

google翻訳

クラス本体の最後で余分な空行が検出されました。

class Hoge
  def fuga
    return piyo
  end
  # 不正な改行
end

Final newline missing.

google翻訳

最終改行がありません。

class Hoge
  def fuga
    return piyo
  end
end # ファイルの末尾に改行なし

1 trailing blank lines detected.

google翻訳

1つの末尾空白行が検出されました。

class Hoge
  def fuga
    return piyo
  end
end
# 空白行
# 空白行 : NG

Space missing after comma.

google翻訳

コンマの後にスペースがありません。

# カンマのあとにスペースが入っていない
Hoge.new(a,b,c) # NG
Hoge.new(a, b, c) # OK

Trailing whitespace detected.

google翻訳

末尾の空白が検出されました。

class hoge
  def fuga
    puts piyo
  end  # 行の末尾に空白文字
end

Missing top-level class documentation comment.

google翻訳

トップレベルのクラスのドキュメントコメントがありません。

# クラスの1行上にコメントを書く
class hoge
  def fuga
    puts piyo
  end
end

Use only ascii symbols in comments.

google翻訳

コメントにはASCII記号のみを使用してください。

# piyoを出力 : NG
# output piyo : OK
puts piyo

Space inside { missing. / Space inside } missing.

google翻訳

内側にスペースがありません。

# {}の内側には半角スペースを入れる。
{ hoge: "hoge", fuga: "fuga" }

Line is too long. [84/80]

google翻訳

ラインが長すぎます。 [84/80]

# 1行の文字数は80文字まで
# NG
puts HogeHoge.new(hogehoge: 52, fugafuga: 11, piyopiyo: piyo.new("hiyoco", "niwatori")).hogefugapiyo_method
# OK
hoge = HogeHoge.new(
  hogehoge: 52, 
  fugafuga: 11, 
  piyopiyo: piyo.new("hiyoco", "niwatori")
)
puts hoge.hogefugapiyo_method

Closing method call brace must be on the line after the last argument when opening brace is on a separate line from the first argument.

google翻訳

中括弧を最初の引数とは別の行に置いているときに、最後の引数の後の行には、メソッド呼び出し中括弧を閉じる必要があります。

# 1行の文字数は80文字まで
# NG
Hoge.new(
  hoge: "hoge",
  fuga: "fuga")
# OK:閉じ括弧の位置は開始の位置と合わせる。
Hoge.new(
  hoge: "hoge",
  fuga: "fuga"
)

Inconsistent indentation detected.

google翻訳

矛盾したインデントが検出されました。

# 適切にインデントを入れる
# NG
  private 
    def hoge
    end
# OK:private配下はインデントは不要
  private
  def hoge
  end

Use %i or %I for an array of symbols.

google翻訳

シンボルの配列には %iまたは%Iを使います。

# シンボルの配列には%記法を使う
# NG
  before_action :set_page, only: [:show, :edit, :update, :destroy]
# OK
  before_action :set_page, only: %i[show edit update destroy]

おわりに

また新しいメモや警告があれば追記していきます!φ(..)

参考ページ

wonderwall.hatenablog.com

blog-ja.sideci.com

RubyonRails:deviseのエラーメッセージをカスタマイズする方法

deviseで発生するエラーメッセージのBootstapっぽくしたかったので、その方法をφ(..)メモメモ

事象

deviseでは、通常エラーメッセージをdevise内で定義されているdevise_error_messages!で表示させるため、class等を設定し、レイアウトを調整することは出来ない。

f:id:madogiwa0124:20170610103432p:plain

対処法

devise_error_messages!とは別にメソッドをHelperに定義し、エラーメッセージを返却すれば良い。

application_helper.rb

  # デバイスのエラーメッセージ出力メソッド
  def devise_error_messages
    return "" if resource.errors.empty?
    html = ""
    # エラーメッセージ用のHTMLを生成
    messages = resource.errors.full_messages.each do |msg|
      html += <<-EOF
        <div class="error_field alert alert-danger" role="alert">
          <p class="error_msg">#{msg}</p>
        </div>
      EOF
    end
    html.html_safe
  end

view

<%= devise_error_messages %>
    <h1>アカウント情報</h1>
    <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
      <div class="myinfo_form">
        <div class="form-group">
          <%= f.label :email %>
          <%= f.email_field :email, autofocus: true, class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :password %>
          <%= f.password_field :password, autocomplete: "off", class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :password_confirmation %>
          <%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :current_password %>
          <%= f.password_field :current_password, autocomplete: "off", class: "form-control" %>
        </div>
        <div class="form-group">
          <%= f.label :send_mail %>
          <%= f.check_box :send_mail %>
        </div>
        <div class="actions">
          <%= f.submit "更新する", class: "btn btn-primary" %>
        </div>
      </div>
    <% end %>

修正後 f:id:madogiwa0124:20170610103653p:plain

参考にしたページ

qiita.com


Bootstrap:ナビゲーションバーの丸みをなくす方法

Bootstrapのナビゲーションバーに微妙に丸みがあるのが気になったので、無くす方法をメモφ(..)

事象

Bootstrapのナビゲーションバーはデフォルトでは、微妙に丸みを帯びている。
いままで見てみぬふりをしてきたが、結構気になっていた。。。

f:id:madogiwa0124:20170607223836p:plain

bootstrap3.cyberlab.info

解決方法

下記CSSを記載すればOK

.navbar{
  border-radius: 0px;
}

Chrome等で検証すればわかるが、
デフォルトでは.navbar5pxradiusが設定されてる。
これを上書きしてあげればOK!

f:id:madogiwa0124:20170607224205p:plain

※画像はCSS反映後のため無効化されてます。

RubyonRails:SNSログインエラーの確認ポイント

SNSログイン周りのエラーで大分ハマったので、確認観点をメモ。

エラー

Facebook
f:id:madogiwa0124:20170606230855p:plain Twitter
f:id:madogiwa0124:20170606230915p:plain

API KEYとSECRET KEYは一致しているか?

API KEYとSECRET KEYが作成したAPIと一致しているか確認する。

API KEYとSECRET KEYは取得出来ているか?

下記コマンドを実行し、環境変数が取得出来ているかを確認する。

$ rails console
$ ENV["指定したAPI KEY"]
$ ENV["指定したSECRET KEY"]

取得出来ない場合は、環境変数の名称と取得側の名称が異なっている可能性がある。
例)環境変数:aaa=~~~ / 取得側:aaA=~~~

.envファイルの配置場所

dotenvを使用している場合は、.envファイルの配置場所に注意
rootフォルダ(アプリケーション名)直下に配置すること

RubyonRails:データベースをsqlite3からpostgresqlに変更する方法

間違えてsqlite3でRailsアプリケーションを作成してしまい、

途中からposgresqlに変更した手順をメモφ(..)

変更手順

Gemfileの修正

sqlite3コメントアウトし、postgresql用のgempgに変更

# gem 'sqlite3'
gem 'pg'

変更後、下記コマンドを実行

bundle install

database.ymlの修正

config/databese.ymlの内容をpostgresql用に修正

appnameにはrails newした際に指定したアプリケーション名を設定

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  template: template0


development:
  <<: *default
  database: appname_development

test:
  <<: *default
  database: appname_test

production:
  <<: *default
  database: appname_production
  username: appname
  password: <%= ENV['appname_DATABASE_PASSWORD'] %>

dbの再作成とmigrateの再実行

下記コマンドを実行し、dbの再作成とテーブル定義の反映を行う。

$ rake db:creat

$ rake db:migrate

参考資料

blog.bgbgbg.net

RubyonRails:登録時にRollbackされる原因がわからない時の対処法

model.saveの際になぜか TransactionがRollbackされ原因調査でハマったのでメモφ(..)

対処法

model.save!で登録を行ってみる。 model.saveの返り値は、true/falseのため、どのようなエラーが発生しROLLBACKされているかはわからない。 しかし、model.save!では、ActiveRecordの例外を返してくれるため、原因調査に役立つ。

実際の結果

[2] pry(#<MessagesController>)> @message.save
   (0.1ms)  begin transaction
  Message Exists (0.3ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."body" = 'ああああ' LIMIT 1
  Message Exists (0.2ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."conversation_id" = 1 LIMIT 1
  Message Exists (0.2ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."user_id" = 2 LIMIT 1
   (0.1ms)  rollback transaction
=> false
[3] pry(#<MessagesController>)> @message.save!
   (1.3ms)  begin transaction
  Message Exists (0.8ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."body" = 'ああああ' LIMIT 1
  Message Exists (0.3ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."conversation_id" = 1 LIMIT 1
  Message Exists (0.4ms)  SELECT  1 AS one FROM "messages" WHERE "messages"."user_id" = 2 LIMIT 1
   (0.1ms)  rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Conversation has already been taken, User has already been taken

こんな感じでエラーの原因を確認出来る。

参考にしたページ

d.hatena.ne.jp