20190323のRailsに関する記事は14件です。

フルリモートで開発している会社で使用しているツール

はじめに

私は普段リモートワークで開発しているのですが、会社全体リモートを数ヶ月間する機会があり潤滑に業務を行えていました。色々な会社の方とお話しする機会があるのですが、リモートワークを導入してもうまく機能せず、廃止したという話をよく耳にします。働き改革やエンジニア不足が進む現在において、リモートワークが世に広がるために貢献できれば良いな、という気持ちを込めて記事を書かせていただきます。
尚、Railsを使用した自社サービスの開発を行なっております。

ツール

GitHub

言わずも知れたコードのやり取りをできるツール。

AWS

言わずも知れたクラウドサーバ。

slack

ベースとしてやり取りに使用しているチャットツールです。
業務内容もそうですが雑談も多くすることが重要です。
作業はWorking out loudですることがおすすめ。
他のツールと連携し、通知先に設定しておくと他の人の作業やサービスの問い合わせを検知でき便利。

esa

ドキュメントを書き溜めるツール。
仕様やアイデアなどを書き溜めています。

Qiita team

こちらもドキュメントを書き溜めるツールではあるのですが、esaは開発チーム・Qiitaは会社全体と使い分けています。

pivotal tracker

タスク管理ツール。スクラムで使用しています。

Trello

ボードでタスクを管理するのに使用しています。

Lastpass

社内で使用している共有パスワードを管理しているツール。

G Suite

様々な会社で使用していて、自身の経験上gmailを使用している会社ではどこも使っています。

Realtimeboard

現在はmioに変更されたが、URLはrealtimebordのまま。
オンラインで同期的にボードを共有できるサービス。物理的にワークショップを開いているのと近い感覚でアイデアなどの出し合いをできます。
私的に一押しのツールです。

Zoom

今勢いのあるビデオチャットツール。録画することも可能で、MTGに参加できないメンバーもあとで録画を確認することで議事録とは違った形で非同期にMTGを共有することができる。

sentry

エラー通知サービス。Webサービスに組み込み定期的にエラーの棚卸しをすることで既存のバグを調査することができます。

intercom

CS部門とのやりとりで便利。

他社で使っていた時に有効だと感じたツール

Remotty

ソニックガーデン製のツール、常にカメラで顔を写しあたかもオフィスにいるようにやり取りをすることができる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

current_userの↓説明できる?

これって元々どうなってたの?

app/helpers/sessions_helper.rb
def current_user
    @current_user ||= User.find_by(id: session[:user_id])
end

っていうかこれどう動いてたんだっけ?

Lv.1 if文

if @current_user.nil?
  @current_user =  User.find_by(id: session[:user_id])
else
  @current_user =  @current_user
end

Lv1.1 asmさんからご提案頂きました。

@current_user = if @current_user.nil?
                  User.find_by(id: session[:user_id])
                else
                  @current_user
                end

「移り変わり」感がよりイメージしやすくなりましたね。

Lv.2 三項演算子

名前でビビりますね。

@current_user = @current_user.nil? ? User.find_by(id: session[:user_id]) : @current_user

これにリファクタリングできたらかっこいいけど…

Lv.3 or 演算子 「 || 」

@current_user = @current_user || User.find_by(id: session[:user_id])
                 ②  ①

@current_userが無ければ(nil)なら、User-を代入
②userと||のスキマ
 @current_userが存在すれば、@current_userの値はそのまま。

Lv3.5 大前提

n = n + 1
n += 1

同じ意味でしたね。

Lv.4 自己代入演算子 「||=」

@current_user ||= User.find_by(id: session[:user_id])
           ①

①Lv.3.5の
 nが@current_userの立場

まとめ

いきなりif文から「||=」までは難しい。
条件によりけりですが、Lv.2までは大体リファクタリングできる。
今回がかなり特別。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails DM 2019 登壇者の影響を受けた3冊まとめ (day.2)

すごいRailsエンジニアの方々がどんな書籍を読んで今に至るのか、またどんな本が人気なのか?をもとに、もっと高みを目指そうということで、Ruby on Rails 2019の冊子で紹介された、

「影響を受けた3冊」

をリスト形式で掲載。途中で力尽きて、著作名のみになっている点はご了承ください。

イベントについて:
Ruby on Rails 2019 3/22~23 開催
https://techplay.jp/event/714867

Day 1の登壇者の方々 はこちら

https://qiita.com/shogotgm/items/adece25dd5ac16fcb7cf

Day 2の登壇者の影響を受けた3冊まとめ

@ moro

・UNIXという考え方-その設計思想と哲学
・テスト駆動開発入門
・エクストリームプログラミング

@ taiki-t

・オブジェクト指向設計 実践ガイド Rubyでわかる進化しつづける柔軟なアプリケーションの育て方
・イシューからはじめよ -知的生産のシンプルな本質
・Rails Tutorial

@ masa-iwasaki

・達人プログラマー 職人から名匠への道
・ライト、ついてますか -問題発見の人間学
・OSの基礎と応用 - 設計から実装、DOSから分散OS Amoebaまで

@ willnet

・ウェブ進化論 本当の大変化はこれから始まる
・RailsによるアジャイルWebアプリケーション開発
・パーフェクトRuby on Rails

@ fujimura

・RailsによるアジャイルWebアプリケーション開発
・The Little Schemer
・言語哲学大全

@ kokuyouwind

・マッチ箱の脳(AI)-使える人工知能のお話
・プログラムはなぜ動くのか 知っておきたいプログラムの基礎知識
・数学ガール

@ koichiroo

・入門 GNU Emacs
・JavaからRubyへ
・達人プログラマー 職人から名匠への道

@ idesaku

・達人プログラマー 職人から名匠への道
・アジャイルな見積もりと計画づくり ~ 価値あるソフトウェアを育てる概念と技法 ~
・ライト、ついてますか - 問題発見の人間学

@ koic

・オブジェクト指向スクリプト言語 Ruby
・達人プログラマー 職人から名匠への道
・エクストリームプログラミング

@ radioboo

・初めてのPerl
・アジャイルソフトウェア開発の奥義
・ねぼけ人生

@ risacan

・Practical Object-Oriented Design in Ruby
・プログラムはなぜ動くのか 知っておきたいプログラムの基礎知識
・Namluby pana Pipi

@ joker1007

・ジョジョの奇妙な冒険
・アジャイルサムライ - 達人開発者への道
・パーフェクト Ruby

@ f440

・Agile Web Developmet with Rails
・エンタープライズ Rails
・ウェブオペレーション - サイト運用管理の実践テクニック

@ yoshuki

・コンサルタントの秘密 - 技術アドバイスの人間学
・ハッカーと画家 コンピュータ時代の創造者たち
・Ruby on Rails 携帯サイト開発技法

@ unak

・闘うプログラマー
・プログラミング技法
・達人プログラマー 職人から名匠への道

@ ikedaosushi

・イシューからはじめよ - 知的生産のシンプルな本質
・CAREER SKILLS ソフトウェア開発者の完全キャリアガイド
・ハッカーと画家、コンピュータ時代の創造者たち

@ komagata

・プログラミングPerl
・ピープルウエア
・人月の神話

@ bany

・Rubyist Magazin 出張版 正しいRubyコードの書き方講座
・JavaScript The Good Parts
・UNIXという考え方 -その設計思想と哲学

@ shinamon129

・Flash&ActionScript3.0 プロが教える本当の使い方
・ツイッターで学んだいちばん大切なこと
・エラスティックリーダーシップ 自己組織化チームの育て方

@ yasaichi

・テスト駆動開発
・ハッカーと画家、コンピュータ時代の創造者たち
・問題発見プロフェッショナル

@ knu

・アスキー「256倍使うための本」
・プログラミングPerl
・C言語による標準アルゴリズム事典

@ mtsmfm

・メタプログラミングRuby
・アジャイルサムライ - 達人開発者への道
・Rails によるアジャイルWebアプリケーション開発

@ pipopotamasu

・開眼!JavaScript - 言語仕様から学ぶJavaScriptの本質
・やさしいJAVA
・アメリカの少年野球 こんなに日本と違ってた

@ hokaccha

・ユニバーサルHTML/XHTML
・ハイパフォーマンス Webサイト -高速サイトを実現する14のルール
・初めてのRuby

@ hanachin

・ハッカーと画家 コンピュータ時代の創業者たち
・情熱プログラマー ソフトウェア開発者の幸せな生き方
・フリーソフトウェアと自由な社会

@ katsumata-ryo

・たのしいRuby
・SCRUM BOOT CAMP THE BOOK
・落下する夕方

@ k0kubun

・たのしいC
・たのしいRuby
・きつねさんでもわかる LLVM

@ 284km

・ジョジョの奇妙な冒険 Part5 黄金の風
・ジョジョの奇妙な冒険 Part3 スターダストクルセイダース
・ジョジョの奇妙な冒険 Part7 スティール・ボール・ラン

@ sinsoku

・JAVA言語で学ぶデザインパターン入門
・アジャイルソフトウェア開発の奥義 オブジェクト指向開発の真髄と匠の技
・レガシーコード改善ガイド

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails DM 2019 登壇者の影響を受けた3冊まとめ (day.1)

概要

すごいRailsエンジニアの方々がどんな書籍を読んで今に至るのか、またどんな本が人気なのか?をもとに、もっと高みを目指そうということで、Ruby on Rails 2019の冊子で紹介された、

「影響を受けた3冊」

をリスト形式で掲載。途中で力尽きて、著作名のみになっている点はご了承ください。

イベントについて:
Ruby on Rails 2019 3/22~23 開催
https://techplay.jp/event/714867

Day 2の登壇者の方々 はこちら

https://qiita.com/shogotgm/items/f074fe85c285e02a2027

Day 1の登壇者の影響を受けた3冊まとめ

@ dhh

・The Manual: A Philosopher's Guide to Life (Epictetus, Sam Torode)
・Escape from Freedom (Erich Fromm)
・Punished by Rewards (Alife Kohn)

@ takahashim

・ひとめあなたに… (新井 素子)
・心のなかの冷たい何か (若竹 七海)
・計算機プログラムの構造と解釈 (Gerald Jay Sussman, Julie Sussman, Harold Abelson)

@ jeremy

・How to Solve It (George Poyla)
・Calvin and Hobbes (Bill Watterson)
・The Overcoat (Nikolai Gogol)

@ onk

・影響力の武器 (ロバート・B・チャルディーニ)
・バクマン。 (大場 つぐみ・小畑 健)
・大東京トイボックス (うめ)

@ youchan

・あすなろ物語 (井上 靖)
・路上 (ジャック・ケルアック)
・聖書

@ kei-p, @ gotchane

・UNIX という考え方 (Mike Gancarz)
・プログラマが知るべき 97のこと (和田 卓人)
・リーダブルコード (Dustin Boswell)

@ yoshinori

・プログラマの数学 (結城 浩)
・情熱プログラマー (Chad Fowler)
・テスト駆動開発 (Kent Beck)

@ yahonda

・Head First Rails(David Griffiths)
・遠い太鼓 (村上 春樹)
・Oracle Database 概要 (Oracle Docs)

@ tawachan

・限界費用ゼロ社会 (ジェレミー・リフキン)
・社会契約論 (J.J ルソー)
・ブロックチェーンアプリケーション開発の教科書 (篠原航、 加嵜長門)

@ hsbt

・Rubyのしくみ (Pat Shaughnessy)
・Crafting Rails Applications (Jose Valim)
・アジャイルサムライ (Jonathan Rasmusson)

@ upinetree

・アジャイルサムライ (Jonathan Tasmusson)
・たのしい開発 スタートアップRuby (大場寧子、大場光一郎、他)
・リーダブルコード (Dustin Boswell)

@ itkrt2y

・Simple is not easy
・TOYOTA KATA
・Ruby on Rails Tutorial

@ rust

・四次元の世界 - 超時空から相対性理論へ (都筑 卓司)
・はじめの一歩を踏み出そう - 成功する人たちの起業術 (マイケル・E・ガーバー)
・逆境ナイン (島本 和彦)

@ yancya

・たのしい Ruby (高橋 征義、後藤 裕蔵)
・SQL アンチパターン (Bill Karwin)
・CPUの創りかた (渡波 郁)

@ m-nakamura145

・マスタリング TCP/IP 入門編
・やさしい C++
・珠玉のプログラミング 本質を見抜いたアルゴリズムとデータ構造

@ mrkn

・C言語による最新アルゴリズム事典 (奥村 靖彦)
・プログラミング言語 C++ (Bjarne Stroustrup)
・ご冗談でしょう ファインマンさん (Richard P. Feynman)

@ takatoshi-maeda

・メタプログラミング Ruby (Paolo Perrotta)
・イシューからはじめよ (安宅 和人)
・リーン・スタートアップ (Eric Ries)

===(ここからは著作名のみです...)===

@ riho

・夜と霧
・オブジェクト指向でなぜつくるのか
・ライト、ついてますか - 問題発見の人間学

@ nay

・Effective Java
・RailsによるアジャイルWebアプリケーション開発
・アドラー心理学入門

@ takkanm

・たのしいRuby
・情熱プログラマー ソフトウェア開発者の幸せな生き方
・Clean Coder プロフェッショナルプログラマへの道

@ ota42y

・情熱プログラマー ソフトウェア開発者の幸せな生き方
・理科系の作文技術
・ゲーデル、エッシャー、バッハーあるいは不思議の環

@ ujihisa

・UNIXという考え方 - その設計思想と哲学
・発酵の技法 - 世界の発酵食品と発酵文化の探求
・How to Become A Hacker

@ owlworks

・UNIXという考え方 - その設計思想と哲学
・予想どおりに不合理: 行動経済学が明かす「あなたがそれを選ぶわけ」
・ザ・ゴール - 企業の究極の目的とは何か

@ katorie

・初めてのプログラミング
・Webを支える技術 - HTTP, URI, HTML, そしてREST
・パターン、Wiki、XP ~ 時を超えた創造の原則~

@ yui-knk

・Ruby ソースコードで完全解説
・はじめての OSコードリーディング
・ディジタル回路設計とコンピュータアーキテクチャ ARM版

@ aeroastro

・人工衛星の力学と制御ハンドブック - 基礎理論から応用技術まで
・詳解 Linuxカーネル
・Goならわかるシステムプログラミング

@ taogawa

・リファクタリング - プログラムの体質改善テクニック
・Java言語で学ぶデザインパターン
・山椒魚戦争

@ kyuden

・パーナムピアノ教本シリーズ

@ r7kamura

・初めてのPerl
・初めてのRuby
・Patterns of Enterprise Application Architecture

@ Morred

・Practical Object-Oriented Design in Ruby: An Agile Primer
・Letters from a Stoic
・Pippi Longstocking

@ amatsuda

・Rails3 レシピブック 190の技
・HEAD FIRST RAILS
・たのしいRuby

@ emorima

・プログラミング言語 C
・深い河
・はみだしっ子

@ siman-man

・たのしいRuby
・プログラミングコンテストチャレンジングブック
・メタプログラミング Ruby

雑なまとめ:「たのしいRuby」はいい本

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング学習記録35〜道場コースをCloud9で〜

今日やったこと

  • ProgateのRailsで作ったアプリをCloud9で再現する

Progateで作ったTwitterっぽいアプリを道場コースの手順に従って、Cloud9で動かすことを試みました。

なんとか道場コース1の7まではうまくできました。

Progateではターミナルが最初からtweet_appがホームポジションになっていますが、Cloud9のターミナルでは自分でtweet_appまで移動する必要があります。

ついProgateのノリでやってしまい、何回かこれでミスしてしまいました。

あと、ミスした時にProgateだとどこがミスしているかわかりやすく教えてくれますが、Cloud9ではProgateほど丁寧にミスの場所を教えてくれません。

なので、'が1つ足りなかったり、/が抜けてたりして起こったエラーに気づくのに時間がかかりました。

このあたりまだまだ実践が足りてないですね。

データベースもProgateのようにわかりやすくチェックするページがないので、ターミナルでチェックしなければならないようです。

一応やり方を調べてみて、railsのレファレンスサイトにある手順でsqliteに入っているデータを見てみたのですが、思ってたのと違いました。

カラムごとにわかりやすく表示させたいですね。

明日はデータベース(テーブル)の確認方法を調べて、道場コースに従い、tweet_appを作っていきたいと思います。

おわり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] TwitterAPI(omniauth-twitter)とdeviseを使用して新規登録(サインアップ)できないとき

問題

deviseとomniauth-twitterを使ってTwitterログインできるようにしようと
各種設定を行ったが、新規登録をするとエラーが発生してしまう。

自分はmodels/user.rbにはこのような記述をした

models/user.rb
  def self.from_omniauth(auth)
    find_or_create_by(provider: auth[:provider], uid: auth[:uid]) do |user|
      user.uid = auth[:uid],
      user.provider = auth[:provider],
      user.username = auth[:username]
    end
  end

その結果、新規登録ボタンを押しても

  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."provider" = ? AND "users"."uid" = ? LIMIT ?  [["provider", "twitter"], ["uid", "伏せますね"], ["LIMIT", 1]]
   app/models/user.rb:9
   (0.0ms)  begin transaction
   app/models/user.rb:9
   (0.0ms)  rollback transaction

とロールバックしてしまい登録できない。


原因

原因はすぐにわかった。
Userモデルには、Twitter登録用にuid, provider, usernameという3つの
カラムを登録したが、それとは別に通常ログイン用の emailpasswordカラムもある。
rails g devise:model User時に自動設定されるはず)


てことはemailpasswordにはvalidationが設定されているため、
uid, provider, usernameと一緒にemail, passwordにもvalidationを
満たすような値を設定しなければならない。


解決策

email, passwordにダミーの値を入れて解決した。

models/user.rb
#  def self.from_omniauth(auth)
#    find_or_create_by(provider: auth[:provider], uid: auth[:uid]) do |user|
#      user.uid      = auth[:uid],
#      user.provider = auth[:provider],
#      user.username = auth[:username],
      user.email    = self.dummy_email(auth),       #emailにダミーを設定する
      user.password = Devise.friendly_token[0, 10]  #passwordに適当な値を設定する
#    end
#  end

  private

  def self.dummy_email(auth)
    "#{auth[:username]}_#{auth[:uid]}@example.com"
  end

ちなみに

userが一人も登録されていないとする。

user.rbuid, provider, usernameだけ設定してTwitterでログインしようとすると、
登録失敗後、uid, provider, usernameがキャッシュされる場合がある。

その場合、その後に(通常の)新規登録画面で、emailpasswordを入力して新規登録すると、
フォームで設定された値によってはuid, providerm usernameがキャッシュされたまま
id=1のユーザとして登録されてしまう
ので、注意が必要。

つまり、uid, provider, usernameで登録(失敗)して、
それとは別にemail, passwordで登録したはずなのに
uid, provider, username, email, passwordをもつuserが作られてしまうということ。



登録後にコンソールでUser.all打って確認する必要がありそう。。



おわり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] deviseのセッション(session)はどのように決められているのか

deviseが作成したsessionはどれだ?

devise/lib/devise/controllers/helpers.rb
https://github.com/plataformatec/devise/blob/40f02ae69baf7e9b0449aaab2aba0d0e166f77a3/lib/devise/controllers/helpers.rb

l.123
 def #{mapping}_session
   current_#{mapping} && warden.session(:#{mapping})
 end

helpers.rbの123行目には
#{mapping}_sessionとすればそのセッションを見ることができる
ということが書いてある。
(mappingは今はuserと考えておけば良い)

user_sessionを入力すると、

[16] pry(#<TopController>)> user_session
=> {"last_request_at"=>1553329704}

が返ってくる。

ちなみに先ほどのメソッドの内容から、warden.session(:user)としても同様。

[15] pry(#<TopController>)> warden.session
=> {"last_request_at"=>1553329704}

また、 session.keysと入力すると

[18] pry(#<TopController>)> session.keys
=> ["session_id", "flash", "warden.user.user.key", "warden.user.user.session"]

と返ってくるが、 session["warden.user.user.session"]としても同様に同じセッションが帰ってくる。

[19] pry(#<TopController>)> session["warden.user.user.session"]
=> {"last_request_at"=>1553329704}

てなると気になるのは、

このsessionのHashはどこで設定されているのか?

という点。

まずは wardensessionというメソッドらしきものがあるかを確認する。

warden/lib/warden/proxy.rb
https://github.com/wardencommunity/warden/blob/b7ff0f4ffacd7ad5a9b5a0191f1da0c7a64b2c2c/lib/warden/proxy.rb

l.244
  def session(scope = @config.default_scope)
    raise NotAuthenticated, "#{scope.inspect} user is not logged in" unless authenticated?(scope)
    raw_session["warden.user.#{scope}.session"] ||= {}
  end

warden/proxy.rbの244行目にsessionメソッドがあった。
ここには先ほど3番目に確認した "warden.user.user.session"という名前の命名についてのルールが書かれてある。
sessionのHashのルールについては書かれていないが、これもこれで勉強になる。



では肝心のHashについてはというと、

devise/lib/devise/hooks/timeoutable.rb
https://github.com/plataformatec/devise/blob/master/lib/devise/hooks/timeoutable.rb

l.31
  unless env['devise.skip_trackable']
    warden.session(scope)['last_request_at'] = Time.now.utc.to_i
  end

timeoutable.rbの31行目に答えが書いてあった。

Hashのkeyである last_request_atは、手入力で決められたもので、
valueは UTCでの現在時刻という変数だった。


お勉強になりました

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで使える環境変数を管理できるgem(dotenv-rails)や.envの導入方法

はじめに

DBのパスワードなどの設定は、PCというか開発環境ごとに異なることが多いです。ですが、Railsを利用して共同開発する場合、database.ymlなどに、DBに関する設定をそのまま定数に記入すると、ある特定の環境でしか動かなくなるでしょう。また、そういうデータは、GitHubのようなオンラインのホスティングサービスに公開したくないものです。

そこで、環境に依存する設定値を環境変数として扱って、どんな開発環境のDB設定値でも柔軟に対応できるgem(dotenv-rails)を使って管理して見ましょう。

環境

  • macOS HighSierra 10.13.6
  • Rails 5.2.0
  • Ruby 2.5.1
  • mysql 5.7.22
    • mysqlはdockerに作成
  • Docker version 18.03.1-ce

導入方法

Gemfileに以下を記述

gem 'dotenv-rails'

そして、書きを実行することで、gemを インストール

$ bundle install

環境変数を設定

top of your application に、.envファイルを作成。

例えばこんな感じ。

.env
RAILS_MAX_THREADS = 5
DATABASE_HOST = 127.0.0.1
DATABASE_USER = test
DATABASE_PASSWORD = test
DATABASE_NAME = my_project

すると、rails cで確認できるようになります。

irb(main):002:0> ENV['RAILS_MAX_THREADS']
=> "5"
irb(main):003:0> ENV['DATABASE_HOST']
=> "127.0.0.1"
irb(main):004:0> ENV['DATABASE_USER']
=> "test"

環境変数の利用法

database.yml
・・・

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: <%= ENV.fetch("DATABASE_HOST") { "127.0.0.1" } %>
  username: <%= ENV.fetch("DATABASE_USER") { "test" } %>
  password: <%= ENV.fetch("DATABASE_PASSWORD") { "test" } %>
  database: <%= ENV.fetch("DATABASE_NAME") { "my_project" } %>

・・・

これで使えるようになります。

こうすれば、環境ごとに異なる設定値でも.envに記述すれば、実行環境が異なっても使えるようになります。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル 第六章

はじめに

railsチュートリアルで理解しにくいところや、詰まったところを書いていく記事になります。
なので、手順を示す記事とはなっていません。

データベースの構造の確認

Userモデルを生成し、db:migrateコマンドを打つとdb/development.sqlite3という名前のファイルが生成される。↓

$ rails generate model User name:string email:string
$ rails db:migrate

通常はDB Browser for SQLiteというツールを利用しデータベースの構造の確認ができるが、今回僕はcloud9(クラウドIDE)を使っているので、ファイルをダウンロードし、Spliceというアプリを使ってデータベースの構造を確認することができた。

便利!!

サンドボックス

$ rails console --sandbox

↑のようなコマンドを打つと、コンソールをサンドボックスで起動することができる。

起動すると以下のようなメッセージがでる。
Any modifications you make will be rolled back on exit

ここで行ったすべての変更は終了時にロールバックされます

ということで、データベースを変更せずにコンソールを使いたい場合はサンドボックスモードにするといい。

ユーザーオブジェクトを更新

いったん作成したオブジェクトを更新したい場合はupdate_attributesメソッドを使うといい。

例:

user.update_attributes(name: "The Dude", email: "dude@abides.org")

update_attributesメソッドは属性のハッシュを受け取り、成功時には更新と保存を続けて同時に行う。
保存に成功すれば、trueを返してくれる。

バリデーションとテスト駆動開発

バリデーションとテスト駆動開発は相性が良く まず失敗するテストを書き、次にテストを成功させるように実装すると、期待した通りに動いているかを確認することができる。

例:

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
  end
end

setupメソッド@userを定義しておく。
setupメソッドの中の書かれた処理は各テストが走る直前に実行される。

@user.nameを空白にし、assert_notメソッドを使うことで有効性を確認できる。

まだ、validatesをかけていなければテストはREDになる。

以下のようにすることで、テストはGREENとなる。

app/models/user.rb
validates :name,  presence: true

メールの正規表現

email属性の場合は、有効なメールアドレスかどうかを判定するために、もっと厳重な要求を満たさなければらない。
空のアドレスに対してvalidatesするだけではなく、
user@example.com
にフォーマットが合っているかを確認する必要がある。
以下にそのテストを載せる。

例:
有効なメールアドレス

test/models/user_test.rb
test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
end

無効なメールアドレス(,があったり、@がない)

test/models/user_test.rb
test "email validation should reject invalid addresses" do
    invalid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                           foo@bar_baz.com foo@bar+baz.com]
    invalid_addresses.each do |invalid_address|
      @user.email = invalid_address
      assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
    end
end

assert @user.valid?, "#{valid_address.inspect} should be valid"
により、どのメールアドレスでテストが失敗したかわかるようにする。

このテストをGREENにするなら以下のようなvalidatesが必要になる。

app/models/user.rb
class User < ApplicationRecord
  #空白と長さに対するvalidatesを含む
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }
end

他にも一意性を持たせないといけないが割愛。

セキュアなパスワード

セキュアパスワードという手法では、各ユーザーにパスワードとパスワードの確認を入力させ、それを (そのままではなく) ハッシュ化したものをデータベースに保存する。

ユーザーの認証は、パスワードの送信、ハッシュ化、データベース内のハッシュ化された値との比較、という手順で進む。

比較するのは生のパスワードではなく、ハッシュ化されたもの同士である。

そのためにhas_secure_passwordというメソッドを利用する。

このメソッドはUSERモデル内で呼びだすことができる。

class User < ApplicationRecord
  .
  .
  .
  has_secure_password
end

モデルにこのメソッドを追加することで、

・データベース内のpassword_digestというカラムにハッシュ化したパスワードを保存
・passwordとpassword_confirmationの利用
・authenticateメソッドが使用

が可能になる。

このメソッドを使用するにはデータベースにpassword_digesというカラムを追加する必要がある。
(マイグレーションファイルを作り、changeメソッド内に処理を書き、マイグレートする)

また、bcryptをインストールしていない場合は、Gemfileに記述し、bundle installを実行しておく。

authenticateメソッド

ハッシュ化されたもの同士を比較するにはauthenticateメソッドを利用する。
引数の文字列がパスワードと一致すれば、Userオブジェクトを、間違っていればfalseを返す。

>>user.authenticate("not_the_right_password")
false
>> user.authenticate("right_password")
ユーザーオブジェクトが返される

おわり

第六章は、メインはユーザー登録に対するバリデーションとそれに対するテストだった。
ここも必須の行程になるだろうな。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

学習記録7 rails(5) 新たなルーティングの設定

2019/03/23 Ruby on rails の学習記録(5)です。

正直理解できているかでいうと怪しいですがとりあえず先に進みます。
 
 

今回の目標:

  • 「どんなリクエストをしたらどんなアクションが動くかを新たに設定する」

1.ルーティングの設定

config/routes.rb
(例)
Rails.application.routes.draw do
  get 'test' => 'sample#index'

  get 'test/new' => 'sample#new'
  # 「test/new」パスを受け取ったら「sample」コントローラの「new」アクションを処理する
  post 'test' => 'sample#create'
  # 「test」パスを受け取ったら「sample」コントローラの「create」アクションを処理する
end

2.コントローラの設定

app/controllers/sample_controller.rb
(例)
class SampleController < ApplicationController

  def index
    @samples = Sample.all
  end

  def new
  end
  # newメソッドを設定する

  def create
    Sample.create(sample_params)
  end

  private
  def sample_params
    params.permit(:name, :image, :text)
  # createメソッドで作成するレコードに保存する値をparamsメソッドでフォームに入力された値にする

end

3.ビューの設定

  • あるコントローラのアクションに対応するビューは、アプリケーション内のapp/views/コントローラ名いかに、アクション名.html.erbという名前で作成する。

フォーム

  • フォームとは、ユーザーが情報を入力し、その情報をサーバーに送信するためのもの
  • HTMLのコードの中にform要素を作成し、その中にフォームを構成するための部品のinput要素やtextarea要素を配置することで作成する。
  • Railsではセキュリティの観点からHTMLのformタグだけで作成したフォームを使用することは推奨されない。
  • Railsでフォームから情報を送信するためにはform_tagを始めとするヘルパーメソッドを使用する。
app/views/samples/new.html.erb
(例)
<div class="contents row">
  <%= form_tag('/samples', method: :post) do %>
  <!-- 第一引数「/samples」はformの送信ボタンを押した際のリクエストのパス
       第二引数「method: :post」は送信ボタンを押した際のリクエストのhttpメソッドをpostにするという書き方 -->

    〜中略〜

  <% end %>
</div>

HTTPメソッド

HTTPメソッド 役割
get ブラウザからサーバーへ「サーバーからブラウザに固有の情報を返す」ように命令する。単にウェブサイトを閲覧する際にはこのメソッドを利用する。
post ブラウザからサーバーに「ある情報」を送信するためのもの。情報の登録などの際、サーバーに情報を送信するために利用される。

params

  • ビューでフォームに入力された情報は、コントローラにキーと一緒にパラメーターとして送られる。
  • このパラメーターはparamsというメソッドを使うことで取得できる。
  • paramsメソッドを使用する際にはparams[:キー名]という形で使用する。
    • params[:name]
    • params[:image]
    • params[:text] など

ストロングパラメーター

  • ストロングパラメーターとは、指定したキーを持つパラメーターのみを受け取るようにするもの。
  • 仮に悪意のあるユーザーが、不正な情報を送信した時にストロングパラメーターを設定しておくことで不正な情報を受け取らずに済む。

privateメソッド

  • classの内部でprivateとソースコードに書くと、それ以降に定義したメソッドはclassの外部から呼び出せなくなる。
  • メリット(1) classの外部から呼ばれたら困るメソッドを守ることができる。
    • メソッドの中にはclassの外部から呼び出されてしまうとエラーを起こすメソッドも存在するため、そのような事態を事前に防ぐことができる。
  • メリット(2) 可読性
    • classの外部から呼び出されるメソッドを探すときにprivate以下の部分は目を通さなくてよくなる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails server から flaskサーバーに値を送り、そのまま返す処理

動機

rails でサーバー関係を勉強していたところ、railsでデータを取得して
python側で処理をして返すシステムを実装するための基礎を学びたかったから

1.flask serverを立てる

ーflsk_app
 |ーapp.py

$ cd flask_app
$ python app.py

2. python code

試行錯誤した結果、request.form でrails からpostしたものを受け取る。ということにたどり着いた。

app.py
from flask import Flask, render_template, request,jsonify

app = Flask(__name__)

@app.route('/',methods=["GET","POST"])
def hello():
    #request.form でrails からpostしたものを受け取る。
    return jsonify(request.form)
if __name__ == "__main__":
    app.run(debug=True)

3. rails code

uri = URI.parse("送りたいサーバー側のURL")
res=Net::HTTP.post_form(uri, 送りたいデータ)
送りたいデータはJSON形式(=辞書の形?)
res.bodyで値を取り出す。

ser.rb
require 'net/http'
require 'json'
require 'uri'
uri = URI.parse('http://127.0.0.1:5000/')
#第2引数にHashを指定することでPOSTする際のデータを指定出来る
res = Net::HTTP.post_form(uri, { "q"=>'ruby'})
#puts res.code
puts res.body

[メイン参照]

1.Ruby 2.6.0 リファレンスマニュアル
(https://docs.ruby-lang.org/ja/latest/library/net=2fhttp.html)

2.はじめての Flask #2 ~POSTを受け取ろう~
(https://qiita.com/nagataaaas/items/3116352da186df102d96)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでのenumの使いどころと使い方について

enumとは

  • 日本語で列挙型
  • 値に意味をもたせてわかりやすくする
  • 不正な値を入れないようにする
  • Railsではモデルで使う

今回はRailsを使います。Rubyで同じようなことはできるようですが、enumとしての機能はRubyには用意されていないみたいです。

enumを使いたい状況

中身は何でもいいですが、ある処理があるとして、その処理の流れを
処理開始待ち(waiting)->処理開始(start)->処理中(processing)->処理終了(done)
という流れとします。
文字列型変数[progress]など作成してそのまま「waiting」とか「start」とか入れることもできますが、
数値型変数progressで管理すれば、進捗の進み具合を数値と比較して確認することもできます。
(progressが1より高ければ処理開始(satart)までは進んでいる、など)
ただし、数字で管理すると困ることがあります。それは
「あれ、1ってwaitingだっけ?startだっけ?」のように数字を見てその意味を忘れてしまうとコードを読むときに非常に読みづらくなります。

enumのかっこいいところ

そこでenumを使って数字に意味をもたせることで解決できるのです。上記の例に当てはめてみると
progressカラム(integer型)

  • waiting : 0
  • start : 1
  • processing : 2
  • done : 3

をそれぞれ紐づけます。すると、progressカラムにwaitingを入れたら実際にはprogressカラムに0がデータとして入ります。
人間絡みたら意味を持った文字を入れておきながら、DBでは数字で管理できるということです。

実際のコード

schema.rbの中身はこれです。
(taskモデルにinteger型のカラムprogressを追加しているだけ)

/db/schema.rb
ActiveRecord::Schema.define(version: 2019_03_23_024106) do
  create_table "tasks", force: :cascade do |t|
    t.integer "progress", default: 0
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
   end
end

app/models/task.rbの中身はこれです。
ここでenumを使い、単語と数値の紐づけを行っています。

/app/models/task.rb
class Task < ApplicationRecord
  enum progress: {
    waiting: 0,
    start: 1,
    processing: 2,
    done: 3
  }
end

動きを確認

まずはインスタンス作成

irb(main):001:0> task1 = Task.new
=> #<Task id: nil, progress: "waiting", created_at: nil, updated_at: nil>

マイグレーションファイルに定義しているとおり、デフォルトはwaiting

irb(main):010:0* task1.progress
=> "waiting"

progressに数値の1を代入するとstartとして認識されます

irb(main):029:0* task1.progress = 1
=> 1
irb(main):030:0> task1.progress
=> "start"

他のタスクとの進捗比較

もうひとつインスタンスを作成します。

irb(main):031:0> task2 = Task.new
=> #<Task id: nil, progress: "waiting", created_at: nil, updated_at: nil>

task1はtask2よりも進捗(progress)が進んでいるかの確認
数値として比較する場合は、メソッド[カラム名]_before_type_castが必要になるみたいです。

irb(main):080:0* task1.progress
=> "start"
irb(main):081:0> task2.progress
=> "waiting"
irb(main):082:0> task1.progress_before_type_cast > task2.progress_before_type_cast
=> true

感想

単語としても数値としても扱えるのは便利だけど数値として扱うときが若干めんどくさい。というかすげぇめんどくさい。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Stripeで定額制マーケットプレイスを実装する(rails)

名称未設定.001.jpeg

オンラインサロンや、月額駐車場のような定額制のマーケットプレイスを実装します。
前回、「RailsでStripe Connectを使ってみた」を投稿したのですが、この定額制の場合、そこにあるようなConnectだけでは一筋縄にいかないということが分かりました。定額制を採用するためには、「Stripe Billing」を別途で実装する必要があるため、StripeのGUIをそのまま使えるStandardアカウントでは実装できず、Customアカウントを使う必要が出てきました。

これが意外と厄介で、決済の責任がプラットフォーム側に依存されるようになるため、利用規約やセキュリティ面など気をつけなければならないことがたくさん出てきます。

決済〜入金までの流れ

  1. 決済フォームを作成する(Stripe Element)
  2. 本人確認フォームを作成する
  3. 銀行口座フォームを作成する
  4. 定額商品を作成する
  5. 顧客が定額商品を契約する
  6. プラットフォームからアカウントに送金される
  7. アカウントの口座に入金される

なかなか壮大なワークフローとなりました。
特に、7) プラットフォームからアカウントに送金される部分は想定しておらず、もっと簡単に実装できるかと思っていましたが、Webhookを使う必要があると分かりました。
個人的に、Webhookを使うのは初めてだったので、これはスタックしそうと構えていましたがngrockという便利ツールのおかげでスムーズに進みました。

決済フォームを作成する(Stripe Element)

決済フォームを作成する際にはStripe Elementを使うのがおすすめです。
基本的にクレジットカード情報はサーバー側で持たないため、Stripeのカスタマートークンを受け取るカラムのみをユーザーに追加してあげとけば問題ありません。

payments/new.html.erb
<script src="https://js.stripe.com/v3/"></script>

<%= form_for(@user, html: {class:'add-card', id: 'payment-form'}) do |f| %>
  <div class="block">
    <%= f.hidden_field :stripe_temporary_token, id: 'stripe_temporary_token' %>
    <input type="hidden" name="token" />          
    <div class="group">
      <label>
        <span>クレジットカード番号</span>
        <div id="card-number-element" class="field"></div>
      </label>
      <label>
        <span>有効期限</span>
        <div id="card-expiry-element" class="field"></div>
      </label>
      <label>
        <span>CVC</span>
        <div id="card-cvc-element" class="field"></div>
      </label>
    </div>
    <button type="submit" class="btn btnSubmit" id="submit-card">Submit</button>
    <div class="outcome">
      <div class="error"></div>
      <div class="success"></div>
    </div>
  </div>
<% end %>

JS部分は下記のようになります。

elements.js
var stripe = Stripe(gon.stripe_key);
var elements = stripe.elements();

var style = {
  base: {
    iconColor: "#666EE8",
    color: "#31325F",
    lineHeight: "40px",
    fontWeight: 300,
    fontFamily: "Helvetica Neue",
    fontSize: "15px",

    "::placeholder": {
      color: "#CFD7E0"
    }
  }
};

var cardNumberElement = elements.create("cardNumber", {
  style: style
});
if (document.getElementById("card-number-element")) {
  cardNumberElement.mount("#card-number-element");
}

var cardExpiryElement = elements.create("cardExpiry", {
  style: style
});
if (document.getElementById("card-expiry-element")) {
  cardExpiryElement.mount("#card-expiry-element");
}

var cardCvcElement = elements.create("cardCvc", {
  style: style
});
if (document.getElementById("card-cvc-element")) {
  cardCvcElement.mount("#card-cvc-element");
}

function setOutcome(result) {
  console.log("result", result);

  var successElement = document.querySelector(".success");
  var errorElement = document.querySelector(".error");
  successElement.classList.remove("visible");
  errorElement.classList.remove("visible");

  if (result.token) {
    // In this example, we're simply displaying the token
    successElement.querySelector(".token").textContent = result.token.id;
    successElement.classList.add("visible");

    // In a real integration, you'd submit the form with the token to your backend server
    //var form = document.querySelector('form');
    //form.querySelector('input[name="token"]').setAttribute('value', result.token.id);
    //form.submit();
  } else if (result.error) {
    errorElement.textContent = result.error.message;
    errorElement.classList.add("visible");
  }
}

cardNumberElement.on("change", function(event) {
  setOutcome(event);
});

cardExpiryElement.on("change", function(event) {
  setOutcome(event);
});

cardCvcElement.on("change", function(event) {
  setOutcome(event);
});

// Handle credit card form submission:
var paymentForm = document.getElementById("payment-form");
$("#submit-card").on("click", function(event) {
  event.preventDefault();
  stripe.createToken(cardNumberElement).then(function(result) {
    console.log("result", result);

    if (result.error) {
      // Inform the user if there was an error
      var errorElement = document.getElementById("card-errors");
      errorElement.textContent = result.error.message;
    } else {
      // Send the token to your server
      stripeTokenHandler(result.token);
    }
  });
});

これでUser情報が書き換わる時に、Stripeカスタマートークンを作成します。

users_controller.rb
・・・
if @user.stripe_temporary_token.present?
  customer = Stripe::Customer.create(
    email: @user.email,
    source: @user.stripe_temporary_token
  )
  @user.update_attribute(:stripe_customer_id, customer.id)
  flash[:success] = "クレジットカード情報が登録されました"
end
・・・

本人確認フォームを作成する

売り手側が入金を受け取るためには本人確認書類をStripeに提出する必要があります。個人で受け取る場合と、法人で受け取る場合にて入力する内容が異なります。ドキュメントを読んで確認していきましょう。

国内で本人確認するために必要な情報は下記を参考にしていきます。
https://stripe.com/docs/connect/required-verification-information

本人確認の画像を送る際には、JSを使って直接Stripeに送信しトークンを取得する必要があります。

accounts/new.html.erb
・・・
<div class="mainItem">
  <div class="label">
    <p>本人確認書類</p>
  </div>
  <div class="mainForm">
    <div class="inputFile">
      <div
        class="preview"
        style="background-image: url('../assets/img/verification.png')"
      >
        <input accept="image/*" id="id-file" name="id-file" type="file" />
      </div>
      <p class="btn_upload">
        アップロードする
      </p>
    </div>
  </div>
</div>
・・・
verification.js
// Handle verification from submission:
var verifyForm = document.getElementById("verify-form");
$("#submit-account").on("click", function(event) {
  event.preventDefault();
  this.innerHTML =
    "<i class='fa fa-spinner fa-spin'></i> アカウント情報を登録しています...";
  this.className += " disabled";

  function() {
    // Handle a file upload
    var data = new FormData();
    data.append("file", document.querySelector("#id-file").files[0]);
    data.append("purpose", "identity_document");

    $.ajax({
      url: "https://uploads.stripe.com/v1/files",
      data: data,
      headers: {
        Authorization: `Bearer ${gon.stripe_key}`
      },
      cache: false,
      contentType: false,
      processData: false,
      type: "POST"
    }).done(function(response) {
      var fileData = response.id;
      $("input[id=stripe_file]").val(fileData);
      verifyForm.submit();
    });
  });
});

※ コントローラー部分は決済フォームで実装したものとほぼ同じですので省略させていただきます。

銀行口座フォームを作成する

続いて、売り手側が入金を受け取る銀行口座を登録していくフォームを作成していきます。
こちらは本人確認書類で作成したStripe側のアカウントを呼び起こして、そこに銀行口座の情報を追加してあげるように実装を進めていきます。

こちらも本人確認書類と同じで、下記URLを参考にして必要な情報を取得します。
https://stripe.com/docs/payouts

本人確認書類や決済フォームと同じようにJSによってStripeと交信し、取得したトークンを既存のユーザーアカウントに追加します。

user_controllers.rb
・・・
if @user.stripe_bank.present?
  stripe_account = Stripe::Account.retrieve(current_user.stripe_account_id)
  stripe_account.external_account = @user.stripe_bank
  stripe_account.save
end
・・・

定額商品を作成する

このあたりは少し我流もあったのですが、定額商品には「商品」と「プラン」の二つの概念があります。例えば、一つの会社がAとB製品を持っているのであれば、それぞれにプランを持つことになりますよね。今回に関していえば、手入力でStripe側の商品をあらかじめ作っておいて、そこに紐づくプランをユーザーがアプリケーション側でプランを作成するたびに増えていくようにしました。
(これが、ユーザーが商品に対して幾つものプランを用意することを想定する場合は商品ごとユーザーが作る必要があるかもしれませんが、今回はユーザーは一つのプランに対して一つの価格設定を前提とします。)
スクリーンショット 2019-03-21 16.11.39.png

作成した商品のIDはクレデンシャルに書き込んで保存しておきます。
あと、プラン側はアプリケーション側が作成された時に一緒に作成するようにコントローラー側で仕込むだけです。

planc_controller,rb
  def create
    @community = current_user.plans.create(create_params)
    @community.community_id = "plan_#{@plan.id}"
    if @community.save
      Stripe::Plan.create(
        product:      Rails.application.credentials[Rails.env.to_sym][:stripe][:product_id],
        id:           @plan.community_id,
        currency:     'jpy',
        interval:     'month',
        nickname:     @plan.name,
        amount:       @plan.price,
      )
      flash[:success] = "We'll let you know when your community is approved."
      redirect_to current_user
    else
      flash[:alert] = "Faild to add a community."
      redirect_to current_user
    end
  end

顧客が定額商品を契約する

クレジットカード情報を持ったユーザーが定額商品を契約します。
これによって、ユーザーとプラットフォーム側が定期支払いによって契約が交わされることになります。
顧客情報と、プラン情報だけでなく、メタ情報としてプランを作成したアカウントのIDと、プラットフォーム側の手数料比率をここでいれておくのがポイントです。

subscriptions_controller.rb
・・・
def create
  @subscription = current_user.subscriptions.create(create_params)
  if @subscription.save
    @plan_id = "plan_#{@subscription.community.id}"
    stripe_subscription = Stripe::Subscription.create(
      customer: @subscription.user.stripe_customer_id,
      plan: @community_id,
      metadata: {
        destination: @subscription.user.stripe_account_id,
        commission_fee: "20"
      }
    )
    @subscription.stripe_subscription_id = stripe_subscription.id
    @subscription.save

    redirect_to current_user
  else
    redirect_to current_user
  end
end
・・・

プラットフォームからアカウントに送金される

顧客から受け取った金額をそのまま、アカウントに送金する必要があります。
そのためには、StripeのWebhookを使って、毎月なり支払いがある度に都度、アカウント側へ送金を行なっていきます。ngrockというサービスがWebhookのローカルでのテストでは非常に便利です。
Stripeにおけるngrockの設定は下記を参照にしてください。
https://qiita.com/kakipo/items/5d7325902965e74b3091

ngrokを設定したあとは、Stripeダッシュボードのテスト画面から配信ができるようになります。
ngrok.jpg

支払いが行われる度に、プラットフォームからアカウントへ自動送金処理を実装していきます。

Stripe.rb
Rails.configuration.stripe = {
  :publishable_key          => Rails.application.credentials[Rails.env.to_sym][:stripe][:publishable_key],
  :secret_key               => Rails.application.credentials[Rails.env.to_sym][:stripe][:secret_key],
  :account_signing_secret   => Rails.application.credentials[Rails.env.to_sym][:stripe][:account_signing_secret],
  :connect_signing_secret   => Rails.application.credentials[Rails.env.to_sym][:stripe][:connect_signing_secret]
}

Stripe.api_key = Rails.configuration.stripe[:secret_key]
StripeEvent.signing_secrets = [
  Rails.configuration.stripe[:account_signing_secret],
  Rails.configuration.stripe[:connect_signing_secret],
]

StripeEvent.configure do |events|
  # 請求に成功した場合の処理
  events.subscribe(
    'invoice.payment_succeed',
    Events::InvoicePaymentSucceed.new
  )
end
services/invoice_payment_succed.rb
class Events::InvoicePaymentSucceed
  def call(event)
    source = event.data.object

    # 送金処理を行なう
    subscription = source.lines.data[0]
    metadata = subscription.metadata
    commissionPercentage = metadata.commission_fee.to_i / 100
    commissionAmount = subscription.amount * commissionPercentage
    destinationAmount = subscription.amount - commissionAmount
    destinationAccount = metadata.destination

    transfer = Stripe::Transfer.create({
      amount: destinationAmount,
      currency: 'jpy',
      destination: destinationAccount
    })
  end
end

アカウントの口座に入金される

入金はStripeダッシュボード上より、手動入金と、自動入金(月に何日、週に何曜日)など選べるみたいです。
10,000円以上残高貯まらないとできないなど、実装でカスタマイズはできるみたいです。
今回はサブスクリプションなんで、一ヶ月定期でいいんじゃないかなと思って、とりわけ実装はしませんでした。
スクリーンショット 2019-03-22 19.11.17.png

やってみると、意外にも壮大になってしまいました。。
お金を取り扱うあたり、慎重にならなきゃいけないところもありますよね。銀行口座や、本人確認書類のバリデーションもフロント側で処理できるといいですよね。なんか良いライブラリあったら、教えて欲しいです。

実際、これやり切るのに、Stripeご担当者さまに幾度となく問い合わせしました。
すぐに、優しく応答してくれて、サービスも会社も素晴らしいなと感動でした!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CentOSにrbenvをインストールする

公式からcloneする。

$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv

必要な環境変数を追加し、読み込み直す。

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc

コマンドを打って確認。

$ rbenv --help
Usage: rbenv <command> [<args>]

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List installed Ruby versions
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme

installコマンドがない。ruby-buildがないからか。
ruby-buildをrbenvのplugins配下にインストールする。

$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

もう一回見てみる。

$ rbenv --help
Usage: rbenv <command> [<args>]

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   install     Install a Ruby version using ruby-build
   uninstall   Uninstall a specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List installed Ruby versions
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme

installとuninstallが追加されている。

ついでにruby(2.4.1)をインストールする。
時間はそこそこかかる。

$ rbenv install 2.4.1
Downloading ruby-2.4.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.bz2
Installing ruby-2.4.1...

BUILD FAILED (CentOS release 6.10 (Final) using ruby-build 20190320)

Inspect or clean up the working tree at /tmp/ruby-build.20190322234150.2287
Results logged to /tmp/ruby-build.20190322234150.2287.log

Last 10 log lines:
The Ruby openssl extension was not compiled.
The Ruby readline extension was not compiled.
The Ruby zlib extension was not compiled.
ERROR: Ruby install aborted due to missing extensions
Try running `yum install -y openssl-devel readline-devel zlib-devel` to fetch missing dependencies.

Configure options used:
  --prefix=/home/xxx/.rbenv/versions/2.4.1
  LDFLAGS=-L/home/xxx/.rbenv/versions/2.4.1/lib
  CPPFLAGS=-I/home/xxx/.rbenv/versions/2.4.1/include

失敗した。
openssl, readline, zlib
ここら辺がないようなのでyumでインストールする。

$ sudo yum install -y openssl-devel readline-devel zlib-devel

再度インストールする。

$ rbenv install 2.4.1
Downloading ruby-2.4.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.bz2
Installing ruby-2.4.1...
Installed ruby-2.4.1 to /home/xxx/.rbenv/versions/2.4.1

成功した。

$ rbenv global 2.4.1
$ ruby -v
bash: ruby: コマンドが見つかりません

ふむ…。

$ rbenv exec ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]

なるほど。

$PATHに$HOME/.rbenv/shimsを追加する。

$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]

無事行けたっぽい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む