スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

SinatraでTwitterのOAuthを取得する

SinatraでさらっとTwitterのOAuth認証を書きたくなりました。
require 'sinatra/base'
require 'twitter_oauth'

class MyApp < Sinatra::Base
enable :sessions

def get_oauth_client
TwitterOAuth::Client.new(
consumer_key: 'your_consumer_key',
consumer_secret: 'your_consumer_secret'
)
end

get '/' do
client = get_oauth_client
request_token = client.request_token(oauth_callback: 'http://127.0.0.1:9292/callback')
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
redirect request_token.authorize_url
end

get '/callback' do
client = get_oauth_client
begin
access_token = client.authorize(
session[:request_token],
session[:request_token_secret],
oauth_verifier: params[:oauth_verifier]
)
user = client.verify_credentials
"hi #{user["screen_name"]}"
rescue Exception => e
e.message
end
end
end
スポンサーサイト

rubyのhttpclientでslackに投稿

Ruby2.4にしたらgemのslack-apiが古いjsonを参照してbundle installに失敗しました。
そこでhttpclientを使って投稿してみようと思います。
WebhookとAPIで実装してみました。

Webhook版
require 'httpclient'
require 'json'

client = HTTPClient.new

content = {
channel: '#general',
username: 'aoyagi',
text: 'hi'
}

url = "https://hooks.slack.com/services/xxxxxxxxx"

p client.post_content(url, payload: content.to_json)


API版
require 'httpclient'

client = HTTPClient.new

content = {
channel: '#general',
username: 'aoyagi',
text: 'hello',
token: "xxxxxxxxxxx"
}

url = "https://slack.com/api/chat.postMessage"

p client.post_content(url, content)

開発中にDBに一括で登録するスクリプト

開発中には、以下ような感じでSQLファイル等を分けて管理しています。

db
|- bin
|- erd
|- sql
|- 01schema.sql
|- 02data.sql
|- lib
|- uv_plpgsql.sql
|- ...
|- stored
|- ...
|- table
|- users.sql
|- ...

これを一括でDBに登録するのがめんどくさいです。
なのでスクリプト書きました。
vi bin/config.yaml

default: &default
psql: /usr/bin/psql
base: ../sql
db_host: localhost
db_user: user
db_name: web_development
params:
- name: schema
path: 01schema.sql
command: c
- name: lib
path: lib/*.sql
command: l
- name: table
path: table/*.sql
command: t
- name: stored
path: stored/*.sql
command: s
- name: data
path: 02data.sql
command: d

development:
<<: *default

test:
<<: *default
db_name: web_test


vi bin/make_sql.rb

require 'optparse'
require 'tempfile'
require "yaml"
require "erb"

# ファイルを読み込む
def read_one(path, dst)
open(path) do |file|
dst.puts file.read
end
end

# ディレクトリの中のファイルを読み込む
def read_many(path, dst)
Dir::glob(path).each do |f|
read_one(f, dst)
end
end

# パラメーターをパースする
def parse(params)
ary = []
all = []
params.each do |param|
all << param["command"]
ary << "-#{param["command"]} : #{param["name"]}"
end
ary << "-e : 環境名"
ary << "-#{all.join("")} : all"
[ary.join("\n"), all.join("") + "e:"]
end

# コマンドを生成する
def make_command(environment, file)
"#{environment["psql"]} -h #{environment["db_host"]} -U #{environment["db_user"]} #{environment["db_name"]} < #{file.path}"
end

#
# 処理本体
#

# コンフィグを読み込む
config = open("./config.yaml") do |f|
::YAML::load(::ERB.new(f.read).result)
end

# エラーメッセージと全てのパラメーター取得
error_message, all_parameters = parse(config["development"]["params"])

# 引数が空の時は終了
if ARGV.empty?
puts error_message
exit 0
end
params = ARGV.getopts(all_parameters)

# 環境が無い場合は終了
if params["e"].nil? || "" == params["e"]
puts error_message
exit 0
end

environment = config[params["e"]]
base = environment["base"]

Tempfile.open('makesql') do |file|
targets = environment["params"]
targets.each do |target|
# コマンドが選択されているものだけ処理する
if params[target["command"]]
path = "#{environment["base"]}/#{target["path"]}"
if /\*/ =~ target["path"]
read_many(path, file)
else
read_one(path, file)
end
end
end
file.close
command = make_command(environment, file)
system(command)
end


以下のように実行します。
ruby make_sql.rb -cltsd -e development

RailsでProxy経由の接続で本当のIPアドレスを取得する

WAFなどのプロキシーを通した時にRailsでは発信元のIPを取得することができなくなります。
その対応方法です。

プロキシーのIPアドレスを
1.2.3.4
5.6.7.8
の2つとします。
またAWSのELBではプライベートアドレスで接続してくるので、それも追加しています。

まず、nginxがRailsの前にいる場合はそれから設定します。

set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 127.0.0.1/32;
set_real_ip_from 1.2.3.4/32;
set_real_ip_from 5.6.7.8/32;
real_ip_header X-Forwarded-For;

次にRails側です。
vi config/application.rb
config.action_dispatch.trusted_proxies = /(^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.)|(1\.2\.3\.4)|(5\.6\.7\.8)/

RailsではIPアドレスの正規表現で設定します。

RailsでPostgreSQLのストアードプロシージャの例外コードを受ける

PostgreSQLのストアードプロシージャで例外を出した時に、素のままではRailsではエラーコードが受け取れません。
RailsというかRubyのpgというドライバーがデフォルトでは受け取らないようになっています。
pgを直接扱っている場合には、簡単に設定できるのですがRailsでは一苦労いります。
initializersにドライバーと例外に手を入れるコードを書きます。

vi config/initializers/stored_procedure.rb

require 'active_record/connection_adapters/postgresql_adapter'

module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
alias :base_configure_connection :configure_connection
def configure_connection
base_configure_connection
@connection.set_error_verbosity(PG::PQERRORS_VERBOSE)
end
end
end
end

module PG
class Result
def error_code
error_message[8..12]
end
end
end


使い方は以下の通り。

def index
begin
TestModel.find_by_sql(["SELECT * FROM test_get_list_data(p_id := :id", {id: 1}])
rescue => e
Rails.logger.debug(e.original_exception.result.error_code)
Rails.logger.debug(e.original_exception.result.error_message)
end
end


例外eはActiveRecord::StatementInvalidのインスタンスでoriginal_exceptionに本当の例外PG::ServerErrorを持っています。
PG::ServerErrorはPG::Resultのインスタンスresultを持っていて、ここのエラーコードが含まれています。
エラーメッセージは以下の通りです。

ERROR: U0001: error occerd p_id=1
LOCATION: exec_stmt_raise, pl_exec.c:3068

アプリケーションとしてはエラーコードだけ欲しいので、PG::Resultに手を入れて
error_codeでメッセージだけを取るようにメソッドを追加しています。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。