コピペコードで快適生活

明日使えるソースを自分のために

受託開発で炎上しないためのチェックリスト

未来への自分の戒めとして「受託開発で炎上しないためのチェックリスト」を作成してみました。基本的なことばかりだけど、この基本をきちんと押さえておくことが大切だと思うのです。

・プロジェクトリーダーを立てているか
・リードエンジニア(技術責任者)を立てているか

・スケジュールを立てているか
・スケジュールに予備日を設けているか
・進捗状況を把握できているか
・遅れに対する対策を講じているか

・メンバーとスケジュール共有したか
・メンバーに担当タスクと期限日を認識させたか
・メンバーと定期的に状況共有しているか

・お客様とスケジュール共有したか
・お客様にお客様担当タスクと期限日を認識させたか
・定期的にお客様に状況を報告しているか

仕様書/設計書を作成したか
仕様書/設計書のレビューを行っているか
仕様書の内容についてお客様と認識合わせしたか
・仕様/設計FIXしたか

・コードレビューを行っているか
 (レビューポイントはリーダブルか/DRYか/再利用しやすいか/拡張しやすいか)

・テスト仕様書/テストコードを作成したか
・テスト仕様書/テストコードのレビューを行っているか

検収時の指摘事項に対する対応として、やる/やらない/別見積を明確にお客様に提示しているか
検収完了の連絡をいただいたか

minttyのカッコいい設定

minttyは設定次第でカッコいい見た目になるのでとても気に入っています。
僕の.minttyrcは↓のような感じです。

BoldAsFont=no
FontHeight=11
Font=Inconsolata
FontIsBold=no
BackgroundColour=0,0,0
ForegroundColour=245,245,245
Transparency=medium
Columns=160
Rows=40
Black=0,0,0
Red=255,204,153
Green=204,255,204
Yellow=255,255,153
Blue=153,204,255
Magenta=204,153,255
Cyan=204,255,255
White=255,255,255
BoldRed=255,204,153
BoldGreen=204,255,204
BoldYellow=255,255,153
BoldBlue=153,204,255
BoldMagenta=204,153,255
BoldCyan=204,255,255
BoldWhite=255,255,255
CopyOnSelect=no


見た目こんな感じになります。
f:id:comb_8107:20160323151424p:plain


設定はこちらを参考にさせていただきました。感謝です。
Cygwin Terminal (Mintty) の設定 - 計算物理屋の研究備忘録


フォントはこちらを使用しています。
Inconsolata

RubyでUTF-8変換時にUndefinedConversionが出た件

shift_jisで書かれたCSVUTF-8に変換して取り込み処理をするところで、Encoding::UndefinedConversionError が吐かれてた。

str.encode('utf-8', 'shift_jis') # => Encoding::UndefinedConversionError: "\x87@" from Shift_JIS to UTF-8


なんでだと思って調べてたところ、shift_jisでは対応していない①とか㈱とかの機種依存文字を変換しようとしていたからエラー出ていたみたい。なのでCP932(Windows-31J)使えば解決。

str.encode('utf-8', 'CP932') # => ①㈱

対応しない文字を強制的に置き換えするときは

str.encode("Shift_JIS", "UTF-8", {
            :invalid => :replace,
            :undef   => :replace,
            :replace => ""})

MySQLのユーザ管理コマンド

ユーザ管理
-- ユーザリスト
SELECT Host, User, Password FROM mysql.user;

-- ユーザ作成
CREATE USER 'kinosuke'@'localhost' IDENTIFIED BY 'some password';

-- ユーザ作成
-- GRANT使う&パスワードハッシュ使う版
GRANT USAGE ON *.* TO 'kinosuke'@'localhost' IDENTIFIED BY PASSWORD '*235FBD5A94312B29D808844FC68009764D01AD27';

-- ユーザ名、ホスト変更
RENAME USER 'kinosuke'@'localhost' TO 'new_name'@'new_host';

-- パスワード変更
SET PASSWORD FOR 'kinosuke'@'localhost' = PASSWORD('some password');

-- ユーザ削除
DROP USER 'kinosuke'@'localhost';
権限変更
-- 権限確認
SHOW GRANTS FOR 'kinosuke'@'localhost';

-- グローバルレベル:
GRANT 権限 ON *.* TO 'kinosuke'@'localhost';

-- データベースレベル:
GRANT 権限 ON db_name.* TO 'kinosuke'@'localhost';

-- テーブルレベル:
GRANT 権限 ON db_name.table_name TO 'kinosuke'@'localhost';

-- カラムレベル:
GRANT 権限 (カラム1, カラム2, ...) ON db_name.table_name TO 'kinosuke'@'localhost';

-- 例) 特定DBのREADのみ
GRANT SELECT ON `mydb`.* TO 'kinosuke'@'localhost';

rbenvでRubyをインストール~gemsetの設定

Rubyインストー
# rbenv をインストール(clone)する
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

# bash_profile 設定追加
# vim ~/.bash_profile
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

# 上記設定の再読み込み
exec $SHELL -l

# rbenvの確認
rbenv --version

# ruby-build を インストール(clone)する
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

# ruby の最新版を確認
rbenv install --list

# ruby のインストール
RUBY_BUILD_CURL_OPTS=--tlsv1.2 rbenv install -v 2.0.0-p451

# 再読み込み
rbenv rehash

# installed 確認
rbenv versions

# デフォルト設定
rbenv global 2.0.0-p451

# カレントディレクトリで使う
rbenv local 2.0.0-p451

参考にさせていただきました!感謝!
rbenv を使って ruby をインストールする(CentOS編) - Qiita

gemsetの設定
# ruby-gemset を インストール(clone)する
cd ~/.rbenv/plugins/
git clone https://github.com/jf/rbenv-gemset.git

# gemset 作成
rbnev gemset list
rbenv gemset create 2.0.0-p451 redmine

# 削除するとき
rbenv gemset delete 2.0.0-p451 redmine

# 指定dir以下で gemset使う
cd /var/www/app/redmine/
echo redmine > .rbenv-gemsets
rbenv rehash

# カレントディレクトリで有効なgemset
rbenv gemset active

参考にさせていただきました!感謝!
Redirecting...

Rails×SES バウンスメール(不達メール)対策

「SESで不達メールが多いから、対策してくれなかったらSES止めるよ」って過去にAWSから言われたことがあって、そのときの対応メモを書きだしてみた。

対応の基本的な流れ
SESは不達メールがあった場合に特定のURLに対してリクエストをjson付きで投げてくれるので、それを特定のURLでうけてJSONパースして、そのパースしたJSONの中にメールアドレスがあるので、それをブラックリストテーブルか何か作ってINSERTして、メール送信の時はそのブラックリストテーブルを見て、送っていいメールアドレスいいか判定するって感じ。

AWSの設定はここを参考に。
Amazon SESのBounce SNS通知をRailsで処理する|WEBデザイン Tips

Railsのソースはこんな感じ。

app/controllers/api/aws_controller.rb

#
# AWSから飛んできたリクエストを受け取るAPI
#
require 'json'
require 'open-uri'
class Api::AwsController < ActionController::Base
  skip_before_filter :verify_authenticity_token

  #
  # SESからリクエストされる
  # 不達メールアドレスリストをブラックリストに登録する
  #
  def receive_bounce_notice
    # data = JSON.parse(dummy_raw_post) # debug用
    data = JSON.parse(request.raw_post)

    # Subscription認証用URLを開いて認証を完了する
    if data['SubscribeURL'].present?
      open(data['SubscribeURL'])    

    # ブラックリスト登録する
    else
      data2 = JSON.load(data['Message'])
      type = data2['notificationType']

      if type=='Bounce'
        bounce = data2['bounce']
        bouncerecps = bounce['bouncedRecipients']
        bouncerecps.each do |recp|
          email = recp['emailAddress']
          if BouncedEmailAddress.where(email: email).blank?
            BouncedEmailAddress.create(email: email)
          end
        end
      end
    end

    render text: ""
  end

  private
    def dummy_raw_post
str =<<EOS
{
  "Type" : "Notification",
  "MessageId" : "463fbb0b-63ea-4a6d-90c5-33c8686e3bd1",
  "TopicArn" : "arn:aws:sns:us-east-1:811118151095:suz-lab-ses",
  "Message" : {
      "notificationType":"Bounce",
      "bounce":{
         "bounceType":"Permanent",
         "bounceSubType": "General",
         "bouncedRecipients":[
            {
               "emailAddress":"recipient1@example.com"
            },
            {
               "emailAddress":"recipient2@example.com"
            }
         ],
         "timestamp":"2012-05-25T14:59:38.237-07:00",
         "feedbackId":"00000137860315fd-869464a4-8680-4114-98d3-716fe35851f9-000000"
      },
      "mail":{
         "timestamp":"2012-05-25T14:59:38.237-07:00",
         "messageId":"00000137860315fd-34208509-5b74-41f3-95c5-22c1edc3c924-000000",
         "source":"email_1337983178237@amazon.com",
         "destination":[
            "recipient1@example.com",
            "recipient2@example.com",
            "recipient3@example.com",
            "recipient4@example.com"
         ]
      }
  },
  "Timestamp" : "2012-10-08T13:00:40.691Z",
  "SignatureVersion" : "1", 
  "Signature" : "FDNBWbFhc5MXs+2tjw327zXhiKca3GLHbbVEN8vUmLAmnj60...",
  "SigningCertURL" : "https://sns.us-east-1.amazonaws.com/SimpleN...",
  "UnsubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action..."
}
EOS
      return str
    end
end


lib/mail/email_interceptor.rb

#
# email_interceptor は、action mailer の
# before action 的な動きをしてくれるヤツ(らしい。。)
#
class EmailInterceptor
  #
  # ブラックリスト宛には送らない
  #
  def self.delivering_email(message)
    _to = message.to
    message.to = probe_email(message.to)   if message.to.present?
    message.cc = probe_email(message.cc)   if message.cc.present?
    message.bcc = probe_email(message.bcc) if message.bcc.present?

    message = set_to(message, _to)
  # rescue => e
  #   binding.pry
  #   Rails.logger.error(e.to_s << "\n" << e.backtrace.join("\n"))
  end

  #
  # ブラックリストに載っていないアドレスだけにする
  #
  def self.probe_email(emails)
    bounced_email_addresses = BouncedEmailAddress.pluck(:email)

    list = []
    emails = [emails] if emails.instance_of?(String)
    emails.each do |email|
      list << email if !(bounced_email_addresses.include?(email))
    end
    return list
  end

  #
  # toがすべて空だった場合
  # 送信処理するとエラーになるため、
  # とりあえず仮で送信先を入れる
  #
  def self.set_to(message, _to)
    return message if message.to.present?

    # ブラックリストに送ろうとしたメールはここに送信する
    message.to = ["sample@gmail.com"]
    # message.subject = "Can not sent to bouced email address"
    return message
  end
end

email_interceptor.rb は、lib/mail の配下とかにおいて、
config/application.rb で読みこむようにすればOK。

  class Application < Rails::Application
  # 略
    config.autoload_paths += %W(#{config.root}/lib/mail)
 # 略


※BouncedEmailAddressというモデルはブラックリスト用テーブル。
 メールアドレスを格納しているだけなのでソースは割愛。

Apacheのログ解析でFSにダブルクォート使うと便利

Apacheのログが扱いづらいとTwitterで嘆いていたら新たな知見をいただいた。

awk v.s. bashどっちが強い?@OSC2011Tokyo より

FSにダブルクォート(")を使え!
ダブルクォートをFSにすると、、、
$1:アクセス元、日付
$2:受け取ったコマンド
$3:ステータスコード
$6:クライアント情報

こんな感じで使う。

cat access_log | awk -F'"' '{print $6}'