ベルリンのITスタートアップで働くジャバ・ザ・ハットリの日記

日本→シンガポール→ベルリンへと流れ着いたソフトウェアエンジニアのブログ

エンジニアの集合知をノードグラフで図解するSNSサイトを作った。「ノード・ノード・ノード(デスクトップ版)」

サイトコンセプトはエンジニアの集合知をノードグラフにして図解するSNS。
サイト名は「node-node-node(ノード ノード ノード)」。デスクトップ版のみ。

エンジニアの集合知をノードグラフで図解するSNS。
「node-node-node(ノード ノード ノード)」
 https://www.node-node-node.com/


考えたのは「新しい技術を学ぶ時に各技術要素の関係が分かりにくい。ググればピンポイントで内容が分かるが各技術の関係は不明なまま。そこを集合知を使ってシステムが自動的に図に示してしてくれればいいのに」と。

トップページはこれ。

f:id:tango_ruby:20180205184519p:plain

親ノードについた子ノードはパラっと開いて、グリグリとドラッグできる訳でして、こうして階層構造の技術リンクをマッピングしていけば理解しやすいかな、と。

f:id:tango_ruby:20180205204551g:plain


例えば私の専門はバックエンドなのでインフラやバックエンドの処理はそれなりに把握しているが、JavaScriptをはじめとするフロントエンドの知識はあまり無い。今回のnode-node-nodeのフロントエンドはReact+Reduxで作っていて、その技術情報を手探りで集めてコードを書いた。するとフロントエンドの専門家なら常識でも、専門外の人からは謎な用語がポンポン出て来る。

npm, Babel, webpack, ES2015, Enzyme、とか。

これらの用語についてはググればヒットするし、一応は分かる。仮にnpmがナニなのか知らなかったとしても、ググれば一瞬で分かる。それでも本当に分からないのはこれらの技術要素の関係。各々の技術については分かったつもりになっても、npmとES2015はどんな関係なのか。それぞれ把握しておかなければならないのか、その技術の関連性はずごくあるのか、またはまったく無いのか、などだ。

ここでは誰もがよく知る技術用語だけをピックアップしたので「そんなもん分かるだろ」と思われたかもしれないが、以下のサッカー戦術用語の場合はどうだろう?

トータルフットボール、ゼロトップ、ミケルス、オフザボール、ポゼッションサッカー、ゲーゲンプレス、4−4−2、ゾーンプレス、アリーゴ・サッキ

これらの用語の相互関係が頭の中に描ける人はある程度サッカーに詳しい人だろう。サッカーに詳しくない人でも、用語をググれば分かる。でも各用語が分かったとしても現在のサッカーシーンの主流戦術や、今までの歴史を俯瞰した概念はなかなか得られない。
そこは「各要素の関係図」を示してもらえれば分かるし、初学者が学ぶ際に役に立つ、というのが本サービスのコンセプト。

これはRailsに必要な技術をマインドマップに示した図。分かりやすいが、そもそもこれを作ったのはきっとRailsのエキスパート。
f:id:tango_ruby:20180205030352p:plain:w400

こういうのはひとりのエキスパートに頼るよりも、ネット文化に添って集合知を結集して自動作成されるようにしたかった。「人気のあるノード=有用なノード」として目立つ場所に出てくるようにした。

例えばJavaScriptはこんな感じ。
f:id:tango_ruby:20180205205225p:plain
そもそもJavaScriptの初学者はフレームワークとしてReactやらAngularJSがあって、それらがJavaScriptである、ということから理解する必要がある。で、このノードのつながりを見れば一目瞭然かな、と。

早くたくさんの人に使っていただいて、もっといろんなノードが付いて欲しいなーとか思ったりしている。


モバイル版を無視して、デスクトップ版しか出さないのはいかがなものか、というご指摘もあるかもしれないが、基本的にPCでコードを書くエンジニアに向けたサービスなのでご了承ください。とにかく公開してその後のサービスの使われ方を見て変更をかけていくつもり。

ご自身が書いた技術記事が有用だと思う方や、他の人が書いた役に立つ技術記事をご存知の方は、ぜひその記事リンクを貼ったノードを作っていただけますでしょうか。
原理的にはどこまでもスクロールできるほぼ無限大に大きなノードグラフができる。
いつの日か考えもしなかったような巨大な集合知のノードグラフがnode-node-nodeにできていることを願って公開した。


使った技術
個人的にはGraphQLがこのサービス内容に対しては最適だったな、と。
料金はドメイン登録料だけで他は無料で済ませることができた。GCPの永年無料枠サイコー。

Front-end

  • React
  • Redux

Back-end

  • Ruby 2.5
  • Rails
  • GraphQL

Infra

  • Google Cloud Platform
  • heroku
  • MongoDB
  • Redis
  • Cloud flare
  • SendGrid
  • NewRelic

エンジニアの集合知をノードグラフにして図解するSNS。
「node-node-node(ノード ノード ノード)」
 https://www.node-node-node.com/

良くても悪くても賞賛でも罵倒でもなにかコメントか反応いただければ嬉しいです。反応ゼロが一番辛い。。。

Rails 5 モデルの条件付きbefore_destroy

Rails 5 でモデルに条件付きbefore_destroyを設定する方法。

例えばPostモデルがあって、レコードを消す前に条件判定をするとする。ステータスがアクティブだったら消さない。アクティブ以外の場合だけレコードを消してもOkとしたい。

そこで以下のようなコードを書いても動かない。

class Post  < ApplicationRecord

  before_destroy :do_not_destroy_active_post

  private

  def do_not_destroy_active_post
    return false if active?
  end
end

 
どうすればいいのかはここ(Active Record Callbacks)に書いてある。
 

If the before_validation callback throws :abort, the process will be aborted and ActiveRecord::Base#save will return false. If ActiveRecord::Base#save! is called it will raise an ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.

動くコードはこんな感じになる。

class Post  < ApplicationRecord

  before_destroy :do_not_destroy_active_post

  private

  def do_not_destroy_active_post
    throw(:abort) if active?
  end
end

エラーメッセージを加えたければ、throw(:abort)をする前にerrors.addすればできる。

ほとんどお約束みたいなことで、現行のプロジェクトを検索してみたらたくさんthrow(:abort)が引っかかるが、全てこの条件付きbefore_destroyだった。私自身の経験としてもこれ以外でthrow(:abort)を使ったことが無いのだが。。。

結論としてはthrow(:abort)したらOkってことなんだけど、他の技術ブログでRails4からの歴史的経緯とか長々と書いてあって「ググってこういう記事に辿り着いた人ってそんなゴチャゴチャと昔話しまで求めてないのでは」と思ったので簡素に結論だけ書いて終わりにしたい。

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

Rails 5.1のwebpack (gem無し)を使ってReact, Redux, Material-UIの環境構築

RailsのViewをReactにする場合のお手軽な環境構築としては少し前ならreact-railsやreact_on_railsといったGemを使って統合していた。それもRail 5.1になってGem無しでもカンタンに環境構築が可能になった。もちろんGemを使えばそれらに付随する機能が使えて便利な面もあるが、「無しでもカンタンにできる」というのはありがたい。またRail標準としては「これからJavaScriptフォルダ配下のpackにReact関連コードを置きます」とかやられると、一応Rails標準というものを知っておいた方がよさそう。
ということでRails 5.1のwebpack (gem無し)を使ってReact, Redux, Material-UIの環境構築を書いた。

$ ruby -v
ruby 2.3.3
$ rails -v
Rails 5.1.1
$ npm -v
4.0.5

railsのバージョンが5.1であることを確認した後、rails newを--webpack=react指定で実行する。
実行後の出力結果を見るとwebpacktやらyarnがあることが分かる。

rails new myapp --webpack=react
 :
 :
Using rails 5.1.1
Using sass-rails 5.0.6
Bundle complete! 17 Gemfile dependencies, 71 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
       rails  webpacker:install
Copying webpack core config and loaders
      create  config/webpack
      create  config/webpack/configuration.js
 :
 :
$ brew upgrade yarn
success Saved 562 new dependencies.
├─ abbrev@1.1.0
├─ acorn-dynamic-import@2.0.2
├─ acorn@5.0.3
├─ ajv-keywords@1.5.1
 :
 :
yarn add v0.23.4
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...

フォルダ構成が以下のようになっている。これからはapp/javascript/packs配下に入れるのが標準とのこと。

app/javascript
└── packs
    ├── application.js
    └── hello_react.js

packsに入っているhello_react.jsはこのように単純なReact component。
単にHello Reactと出力しているだけ。早速これを使って動作を確認してみる。

import React from 'react'
import ReactDOM from 'react-dom'
class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.name}!</div>
  }
}
document.addEventListener("DOMContentLoaded", e => {
  ReactDOM.render(<Hello name="React" />, document.body.appendChild(document.createElement('div')))
})

サンプルの動作を見るために以下のコマンドでpages controllerを作る。

bundle exec rails g controller pages index

pagesのindex.html.erbに javascript_pack_tag を追記する。

# app/views/pages/index.html.erb

<h1>Pages#index</h1>
<%= javascript_pack_tag 'hello_react' %>

javascript_pack_tag のロードを有効にするため webpack-dev-serverの設定をdevelopment.rbに記載。

# config/environments/development.rb

Rails.application.configure do
 :
 :
  config.x.webpacker[:dev_server_host] = "http://127.0.0.1:8080"
end

サンプルの動作を確認するためrails サーバーを立ち上げる。

bundle exec rails server

別のターミナルから以下のコマンドを実行しwebpack-dev-serverを立ち上げる。つまりrails sserverだけではサンプルを見ることができない。

./bin/webpack-dev-server --host 127.0.0.1
  :
  :
  [164] ./app/javascript/packs/application.js 515 bytes {1} [built]
  [266] multi (webpack)-dev-server/client?http://127.0.0.1:8080 ./app/javascript/packs/application.js 40 bytes {1} [built]
     + 70 hidden modules
webpack: Compiled successfully.

ここでローカルホストの以下のページにアクセスする。Hello Reactが見えたら無事に動いていることになる。
http://localhost:3000/pages/index

f:id:tango_ruby:20170515051616p:plain


この時点ではReactが入っているだけでRedux, Material-UIがまだ入っていない。
以下のコマンドで入れる。

npm install --save redux
npm install --save react-redux
npm install --save-dev redux-devtools
npm install --save material-ui
npm install --save react-tap-event-plugin

コマンド実行後にpackage.jsonを確認すると以下のようにインストールされていることが分かる。

{
  "name": "myapp",
  "private": true,
  "dependencies": {
    "autoprefixer": "^7.0.1",
    "babel-core": "^6.24.1",
    "babel-loader": "7.x",
    "babel-preset-env": "^1.4.0",
    "babel-preset-react": "^6.24.1",
    "coffee-loader": "^0.7.3",
    "coffee-script": "^1.12.5",
    "compression-webpack-plugin": "^0.4.0",
    "css-loader": "^0.28.1",
    "extract-text-webpack-plugin": "^2.1.0",
    "file-loader": "^0.11.1",
    "glob": "^7.1.1",
    "js-yaml": "^3.8.4",
    "material-ui": "^0.18.1",
    "node-sass": "^4.5.2",
    "path-complete-extname": "^0.1.0",
    "postcss-loader": "^2.0.5",
    "postcss-smart-import": "^0.7.0",
    "precss": "^1.4.0",
    "prop-types": "^15.5.10",
    "rails-erb-loader": "^5.0.0",
    "react": "^15.5.4",
    "react-dom": "^15.5.4",
    "react-redux": "^5.0.4",
    "react-tap-event-plugin": "^2.0.1",
    "redux": "^3.6.0",
    "sass-loader": "^6.0.5",
    "style-loader": "^0.17.0",
    "webpack": "^2.5.1",
    "webpack-manifest-plugin": "^1.1.0",
    "webpack-merge": "^4.1.0"
  },
  "devDependencies": {
    "redux-devtools": "^3.4.0",
    "webpack-dev-server": "^2.4.5"
  }
}

以降はReduxやらMaterial-UIを使ってコードを書く。そこは長くなりそうなので書くとしても別記事にする予定。

結果としてはこんな感じでよくあるMaterial-UI風のページができあがる。個人的にはBootstrapは飽きたのでMaterial-UIがいいと思っている。フォーム押したときの下線がヒューっと出る動作とかが気持ちいい。

f:id:tango_ruby:20170516005313p:plain

tango-ruby.hatenablog.com
tango-ruby.hatenablog.com
tango-ruby.hatenablog.com