sky’s 雑記

評価経済やコミュニティの密化にブロックチェーンなどの技術で対抗するエンジニアの雑記

有名なGemのソースコードを読んで仕組みを理解する Pundit編

rails向けの権限管理GemにPunditっていうものがあるんですが、 いい感じに権限周りの記述を1ファイルにまとめられて見通しの良いGemだなと感じたので、 ソースコードを読んでみました。

pundit (2.0.0) github.com

簡単な説明

使い方の説明記事ではないのでざっと書くと、 各リソースに対してPolicyというテンプレートファイルを内で権限をメソッド単位で定義できるというもの。

たとえばHoge.rbの権限を設定したかったらApplicationControllerでPunditをincludeしたあとに、

class ApplicationController < ActionController::Base
  include Pundit
end

Policyファイルを作って

class HogePolicy
  def show?
    #ここにHogeリソースの閲覧権限を書く。
  end

  .
  .
  .
end

使うときは

class HogeController
  def show
    authorize @hoge
  end
end

みたいな感じに、 if current_user hoge みたいな条件分岐記述が分散せず1箇所にまとめられて見通しがよくなる。

Gemの中身の概要

中身は結構シンプルでコアは以下の2つのファイル

pundit/pundit.rb at master · varvet/pundit · GitHub

pundit/policy_finder.rb at master · varvet/pundit · GitHub

アプリケーションとGemのインターフェースは先述の通り authorize メソッドで、 これはPunditモジュールに定義されているのでアプリケーション側でincludeすると利用できるようになる。

リソースとポリシーの紐づけはauthorizeメソッドとPolicyFinderクラス内のfindメソッドで行っている。シンプルなアプリケーションであれば権限管理したいリソースのオブジェクトのみをauthorizeの引数として渡すことが多いと思うが、query つまり権限設定に利用するメソッドと policy_class 権限設定が記述されているクラスをカスタマイズできる。デフォルトでは query"#{action_name}?" であり、 policy"#{klass}#{SUFFIX}" となる。

https://github.com/varvet/pundit/blob/master/lib/pundit.rb#L202

def authorize(record, query = nil, policy_class: nil)
    query ||= "#{action_name}?"

    @_pundit_policy_authorized = true

    policy = policy_class ? policy_class.new(pundit_user, record) : policy(record)

    raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)

    record
  end

pundit/policy_finder.rb at master · varvet/pundit · GitHub

def find(subject)
    if subject.is_a?(Array)
      modules = subject.dup
      last = modules.pop
      context = modules.map { |x| find_class_name(x) }.join("::")
      [context, find(last)].join("::")
    elsif subject.respond_to?(:policy_class)
      subject.policy_class
    elsif subject.class.respond_to?(:policy_class)
      subject.class.policy_class
    else
      klass = find_class_name(subject)
      "#{klass}#{SUFFIX}"
    end
end

以上でリソースとポリシーの紐づけが済むので、

raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)

で、HogePolicyの該当アクションを実行することで権限がfalseであれば NotAuthorizedErrorを流せるというわけだ。

非常にシンプルである。

ちなみに

本題とは若干それるが、スコープごとに権限管理を行う対象(user)やポリシーファイル自体もカスタマイズできるようで policy, pundit_policy_scope, pundit_user のオーバーライドが可能なようだ。このあたりActiveSupport::Concern とかhelper_methodで動的に実現しているのもrubyらしいのかなと思いなかなか興味深かった(普段java/kotlinみたいな静的な言語を書くことが多いので尚更)

included do
  helper Helper if respond_to?(:helper)
  if respond_to?(:helper_method)
    helper_method :policy
    helper_method :pundit_policy_scope
    helper_method :pundit_user
  end
end

課金周りのテーブル設計について

とあるサービス開発に携わっていて課金周りの実装に悩ましさを抱えている。

具体的には 課金ユーザーが持つcustomer_idをどのようにもたせるかということだ。 toCのサービスであればユーザー=課金ユーザーなのでuserテーブルにcustomer_idを付与すればいいと思うんだが、 今回はユーザー単位の場合もあれば会社単位の場合もある、といった具合。

脳死状態で実装するとすればcompanyテーブルにcustomer_idがあり、userテーブルにもcustomer_idがあるみたいな感じになるんだが、 これはcustomer_idが点在してるのが微妙だなーと思う。

設計的には中間テーブルでcustomerテーブルとつなぐのが丸い。 companies - company_customers - customers users - user_customers - customers 的な具合。

設計的にはこれでいいんだが実はまだ問題はあって、 userがcompanyに属する場合だ。 この場合以下のようなことを検討する必要があるかなと思う。

  • userとcompanyが同じものを課金する可能性があるか
  • userとcompanyの二重課金を許可するか
  • 課金側は何をもって課金ユーザーを一意に特定するか(たとえばemailで一意に特定する場合、サービス側でuserとcompanyが同じemailを持っていたらどうなるかなど)

なにはともあれ外部の課金サービスでAPI叩いている場合などは、 自分のサービス側で課金情報を適切に保持してしっかりとsyncすることがまずは重要かなと思う。

頼まれごとを断る勇気と決意

人にお願いされると断るのが苦手で損をすることを何度か経験してきた。

だから頼まれたら断れないけど損もしたくないということで、 そもそも土俵に乗らない、つまり頼まれない状況を意図的に作ってきた。

だがこれって逆を返すとこっちからのお願いもやりにくくなるということでもある。 ビジネスはgive&takeかつ交渉であり相手の要求と自分の要求をすり合わせる必要があるからだ。

ということで相手と交渉をすることをこれからは頑張っていくことにした、 自分の要求を通すために相手の要求を飲むし必要であれば交渉するし断る。

結構勇気いるのよねこれって。。。

だが俺は自分のキャリアのために一歩踏み出す。

【Ethereum】Dapps開発で前提となるEthereumネットワークについて

f:id:iwsksky:20180814025638p:plain

中央集権型のアプリケーション同様に、 分散型アプリケーションであるDappsにもデプロイという作業が存在します。

中央集権型のアプリケーションを開発したことがある方であれば、 開発はlocalhostにサーバーを立てて行い、 本番であればクラウドにサーバーを立ててデプロイを行うといった工程が想像できると思います。

ですがDappsをどのようにEthereumネットワークにデプロイするか想像がつかないのではないでしょうか。

この記事ではDapps開発をする上で知る必要があるEthereumネットワークの種類について解説します。

1. プライベートネットワーク

gethのcliやganacheで起動されるネットワークはこのプライベートネットワークにあたります。 一個人により管理されるEthereumネットワークであり、中央集権型のネットワークと言い換えることができるかもしれません。 自由にEtherの発掘を行うことができ閉じたネットワークであるためDappsのテストといった開発用とに適したネットワークと言えます。

2. テストネットワーク

プライベートネットワークとは異なり複数のノードにより管理されるネットワークです。 主要なネットワークとしては以下のようなものがあります。

Ropsten

TESTNET Ropsten (ETH) BlockChain Explorer

もっともEthereumネットワークに近いテストネットワークと言われています。 合意形成アルゴリズムはPoWです。

Ropstenネットワークは2016年運用開始でにストックホルムの駅名から名付けられました。

2017年にはDoS攻撃を受けてGas代が上がるといったこともあったようですが、 現在ではもっとも有力なテストネットワークといって良いと思います。

Ethereum Test network – Coinmonks – Medium

Ropsten testnet is under kind of attack? What can we do? - Ethereum Stack Exchange

ropsten/revival.md at master · ethereum/ropsten · GitHub

# Pros
  • メインネットと同様の環境でありDappsのテスト環境としては最有力
  • geth/parity両方とも利用可
  • Etherの発掘可

Ethernet Faucet

# Cons
  • 前述の通りDosのようなスパム攻撃を受ける可能性がある。
Kovan

Parityチームによりサポートされるテストネットワークです。 こちらは2017年4月運用開始でシンガポールの駅名から名付けられました。

# Pros
  • Etherのサプライが信頼できる機関により管理されているため、スパム攻撃に強い
# Cons
  • geth利用不可
  • Etherの発掘不可
  • 合意形成アルゴリズムがPoSでありメインネットと環境が異なる
Rinkeby

Gethチームによりサポートされるテストネットワークです。 こちらも2017年4月運用開始でストックホルムの地下鉄の駅名から名付けられました。

# Pros
  • Etherのサプライが信頼できる機関により管理されているため、スパム攻撃に強い
# Cons
  • gethのみ利用可能
  • Etherの発掘不可
  • 合意形成アルゴリズムがPoSでありメインネットと環境が異なる

3. メインネットワーク

開発者目線では本番環境のネットワークであり、Ethereumや一般公開されているDappsはメインネットワーク上で動いています。 2015年7月より運用開始。

メインネットに接続する · Ethereum入門

【Ethereum/solidity】ゼロから始めるDapps開発

ブロックチェーン周りの技術は日進月歩で発展しているので、 1年前の情報でも既に使い物にならないということも多い。

この記事ではブロックチェーン未経験のエンジニアが、 Ethereumを利用したアプリケーション(Dapps)を開発するとき、 何をすればよいかまとめていく。

ちなみに私は業務ではRailsウェブアプリケーション、kotlinでandroidアプリなどを開発している、 エンジニア歴としては5年程度なのでマイルストーンとして参考にしてほしい。

1. CryptoZombies

cryptozombies.io

Dapps開発にはsolidityというjavascriptライクな言語を用いる。 このsolidityの文法からクライアント側との連携まで網羅的に学ぶことができるのがCryptoZombiesである。 講座はLesson1から6まで存在しており、はじめは初歩的なsolidity文法から学ぶことになる、 若干退屈感は否めないがところどころ中央集権型のアプリケーションには存在しない、 ブロックチェーン特有の言語概念が存在するので是非CryptoZombiesに取り組むことをおすすめする。

ちなみにCryptoZombiesもまたLoomNetworkを利用したDappsである。

2. Pet Shop Tutorial

Truffle Suite | Tutorials | Ethereum Pet Shop -- Your First Dapp

solidityに慣れDappsの概要がつかめるようになったら、 より詳細なDapps開発の生態系を知りたくなるはずだ。 だがCryptoZombiesを終えただけでは、 Dappsを開発しようと思ったときどうしてよいかわからないということになると思う。

Pet Shop Tutorialでは、 ローカルでブロックチェーンを利用できるGanacheやDappsフレームワークであるtruffleを用いて、 実際にペットをethで購入できるアプリケーションの開発を行う。

Pet Shop Tutorialを終えると自分の作りたいDappsがあったとき何すればよいのか、 具体的な道筋が頭の中に思い描けるレベルになっているはずだ。

終わりに

簡単にDapps開発が行えるようになるまでにやることを紹介したが、 私もまだ初心者なので逐一記事の更新を行っていこうと思う。

メンタルが弱っているとき、楽になるための方法

昨日久々に結構でかい波が来てメンタルがやられたんだが、 以下3点意識すると良い。 普段から意識している部分ではあるんだが、 改めて有効だと思ったのでメモメモ。

参考にする人は、上から順に行動をとっていってほしい。

1.忘れる

忘れるといっても簡単に忘れられるものでもないのでひたすら寝る。 俺の場合昨日は帰ってから何もせずに20:00から翌日12:00(昼)くらいまで寝てた。 やっぱ起きている限りどうしても考えすぎちゃうのでね。

ここの項目書いていて思ったけど、 裁量労働じゃなかったらひたすら寝続けるってできないな、 ガチのブラック企業に勤めている人って本当につらいんだろうな。

2.逸らす

思考の対象を逸らす。 悩んでいる事象以外に1個くらい興味があるものがあると思うのでそれについて深掘りする。 落ち込みが激しいときは逸らそうと思っても簡単には逸らせるものではないので、 前述の通り、1回寝てから逸しにかかると良い。

3.向き合う

悩みの原因となっているものと向き合う。 ただいきなりこれをやるのはリスクが高いので、 前述の2つのプロセスを踏んでから行う。 意外とつまらないことで悩んでいたとか、向き合うことで改善することも結構あるので、 どん底は脱したなと思ったときにやると事態が良い方向に向かうことがある。

コミット対象がない人生について

恋人や家族がいたり、 仕事に打ち込んだり、 没頭できる趣味があったり、 たいていの人は何かにコミットして人生を過ごしてると思うんだけど、 今俺にはそれがなくて虚無感がすごい。

それなりの給料をもらって楽しくない仕事をしている状態。

毎年1つ何か新しいことを始めるとこの退屈から開放されるらしい、 そういえば今年個人事業主登録したっけな。

人生をかけてコミットしたいと思えるものがほしいなぁ、 会社でも作るか。

anond.hatelabo.jp