【メール送信エラー】Net::SMTPAuthenticationError - 534-5.7.14 <https://accounts.google.com/ContinueSignIn ...

メール送信周りでちょっとはまりかけたのでメモ。
ponyというgemを使ってSMTPでメール送信をしようとしてました。
サイトからユーザーが申し込みしてきたら、申込完了メールをユーザーに送信するイメージです。

★環境
Ruby
・pony on sinatra
Gmailで送信(from @gmail.com)

たぶんRails(ActionMailer)でもあまり変わらないと思います。

普通にドキュメントに書かれてる通り実装すると、

Net::SMTPAuthenticationError - 534-5.7.14 <https://accounts.google.com/ContinueSignIn ...

というエラーが出てしまいました。
http://www.google.com/accounts/DisplayUnlockCaptcha
上記にアクセスして許可すればいいとう記事もありましたが、うまくいかず。

結論をいうと、送信したいGmailアカウントの設定から2段階認証を有効にして、
アプリ固有のパスワードを作り、実装にそのパスワードを組み込むのが手っ取り早いと思います。

スクリーンショット 2014-10-24 11.22.22.png

↑ 左上の「2段階認証プロセス」の設定を有効にすると「アプリパスワード」という項目が現れるので設定してください。

以上でうまくいくと思います。

※参考までにponyを使った実装を載せておきます。

def send_complete_mail
  # charsetはデフォルトでutf-8なのですが、指定してないと怒られた気がします。
  Pony.mail(
    to: '送信先メールアドレス',
    subject: '件名',
    body: send_mail_body,
    charset: 'utf-8',
    via: :smtp,
    via_options: {
      address: 'smtp.gmail.com',
      user_name: 'アカウント名@gmail.com',
      password: 'アプリ固有のパスワード',
      authentication: :plain,
      domain: 'サイトのドメイン名'
    }
  )
end

def send_mail_body
  # send_mail.erbというファイルを用意しておけばよいです。
  # localsのハッシュでview内の変数に値を渡せます。
  erb :send_mail, locals: {
    hoge: session[:hoge],
    fuga: session[:fuga]
  }
end

Mechanizeでページ遷移しながらスクレイピング

ちょっとダルいポイントが有ったのでメモ程度に。
スクレイピング対象サイトとスクレイピングの流れは

  • ページャで何ページか一覧ページがある
  • 一覧ページのタイトルをクリックすると詳細ページが見れる
  • 詳細ページの一部を使用
  • また他のタイトルをクリックしていく
  • CSVで出力(別にいらないけどメモ代わりに。。)

みたいな感じです。mechanizeだけでやります。

require 'mechanize'
require 'csv'

class ScrapingPages

  def initialize
    @agent = Mechanize.new
    @data = []
  end

  def retrieve
    # 1ページ目から10ページ目までスクレイピングする
    (1..10).each do |i|
      page = @agent.get(url(i)
      each_section(page) do |section|
        title = section.css('h2.title > a').first.text
        detail = @page.links_with(text: title).first.click
        @data << {
          title: title,
          detail: detail.links.first.text
        }
      end
    end
  end

  def each_section(page)
    page.search('.articleBox').each do |section|
      yield section
    end
  end

  def url(current_page)
    "https://hogehoge.com/#{current_page}"
  end

  def make_file_as_csv
    CSV.open("./csv/scraping-#{Time.now.to_i}.csv", "wb", encoding: 'Shift_JIS') do |csv|
      csv << %w(title detail)
      @data.each do |record|
        csv << [record[:title], record[:detail]]
      end
    end
  end
end

scraping_pages = ScrapingPages.new
scraping_pages.retrieve
scraping_pages.make_file_as_csv

コードは実際のものとちょこちょこ変更箇所あるので流しでいいのですが、ポイントはclickのところ。
mechanizeは中でnokogiriを使っているようで、
上記の@agent, pageとかはmechanizeクラスが 親のオブジェクトなのですが、
.cssとか使うと返ってくるオブジェクトがnokogiriクラスのインスタンスオブジェクトが返ってきます。

で、clickメソッドはmechanizeクラスに対してしか使えないので、微妙に工夫が必要。

title = section.css('h2.title > a').first.text
detail = @page.links_with(text: title).first.click

# .css('h2.title > a').first.clickとかすると、
# nokogiriがclickメソッド持ってないのでエラーになる。

ここです。title変数で一旦クリック個所のテキストを格納しておいて、
mechanizeクラス継承の@pageに対してリンクを辿って
テキストを指定してクリックする、と。

csvはよく忘れるのでメモ程度に載せただけです。

もっと良いやり方あるかもだけど。

Supervisor経由でunicornを立ち上げている環境にCapistrano3で自動デプロイ

前回の続きです。前回はCapistrano3の導入について書きました。
【入門】Capistrano3で自動デプロイ

★★★

私の環境ではsupervisor経由でunicornを監視しているのですが、supervisorをリスタートしてしまうとhot deploy出来ない問題がありました。

そちらに関しての解決策としては下記を参考にしてください。
supervisord + unicornでhot restart (deploy) する


さて、今回は上記を踏まえて

  • capistrano3
  • unicorn
  • supervisor
  • Rails4
  • Ruby2.1.1(ここのバージョンはあまり関係ない)

という環境で自動デプロイしたいと思います。

# config/deploy.rb

# config valid only for Capistrano 3.1
lock '3.2.0'

set :application, 'アプリ名'
set :repo_url, 'git@hogehoge:hogehoge/application.git'
set :branch, 'master'
set :scm, :git

set :format, :pretty
set :log_level, :info # :info or :debug
set :keep_releases, 3

set :rbenv_type, :user
set :rbenv_path, '~/.rbenv'
set :rbenv_ruby, '2.1.1'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all


namespace :deploy do

  task :stop do
    on roles(:app) do
      execute 'kill -USR2 `cat tmp/pids/unicorn.pid`'
    end
  end

  task :graceful_stop do
    on roles(:app) do
      execute 'kill -USR2 `cat tmp/pids/unicorn.pid`'
    end
  end

  task :reload do
    on roles(:app) do
      execute 'kill -USR2 `cat tmp/pids/unicorn.pid`'
    end
  end

  task :restart do
    on roles(:app) do
      stop
    end
  end

  after :finishing, 'deploy:cleanup'
end

capistranoが通常の方法でリスタートしにいくところを上書きしに行ってるような感じです。

あとは環境ごとの設定を好きなように。

# config/deploy/production.rb

set :stage, :production

set :rails_env, 'production'
set :bundle_gemfile, -> { release_path.join('Gemfile') }
set :bundle_dir, -> { shared_path.join('bundle') }
set :bundle_flags, nil
set :bundle_without, %w{development test}.join(' ')
set :bundle_binstubs, nil
set :bundle_roles, :all

role :app, %w{ユーザー名@デプロイ先IP}
role :web, %w{ユーザー名@デプロイ先IP}
role :db,  %w{ユーザー名@デプロイ先IP}

set :deploy_to, '/home/ユーザー名/アプリ名'
set :ssh_options, {
  port: ポート番号,
  forward_agent: true
}

namespace :db do

  task :db_create do
    on roles(:db) do |host|
      execute "mysql -uroot -e 'CREATE DATABASE IF NOT EXISTS production_db;'"
    end
  end
end

ポイントが有るとすると、Rails4からbinstubsが原因でバグる可能性が出てくるので、 binstubsオプションにnilを渡してコマンドを作らないようにしている。
(Rails3まではrailsのサブコマンドがscriptディレクトリ以下だったが、Rails4からbin以下になったため)
⇛参考 railsのサブコマンドが使えなくなる問題の原因はbinstubs


あとはデプロイするのみです。通常通り行ってください。

$ bundle exec cap production deploy

ちなみに後ろに--traceオプションをつけると、より詳細のログが見れます。

【入門】Capistrano3で自動デプロイ

※この記事はcapistrano3についてです。capistrano2.x系には対応していません。


ちょこちょこ新規開発しているのですが、毎回リモートサーバーにsshで入って
pullして手順見ながらbundleなんちゃらして・・・。
みたいなのが非常にめんどくさいので、capistranoを使ってみました。
一度覚えてしまうと楽チンなので損はないと思います!そんなに難しくないです!

今回はインストールから実際のデプロイまで順を追って説明していきたいと思います。

★やろうとしていること

  • Rails4のアプリをリモートサーバーにローカルからデプロイ
    • web, db, appサーバーはとりあえず同じサーバーで
    • git pullとかassets:precompileとかmigrationとか自動でやりたい
  • テスト的にvagrantで作った仮想環境にデプロイするまでを説明します。

★できてないこと

■環境

  • Ruby2.1.1(あまり今回は関係ない)
  • rbenvを使っている
  • vagrant(CentOS6.4)
     

まずcapistranoの導入です。Gemfileに書くだけなので超簡単です。

# Gemfile

group :development do
  gem :capistrano
  gem :capistrano-rails
  gem :capistrano-bundler
  gem :capistrano-rbenv
end

そしてあとはいつもどおりインストール。

$ bundle install

さて、ここまでできたらcapistranoのデフォルトファイル群を用意します。
これもコマンドひとつでできます。

$ bundle exec cap install

mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
Capified

こんな感じでいくつかファイルが出来たと思います。
この時オプション指定でdevelopmentを作ったりもできます。
今回はstagingを使ってvagrantにテストデプロイしていきます。
 


Capfile

まずはここからいきましょう。とりあえずいろいろ書かれていますが全部消しちゃっていいです。

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/rbenv'
require 'capistrano/bundler'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

使うものをrequireしているだけです。これでOK。
 

config/deploy/staging.rb

次にデプロイ先の環境を設定しましょう。今回はvagrantにデプロイします。

set :stage, :staging

role :app, %{vagrant@デプロイ先IP}
role :web, %{vagrant@デプロイ先IP}
role :db, %{vagrant@デプロイ先IP}

 

config/deploy.rb

これがメインとなるファイルです。ここにデプロイのtaskを書いていきます。
と、その前にデプロイ後どういうディレクトリ構造になるのかというのを知っておいたほうが理解しやすいと思うので下に図示しておきます。

[vagrant@localhost ~]$ tree アプリ名/ -L 2
アプリ名/
├── current -> /home/vagrant/アプリ名/releases/20140421075958
├── releases
│   ├── 20140421062631
│   ├── 20140421064312
│   ├── 20140421064620
│   ├── 20140421074708
│   └── 20140421075958
├── repo
│   ├── FETCH_HEAD
│   ├── HEAD
│   ├── branches
│   ├── config
│   ├── description
│   ├── hooks
│   ├── info
│   ├── objects
│   ├── packed-refs
│   └── refs
├── revisions.log
└── shared
    ├── bin
    ├── bundle
    └── public

17 directories, 6 files

上のように、capistranoは[current, releases, repo, shared]という4つのディレクトリを作ります。
releasesにリリースごとのバージョンが管理されていき、currentはreleasesの最新へのシンボリックリンクになっているという感じです。
その他のディレクトリについてはまた調べてみてください。

では、config/deploy.rbに戻りましてとりあえず必要最低限のところから設定していきましょう。

# config valid only for Capistrano 3.1
lock '3.1.0'

set :application, 'アプリ名'
set :repo_url, 'cloneしてくるレポジトリのURL.git'
set :branch, 'master' # デフォルトがmasterなのでこの場合書かなくてもいいです。
set :deploy_to, "/home/vagrant/アプリルートディレクトリ"
set :scm, :git # capistrano3からgitオンリーになった気がするのでいらないかも?

set :format, :pretty
set :log_level, :debug # :info or :debug
set :keep_releases, 3 # 何世代前までリリースを残しておくか

set :rbenv_type, :user
set :rbenv_ruby, '2.1.1'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all # default value

こんな感じでしょうか。 set :key, :valuieのような構造になっています。

さて、いよいよデプロイ時に走らすタスクを書いていくというフェーズなのですが、
実はcapistranoはもともとデフォルトで既にいくつかのタスクを用意しています。

$ bundle exec cap -T

とやるとタスクの一覧が見れるのでみてみましょう。

cap bundler:install                # Install the current Bundler environment
cap bundler:map_bins               # Maps all binaries to use `bundle exec` by default
cap deploy                         # Deploy a new release
cap deploy:check                   # Check required files and directories exist
cap deploy:check:directories       # Check shared and release directories exist
cap deploy:check:linked_dirs       # Check directories to be linked exist in shared
cap deploy:check:linked_files      # Check files to be linked exist in shared
cap deploy:check:make_linked_dirs  # Check directories of files to be linked exist in shared
cap deploy:cleanup                 # Clean up old releases
cap deploy:cleanup_assets          # Cleanup expired assets
cap deploy:cleanup_rollback        # Remove and archive rolled-back release
cap deploy:compile_assets          # Compile assets
cap deploy:finished                # Finished
cap deploy:finishing               # Finish the deployment, clean up server(s)
cap deploy:finishing_rollback      # Finish the rollback, clean up server(s)
cap deploy:log_revision            # Log details of the deploy
cap deploy:migrate                 # Runs rake db:migrate if migrations are set
cap deploy:normalize_assets        # Normalize asset timestamps
cap deploy:published               # Published
cap deploy:publishing              # Publish the release
cap deploy:restart                 # Restart application
cap deploy:revert_release          # Revert to previous release timestamp
cap deploy:reverted                # Reverted
cap deploy:reverting               # Revert server(s) to previous release
cap deploy:rollback                # Rollback to previous release
cap deploy:rollback_assets         # Rollback assets
cap deploy:started                 # Started
cap deploy:starting                # Start a deployment, make sure server(s) ready
cap deploy:symlink:linked_dirs     # Symlink linked directories
cap deploy:symlink:linked_files    # Symlink linked files
cap deploy:symlink:release         # Symlink release to current
cap deploy:symlink:shared          # Symlink files and directories from shared to release
cap deploy:updated                 # Updated
cap deploy:updating                # Update server(s) by setting up a new release
cap install                        # Install Capistrano, cap install STAGES=staging,production

よく見てみると、すでにgit pullやrake db:migrateやassets:precompuleも用意されています。
なのでミニマムではタスクは何も書かなくてもよいでしょう。

でもせっかくなのでDBがデプロイ時になければ作成するというタスクを追加しておきましょう。

# デプロイ前に実行する必要がある。
desc 'execute before deploy'
task :db_create do
  on roles(:db) do |host|
    execute "mysql -uroot -e 'CREATE DATABASE IF NOT EXISTS データベース名;'"
  end
end

これはnamespace :deployの外に書いて個別に実行すると良いと思います。

いくつかタスクについて説明すると、まずnamespaceで名前空間を切ってそれぞれを管理できます。
あとはrolesというのがポロポロ出てきていると思うのですが、これは例えばroles(:db)としておくと、dbサーバーに対してのみ実行します。(dbサーバーはconfig/deploy/以下で指定したものですね。)

taskの前にdescを書くことが出来て、タスクの説明なんかも残しておけます。  

デプロイ

さて、ここまでくれば後は実際にデプロイするのみです。 ローカルからdeployコマンドをうってみましょう。

$ bundle exec cap db_create
$ bundle exec cap staging deploy

うまくできましたか?本番リリース時はstagingのところをproductionにしてデプロイして下さい。

 


 

余談

僕が導入しようと思った環境はsupervisor経由でunicornを動かしていて、リリースごとにsupervisorを再起動する必要があります。
なのでsupervisorの再起動中に503がでてしまって"ゔッ!"ってなるのでcapistrano経由でunicornホットデプロイをできないかとも
考えていたのですが、そもそもsupervisorを使ったunicornホットデプロイのベストプラクティスがわかっておらず、
(先輩が調べてくれたのですがなかなかやっかいそう…)
そこんとこまだ完全に自動化しきれていないなー、、というのが現状です。。

ともかくcapistrano自体の導入はそれほど敷居は高くないので導入してみてはいかがでしょうか!(๑╹ڡ╹๑)  

Facebook, Twitterでの拡散情報を取得する

「うわー、このURLのソーシャルメディアでのシェア状況知りたいって感じやわー」ってことが3日に1日くらいあると思うので、メモがてら投稿します。


Facebook

# https//google.comのいいねとシェア数を取得
https://api.facebook.com/method/fql.query?query=select%20like_count,%20share_count%20from%20link_stat%20where%20url=%22https://google.com%22
<fql_query_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" list="true">
  <link_stat>
    <like_count>86482</like_count>
    <share_count>134607</share_count>
  </link_stat>
</fql_query_response>
# https//google.comのいいねとシェア数を取得
https://api.facebook.com/method/fql.query?format=json&query=select%20like_count,%20share_count%20from%20link_stat%20where%20url=%22https://google.com%22
[
  {
    like_count: 86482,
    share_count: 134607
  }
]

Twitter

# https://facebook.comのツイートカウントを取得
http://urls.api.twitter.com/1/urls/count.json?url=https://facebook.com/
{
  count: 26250,
  url: "https://facebook.com/"
}

 

超簡単ですね。

Railsの404,500エラーページをカスタマイズ

Railsはエラーページをもともと用意してくれていて本番で動かすと
そこに飛ばしてくれるので、まぁいいっちゃいいのですが、
簡単に設定できるのでやってしまえばいいかと。
(レイアウトとかそのまま使えてサイト内ページっぽくなるし)


■環境 Rails 4.0.3 Ruby 2.1.1


とりあえずローカルで見たいのでWEBric(rails s)を本番設定で起動して確認します。
(developmentのままだといつもの赤いページが表示されます)

まず、ActionController::RoutingErrorを拾うためにroutesに設定が必要です。

# config/routes.rb

# どこにも当てはまらなかったものを取得するので最終行に書いて下さい。
get '*path', to: 'application#render_404'

次にapplicationコントローラに設定を書きます。

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  rescue_from ActiveRecord::RecordNotFound, with: :render_404
  rescue_from ActionController::RoutingError, with: :render_404
  rescue_from Exception, with: :render_500

  def render_404(exception = nil)
    if exception
      logger.info "Rendering 404 with exception: #{exception.message}"
    end
    render template: "errors/error_404", status: 404, layout: 'application'
  end

  def render_500(exception = nil)
    if exception
      logger.info "Rendering 500 with exception: #{exception.message}"
    end
    render template: "errors/error_500", status: 500, layout: 'application'
  end
end

あとはviews以下にerrorsディレクトリを作ってそれぞれ
error_400.slim(haml)とerror_500.slimを置いて
好きなようにデザインして下さい。

applicationコントローラじゃなくてerorrsコントローラとかにしたいとかは
適当にパスを書き換えればできます。

Fluentd Casual Talks #3 at :D

ディー・エヌ・エーさんで行われたfluentd勉強家に行ってきました!fluentdはkibanaのdemoを動かすときにインストールしただけというド素人状態で参加しました。

Togetterはこちら: http://togetter.com/li/602421

f:id:mr7myself:20131214114218j:plain

norikraの話

@tagomoris slide: fluent-plugin-norikra #fluentdcasual

fluent-plugin-norikra

Norikra: Schema-less event stream

fluentd - Norikraで遊んでみた - Qiita [キータ]
USTREAM: komamitsu's channel: test live. その他
 

集計処理をSQLっぽくかける これは便利そう。

 

(DeNA枠)Fluentdでshadowサーバ用意したら捗った話

@sonots
slide: Shadow fluentdcasualtalks 20131213

Haikanko -> fluentdクラスタ管理ツール
yohoushi

shadowサーバ
(Kage Kageをちょっとだけ使ってみた - ぱいぱいにっき)

memo: fluentdはログをchunkにまとめてtcpソケットで送って閉じるってのをずっとやってる。fluent-agent-liteがよさそう。shadowサーバをおいてproxyするってのはいいなぁ。自分のいまの仕事だと規模が小さすぎてそこまでしなくてもいいけど使ってみたい。。

 

fluentd go implementation (仮)

@stanaka slide: https://t.co/kVp3vK10ZF fluentdという名のGolangへの勧誘(笑)

 

Windows版fluentdで幸せになれますか

ちょっと俺はWindowsとはさよならバイバイしたので、、って感じだけどほんとにWindowsで動いてた!メモ帳でコード開いて!
 

Treasure Agent Monitoring Service

@kzk_mover
slide: Treasure Agent Monitoring Service (ベータ)

中の方の発表

fluentdモニタリング

  • 基本編

プロセス監視 ポート監視 システム情報

  • fluentd特化編 buffer溢れ buffer flushのリトライ回数 fluentd自体のエラー/ワーニング

type monitor_agentをやるとfluentd自体のログが取れる

★Treasure Agent Monitoring Service

  • td-agentのモニタリングサービス
  • td-monitoringってプラグイン入れたら

この勉強会内でリリースされてました!

 

★感想

fluentd使わねば!!いったんfluentd -> elasticsearch -> kibanaの流れで使ってみるけどいろいろできそうだなという印象を受けた。

最近つかってないツールの勉強会に行って使わないとが続いいたので、絶対導入するぜ〜

楽しかったです!

f:id:mr7myself:20131214114119j:plain