はじめに
皆さん、カスタマーサクセスしてますか?価値あるプロダクトを作っていますか?
日々自分たちのカスタマーがより良い活動をできるよう、プロダクトを開発・運用しているかと思いますが、活動の中でのヒューマンエラーを無くす動きも大切です。
カスタマーサクセスの為に、検証作業も含め、頻繁にカスタマーとデータのやり取りをする場合(例: 提案資料、データの受け渡し...)、うっかりミスが致命的な問題につながり兼ねません。
メールやFBで気軽に連絡できる時代において、ヒューマンエラーによる情報漏えいはかなり大きな割合を占めております。
カスタマーのより良い活動を支援しようと思ったのに・・・、その活動がサービスの停止へと導いてしまった、、、なんて事があったら悲しすぎますね。
そんなミスを防ぐ為に、今日はアプリケーション内でファイルをDLする機構を作ることで、セキュアな環境下でのやり取りを実現してみたいと思います。
イメージ図
実装
サーバ側
- asw-sdk
- Rails・ruby
まずは、AWS側の設定を記述します。
Aws.config.update({
credentials: Aws::Credentials.new(
#ACCESS_KEY,
#SECRET_ACCESS_KEY
),
region: #region情報を
endpoint: #endpoint情報を
})
# もし参照パスにルールがあるなら記述しておきます
module AwsS3
BUCKET = 'test'.freeze
BASIC_URL = "https://s3.console.aws.amazon.com/s3/object/#{BUCKET}".freeze
end
ベースのモデルを作成。
class S3Client
def initialize(*_)
@client = Aws::S3::Client.new
end
end
まずはS3にあるファイルを引っ張ってくる処理。
例えばログインしているユーザに応じて、S3のパスを分けます。
class S3Reader < S3Client
def initialize(user)
super
@user_id = user.id
end
def prefix
"#{Rails.env}/#{@user_id}/"
end
def objects
contents = @client.list_objects(bucket: AwsS3::BUCKET, prefix: prefix).contents
contents.map { |content| S3Reader::Object.new(content, prefix) }
end
end
# objectの加工用
class S3Reader::Object
attr_reader :key, :name, :modified_at
def initialize(content, prefix)
@key = content.key
@name = content.key.gsub(prefix, '')
@modified_at = content.last_modified
end
end
controller側に下記を実装。するとS3からDL可能なObjectが引っ張られてきて表示されます。
class DownloadFilesController < ViewBaseController
def index
s3 = S3Reader.new(@current_user)
@objects = s3.objects.sort_by(&:modified_at)
end
end
S3にアップロードしたファイルが・・・
アプリケーション側でも閲覧可能に。
引っ張るところまで出来れば次はクリック後、DLできるようにします。
DLの方法としては、一定時間だけオブジェクトにアクセスできるURLを作成し、send_dateをすることで、ブラウザ側にDLされるようにします。
参照)
一定時間だけS3のオブジェクトにアクセスできるURLを生成する
class S3Downloader < S3Client
# 一時的なURLは120秒に設定
def download_url(key)
Aws::S3::Presigner.new(client: @client).presigned_url(
:get_object, bucket: AwsS3::BUCKET, key: key, expires_in: 120
)
end
def content(key)
S3Downloader::Object.new(open(download_url(key)), key)
end
end
class S3Downloader::Object
attr_reader :content, :key
def initialize(content, key)
@content = content
@key = key
end
def name
@key.split('/').present? ? @key.split('/')[-1] : 'download'
end
def read
@content.read
end
# ファイルの種類によってはsend_date時に上手くcontent_typeが出せない場合があるので、オーバーライドしておく
def type
@content.content_type
end
end
後は、リストをクリックした際のアクションをController側に実装。
class DownloadFilesController < ViewBaseController
def index
s3 = S3Reader.new(@current_user)
@objects = s3.objects.sort_by(&:modified_at)
end
def download
downloader = S3Downloader.new
content = downloader.content(params[:key])
send_data content.read, filename: content.name, type: content.type
end
end
これらを実施し、クリックすると・・・
無事DLができました。
最後に
今回は第1弾ということで、まずはファイルをDLできる機構を作ってみました。
ログインすることでDLできるので、カスタマーには、『サービス内にアップロードしたので、DLしてくださいね。』と伝えるだけでいけますね。
ヒューマンエラーを出来る限り排除し、価値にフォーカスできる体制をつくるのもプロダクト開発において非常に重要だと感じています!
第二弾はこの機構に自動でファイルをアップロードしていく仕組みを構築します。
これで活用レポートだったり、定期的に送るデータは自動化してしまいましょう。