20210908のNode.jsに関する記事は5件です。

TURNサーバーの動作をパケットをモニタリングして確認

試したこと AWSの異なるリージョンに webRTC のクライアントを設置 tcpdumpでパケットを確認して、 TURNサーバーが、パケットをリレーしていることを確認 環境 オファー側 AWS Region: Singapore Linux Ubuntu 20.04 node-webrtc データチャンネルで通信するサンプルを作成 *1 アンサー側 AWS Region: Ohio Linux Ubuntu 20.04 node-webrtc データチャンネルで通信するサンプルを作成 *1 TURNサーバー AWS Region: Tokyo Linux Ubuntu 20.04 Coturn-4.5.2 tcpdump version 4.9.3 データチャンネルで通信するサンプル(node-webrtc) *1 WebRTCのクライアントの設定 ブラウザのJavaScriptで実装する場合は、RTCPeerConnectionの第1引数に設定を渡す node-webrtc で実装する場合も、まったく同じなので、かなり実装が簡単 TURNサーバーの設定 const rtcPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "turn:{TURN Server Global IP}:{Port}", username: "username", credential: "password" } ] }); TURNサーバーの設定(ICE Candidatesのtypeをrelayだけにする)(必ずTURNサーバーを使うようになるはず) iceTransportPolicy: "relay" を指定 (2021/9/9 追記) const rtcPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "{TURN Server Global IP}:{Port}", username: "username", credential: "password" } ], iceTransportPolicy: "relay" }); STUNサーバーの設定(今回は無関係) const rtcPeerConnection = new RTCPeerConnection({ iceServers: [ { urls: "stun:stun.l.google.com:19302" } ] }); TURNサーバーのインストール バージョンなどのこだわりがなければ、apt でインストールできる 筆者は、ソースからビルドした sudo apt install coturn ソースコードからビルドする場合 テスト用にTURNサーバーの設定ファイルを編集(読み飛ばし可能) 起動時にコマンドのオプションとしても指定が可能なので、オプションで指定する場合は不要 設定ファイルの準備 /usr/local/etc/turnserver.conf.default にデフォルト設定があるので、リネームして適当な場所に保存 /etc/turnserver.conf に配置すると、自動で読み込んでくれそう(2021/9/9 パスが間違っていたので編集) 設定ファイルの設定項目 lt-cred-mech のコメントアウトを外して long-term credential mechanism を有効にする no-tls no-dtlsのコメントアウトを外して、TLSとDTLSを要求しないように設定 realm user listening-ip listening-port external-ip などを設定する user は、Static ユーザーアカウントを設定する、 long term credentials mechanism が有効のときに使える /etc/turnserver.conf # Uncomment to use long-term credential mechanism. # By default no credentials mechanism is used (any user allowed). # lt-cred-mech # Uncomment if no TLS client listener is desired. # By default TLS client listener is always started. # no-tls # Uncomment if no DTLS client listener is desired. # By default DTLS client listener is always started. # no-dtls # The default realm to be used for the users when no explicit # : # : realm=your_organization.jp # 'Static' user accounts for the long term credentials mechanism, only. # This option cannot be used with TURN REST API. # 'Static' user accounts are NOT dynamically checked by the turnserver process, # so they can NOT be changed while the turnserver is running. # user=username:password # TURN listener port for UDP and TCP (Default: 3478). # Note: actually, TLS & DTLS sessions can connect to the # "plain" TCP & UDP port(s), too - if allowed by configuration. # listening-port=3478 # Listener IP address of relay server. Multiple listeners can be specified. # If no IP(s) specified in the config file or in the command line options, # then all IPv4 and IPv6 system IPs will be used for listening. # listening-ip={Local IP} # For Amazon EC2 users: # # TURN Server public/private address mapping, if the server is behind NAT. # : # : external-ip={Global IP}/{Local IP} コマンド実行 設定ファイルを読み込む場合 必要に応じて、-v で Verbouseを指定してログを確認する /etc/turnserver.conf を利用 大文字のブイ-V にするとさらに詳細に確認できる(Extra verbose mode) Extra verboseにしてもパケットを受け取ったときにリレーする様子のログは表示はされないようだ sudo turnserver -v sudo turnserver -V 設定ファイルのパスを指定する場合(2021/9/9 編集) sudo turnserver -c /usr/local/etc/turnserver.conf 設定ファイルで設定しない場合(設定ファイルの項目を読み飛ばした場合) 手っ取り早くテストするならば、コマンドのオプションを指定した方が簡単 sudo turnserver --no-tls --no-dtls --lt-cred-mech -u username:password -r your_organization.jp -p 3478 -L {Local IP} -X {Global IP}/{Local IP} パケットの確認 tcpdump のインストール TURNサーバーのLinuxに tcpdump をインストールする sudo apt install -y tcpdump TURNサーバーのパケットのモニタリングのコマンド TURNサーバー上で、以下の tcpdump コマンドを実行 IPアドレスやポート番号でフィルタリングできるが 今回は、UDPでフィルタリングした(他にUDPのパケットが飛んでなさそうなので) sudo tcpdump udp シンガポールからのパケットが、 東京のTURNサーバーが受け取り USのオハイオにリレーする様子が確認できた 遭遇したエラーメッセージ 以下のエラーメッセージが出ていて、 本当にTURNサーバーが動いているか気になった 以下のリンクによると、ネゴシエーションのプロセスで、発生するとのことだが、理解を深める必要がある 44: : session 000000000000000001: realm <****> user <>: incoming packet message processed, error 401: Unauthorized 401 message is a legitimate message during negotiations. 感想 今回、TURNサーバーを設置して、 NAT配下にある、異なるリージョンにある、複数のEC2インスタンスでWebRTCの通信テストを行い、パケットをモニタリングして、TURNサーバーがパケットをリレーする様子を確認した リレーの負荷が高いと推測できるので、負荷対策などを今後、考えていく
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロジェクトの Yarn (v1.x) のバージョンを固定する(小ネタ)

結論 zsh % yarn policies set-version $(yarn -v) 動機 Yarn 1.x は速くて便利ですが、バージョンや環境の違いにより、yarn install が実行されると yarn.lock を書き換えてしまうことがあります。 git pull でコンフリクトが起きたりして地味に嫌です。 対策 その1: engines の指定と強制 .npmrc へ次のように指定すると、engines の設定を強制することができます。 .npmrc engine-strict=true また、 engines.npm へバージョン番号以外の文字列を指定すると、npm install は使えなくなります。 package.json { "engines": { "node": ">=12.13", "npm": "use_yarn_instead" } } zsh % npm install npm ERR! code EBADENGINE npm ERR! engine Unsupported engine npm ERR! engine Not compatible with your version of node/npm: yarnpkg@1.0.0 npm ERR! notsup Not compatible with your version of node/npm: yarnpkg@1.0.0 npm ERR! notsup Required: {"npm":"use_yarn_instead"} npm ERR! notsup Actual: {"npm":"7.22.0","node":"v14.17.6"} npm ERR! A complete log of this run can be found in: npm ERR! /Users/zenn/.npm/_logs/2021-09-08T05_12_38_243Z-debug.log その2: yarn のバージョンを指定する 上記のように engines.yarn へバージョンを決め打ちすることも可能ですが、クローンした側の負担軽減には寄与しないため採用しません。 package.json "engines": { // Bad! "yarn": "=1.22.11" } 代わりに yarn policies を利用します。 zsh % yarn policies set-version $(yarn -v) # もしくは特定バージョン プロジェクト下に .yarn と .yarnrc が作成されます。 zsh % tree -a . . ├── .npmrc ├── .yarn │   └── releases │   └── yarn-1.22.10.cjs ├── .yarnrc └── package.json 2 directories, 4 files こうすることで yarn さえインストールされている環境であれば、依存パッケージのインストール時に yarn のバージョンを揃えてくれます。 zsh # インストールされているバージョンは v1.22.5 % yarn -v 1.22.5 # プロジェクトフォルダへ移動してインストールすると... % cd your-project % yarn install yarn install v1.22.10 # <-- 指定したバージョンを使ってくれる info No lockfile found. [1/5] ? Validating package.json... [2/5] ? Resolving packages... [3/5] ? Fetching packages... [4/5] ? Linking dependencies... [5/5] ? Building fresh packages... success Saved lockfile. ✨ Done in 0.04s. その3: yarn (berry) は拒否する yarn v2 (berry) 以降のバージョンでは、その1のような旧い形式の .npmrc を適用してくれないため、あらたに .yarnrc.yml を作成します。 zsh % echo "yarn-path: \".yarn/release/yarn-$(yarn -v).cjs\"" > .yarnrc.yml .yarnrc.yml yarn-path: ".yarn/release/yarn-1.22.11.cjs" これで yarn (berry) で yarn install しても v1 の指定バージョンが使われます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebaseのホスティング-デプロイしたい。

はじめに 制作したサイトをfirebaseで公開しようと利用したので、その手順や注意を忘れないよう自分なりにまとめた記事です。 準備 ・ Googleアカウント ・ デプロイするサイト ・ firebaseのプロジェクト作成(公開するサイト1つにつき1つ作る。) ・ node.jsをインストール(推奨版) ターミナルでnode.jsがインストールされているか確かめる。 $ node -v 続いてnpmも一緒にインストールされているか確認してみる。 $ npm -v firebase-toolsのセットアップ firebaseのコマンドラインツールのインストール $ sudo npm install -g firebase-tools インストールされているか確認する。 $ firebase -V インストールが終わったら、firebaseにログイン $ firebase login ? Allow Firebase to collect anonymous CLI usage and error reporting information?(Y/n) ↓Yを選択後 ✔ Success! Logged in as <mail address> Success! が出たらログイン完了。 プロジェクトの初期化 アップしたいファイルに移動し、初期化する。 $ cd <アップしたいファイルまで移動> <ファイル名>$ firebase init 矢印キーで移動、スペースキーで選択、リターンで決定。 Hostingを選択。 ? Which Firebase CLI features do you want to setup for this folder? ❯◉ Hosting: Configure and deploy Firebase Hosting sites どのフォルダを公開用のフォルダにしますか? publicディレクトリを使用するので、Enter。 ? What do you want to use as your public directory? (public) publicフォルダの中のHTMLを上書きしますか? Nを選択。絶対No。注意!!!! complete!と出たら、初期化ができました。 ? File public/index.html already exists. Overwrite? (y/N) ↓Nを選択 ✔︎ Firebase initialization complete! 続いてファイルの中身を確認。 ・ firebase.jsonが作成されている。 ・ publicフォルダの中に404.htmlが作成されている。 サイトを公開(デプロイ) デプロイするときに、初期化したファイルに移動しているか確認してから行う。 <ファイル名>$ firebase deploy Hosting URL: <公開したかったサイトのURL> URLをコピーしてブラウザに貼り付けると、https:で表示される。 ログアウト firebaseにログインしている状態なので、ログアウトして終了。 <ファイル名>$ firebase logout デプロイしているサイトを更新したい。 編集したファイルに移動し、firebaseにログインした後、そのままデプロイすればOK! $ cd <アップしたいファイルまで移動> $ firebase login <ファイル名>$ firebase deploy メモ プロジェクトの一覧を確認 <ファイル名>$ firebase projects:list ターミナルのクリア control + l firebaseサイトの自分のダッシュボードに行くと現在公開しているサイトと履歴を確認できる。ロールバックもダッシュボードでできる。 ※ロールバック:以前公開したサイトに戻す事。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node-RED 2.0の新機能: Flow Linter

はじめに: Flow Linterとは Node-REDは、ブラウザ画面上でノードをつなげていくことで簡単にフローが開発できます。しかし、グラフィカルなプログラミングは記述の自由度が高い反面、パッと見てわからないバグが潜んでいたり、複数の開発者で共同作業をする際のコーディング規約を守らせることがむずかしいという問題があります。 他のプログラミング言語では、Cに対するlint、Javascriptに対するESLint、Javaに対するCheckstyleなど、記述したコードを静的に解析してバグの発見やコーディング規約の遵守状況をチェックするツールがあります。これらのツールと同様に、Node-REDのフローに対して静的解析を行うツールがFlow Linterです。私も微力ながら開発に携わっています。 Flow Linterは、Node-RED 2.0から利用可能となりました。ただし、Node-RED本体には同梱されず、Node-RED 1.3から導入されたプラグイン機能1を使って追加インストールする形になります。また、静的検証のルール自体も、プラグイン機能をつかって拡張できるようにつくられています。 この記事では、Flow Linterの利用方法を説明します。 インストール方法 前述したとおり、Flow LinterはNode-REDのプラグインとして実装されています。このため、Flow Linterを利用するためには改めてインストール作業が必要です。ノードのインストールはパレットマネージャが利用できますが、いまのところプラグインはコマンドラインからのみインストールできます。 利用しているNode-RED環境のユーザディレクトリ(~/.node-red/など)で、npm installコマンドを実行することでプラグインのインストールが行えます。 % cd ~/.node-red % npm install nrlint そして、Flow Linterの設定ファイルのひな型をカレントディレクトリに生成するために、npx経由でnrlintコマンドを実行します。 % npx nrlint --init > .nrlintrc.js これで、~/.node-red/.nrlintrc.jsというファイルが生成されます。このファイルには、静的検証する内容のデフォルトのルールが記載されています。2 module.exports = { "rules": { "align-to-grid": true, "max-flow-size": true, "no-duplicate-http-in-urls": true, "no-loops": true, "no-overlapping-nodes": true, "no-unconnected-http-nodes": true, "no-unnamed-functions": true, "no-unnamed-links": true, "function-eslint": { "config": { "env": { "es2021": true }, "parserOptions": { "ecmaVersion": 12 }, "rules": { "constructor-super": "error", //...省略 "valid-typeof": "error" } } } } } 次に、この設定ファイルをNode-REDの設定として読み込ませるために、~/.node-red/settings.jsの末尾に下記内容を追記します。 //...省略 // * - code : if result is false, the HTTP error status to return // * - reason: if result is false, the HTTP reason string to return // */ //}, nrlint: require("./.nrlintrc.js"), // この行を追記 } この設定を行ったうえでNode-REDを起動させると、サイドバーに新たな「Linter」というタブが現れます。 Editorからの使い方 まず、初期設定のまま使ってみましょう。 ここでは、フローが空の状態であると仮定します。ここで、functionノードをワークスペース上に配置してみましょう。 すると、いくつかの警告がlinterタブ内に表示されます。 Node not aligned to grid: グリッドからノードがずれている。ずれていると見た目が悪いので修正することをお勧めします。 Function node has no name: Functionノードに名前がついていない。どのような機能があるノードなのかが見た目でわからないので、適切な名前をつけることをお勧めします。 また警告対象となったノードにも「!」マークがつき、lintタブやワークスペース下にはエラーと警告の個数が表示されています。 次にfunctionノードを開いて、Javascriptのコードに細工をしてみましょう。 この変更を加えると、新たに下記のエラーが出現します。 'a' is defined but never used: 変数aが定義されているがどこにも使われていない。 このように、フローに変更を加えるとフローの静的検証が実行され、潜在的なエラーの発見やフローの書き方の統一に役立ちます。 この例ではフローに1つのノードしかないため、エラー表示とノードの対応が明白ですが、エラーに対応するノードがわからないときはエラー表示内にあるノードのIDをクリックしてください。対応するノードが点滅します。 また、エラーや警告を一時的に見逃してほしいときは、各エラー/警告表示の右上のメニューから"ignore for node(group/flow)"を選んでください。 ここで出てきた警告はno-unnamed-functions,aligh-to-gridとfunction-eslintルールによるものです。現在Flow Linterには下記のルールが実装されています。 グリッドからずれている(align-to-grid) ノードがグリッドからずれていると見た目が悪いので、グリッドに合わせてください。Node-REDの設定で"Snap to grid"にチェックが入っていれば、グリッドからずれることはあまりないと思います。 1フローに含まれるノードが多すぎる(max-flow-size) 一つのフローに含まれるノードが多いと、コードがわかりづらくなります。サブフローをつかったり、機能別に別のフローに分けることでコードがわかりやすくなります。「多い」の閾値は、初期値で100ノードです。 HTTP inノードのパス名が重複している(no-duplicate-http-in-urls) 1つのインスタンス上に存在するHTTP inノード間でパス名が重複していると、そのURLへのアクセスがどのノードで処理されるのかがわからなくなります。必ず異なるパスを使用してください。 無限ループの可能性(no-loops) フローがループしています。もちろん、正当なループもありますので、もし誤検知していたらそれらの警告を無視するよう"ignore for flow"等としてください。 ノードの重なり(no-overlapping-nodes) ノードが重なっているとノード名などが読みづらいので、適切に位置を調整してノードが見えるようにしましょう。 HTTP In/Responseノードが対応していない(no-unconnected-http-nodes) HTTP Inノードの先にはHTTP Responseノードを置く必要があります。もしこれが守られていないと、HTTPリクエストを受けたときに返答が送られなくなります。正しく接続しておきましょう。ただし、Flow Linterはフローのトポロジー的な観点でのみ対応関係を判定しているので、このチェックが通ったからと言ってすべての場合でHTTP InノードのメッセージがHTTP Responseノードのいずれかに届くことを保証するものではないです。 Functionノードに名前がない(no-unnamed-functions) Functionノードはメッセージに対して任意の処理を記述できるので、適切な名前をつけないとフローを見たときに何をするのかがわかりません。処理内容がわかるような名前をつけましょう。 Linkノードに名前がない(no-unnamed-links) Linkノードは、マウスオーバーによって対応するLinkノードを表示することができますが、フローが込み入ってきたりフローを跨ってリンクをしている場合はどのLinkノードに対応しているかがわかりづらくなります。ノードに適切な名前を付けて、どことつながっているのかを明示してください。 Functionノード内のJavascriptコードに関する警告(function-eslint) Functionノード内のコードをESLintのルールに従ってチェックします。初期設定では、ESlintで"extends": "eslint:recommended"で有効になるルールが設定されています。ESLintの各種ルールとその設定に関する設定に関しては、ESLintのドキュメントを参照してください。 設定方法 ここまでに述べたルールは、設定によって無効化あるいは細かい調整ができます。Linterタブの右上の「歯車」ボタンを押すと、設定画面が出てきますので、ルールの有効化/無効化、フローのサイズやESLintの設定などは、この画面から変更してください。 コマンドラインからの使い方 Flow Linterは、エディタからだけではなくコマンドラインからも呼び出すことができます。Flow Linterをインストールしたディレクトリ(`~/.node-red)にて、下記の形で呼び出すことができます。 % npx nrlint flows.json ╔══════════════════╤══════════╤═══════════════════════╤══════════════════╗ ║ Object ID │ Severity │ Message │ Rule ║ ╟──────────────────┼──────────┼───────────────────────┼──────────────────╢ ║ 92bc4ebe84d23364 │ warn │ Link node has no name │ no-unnamed-links ║ ╚══════════════════╧══════════╧═══════════════════════╧══════════════════╝ ✖ 1 problems (0 errors, 1 warnings) % 何らかのエラーか警告があった場合は、エラーコード1が返ってきますので、これを使って「フローを検査して、エラーがあったらコミットしない」などの処理が実現できます。 終わりに 本記事では、Node-REDのフローの静的検証ツールであるFlow Linterについて解説しました。冒頭で述べた通り、ここで述べたルール自体もプラグインとして拡張可能です。機会があれば、新たなルールプラグインの開発方法などについても記事にしたいと考えています。また、新たなルールに関するアイデアも募集していますので、Node-REDのフォーラムなどにご意見をお寄せいただければ幸いです。 Node-RED 2.0の新機能紹介 Node-RED 2.0の新機能: 概要紹介 Node-RED 2.0の新機能: フローデバッガ Node-RED 2.0の新機能: Flow Linter (本記事) Node-RED: Node-REDは,OpenJS Foundationの米国およびその他の国における登録商標または商標である。 JavaScript, Java: JavaScriptおよびJavaは、Oracleの米国およびその他の国における登録商標または商標である。 Checkstyle: Checkstyle は、Free Software Foundation, Inc. の登録商標もしくは商標である。 実際には、Flow Linterを開発する過程でプラグイン機能の必要性がわかり、プラグイン機能が設計・実装されたという経緯になります。 ↩ 上記は最新のmasterブランチのnrlintで生成したもので、v1.0.4以前ではrulesの部分の記述がありません。最新版がnpmにpublishされるまでしばらくお待ちください。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

node.js超入門ノート11(Sequelizeでのバリデーション編)

バリデーション モデルのバリデーション 以下のように修正します。 models/user.js 'use strict'; module.exports = (sequelize, DataTypes) => { const User = sequelize.define('User', { name: { type:DataTypes.STRING, validate: { notEmpty: true } }, pass: { type: DataTypes.STRING, validate: { notEmpty: true } }, mail: { type: DataTypes.STRING, validate: { isEmail: true } }, age: { type: DataTypes.STRING, validate: { isInt: true, min: 0 } } }, {}); User.associate = function(models) { // associations can be defined here }; return User; }; validateの例は以下のようになります。 validate 意味 notEmpty 未入力の禁止 isEmail メールアドレス形式のみ許可 isInt 整数値のみ許可 min 最小値の設定 User作成処理のバリデーション 以下を修正します。 routes/users.js router.get('/add',(req, res, next) => { var data = { title: 'Users/Add', form: new db.User(), err:null } res.render('users/add', data); }); router.post('/add',(req, res, next) => { const form = { name: req.body.name, pass: req.body.pass, mail: req.body.mail, age: req.body.age }; db.sequelize.sync() .then(() => db.User.create(form) .then(usr => { res.redirect('/users'); }) .catch(err => { var data = { title: 'Users/Add', form: form, err: err } res.render('users/add', data); }) ) }); テンプレートのエラー表示 テンプレートにエラーの表示を追加します。 views/users/add.ejs <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="content-type" content="text/html"> <title><%= title %></title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous"> <link rel="stylesheet" href="/stylesheets/style.css" /> </head> <body class="container"> <header> <h1 class="display-4"> <%= title %> </h1> </header> <div role="main"> <ol class="text-danger"> <% if (err!=null) {for (let i in err.errors) { %> <li><%= err.errors[i].message %></li> <% }} %> </ol> <form action="/users/add" method="post"> <div class="form-group"> <label for="name">NAME</label> <input type="text" name="name" id="name" value="<%=form.name %>" class="form-control"> <ul class="text-danger"> <% if (err!=null) {for (let i in err.get("name")) { %> <li><%= err.get("name")[i].message %></li> <% }} %> </ul> </div> <div class="form-group"> <label for="pass">PASSWORD</label> <input type="password" name="pass" id="pass" value="<%=form.pass %>" class="form-control"> <ul class="text-danger"> <% if (err!=null) {for (let i in err.get("pass")) { %> <li><%= err.get("pass")[i].message %></li> <% }} %> </ul> </div> <div class="form-group"> <label for="mail">MAIL</label> <input type="text" name="mail" id="mail" value="<%=form.mail %>" class="form-control"> <ul class="text-danger"> <% if (err!=null) {for (let i in err.get("mail")) { %> <li><%= err.get("mail")[i].message %></li> <% }} %> </ul> </div> <div class="form-group"> <label for="age">AGE</label> <input type="number" name="age" id="age" value="<%=form.age %>" class="form-control"> <ul class="text-danger"> <% if (err!=null) {for (let i in err.get("age")) { %> <li><%= err.get("age")[i].message %></li> <% }} %> </ul> </div> <input type="submit" value="作成" class="btn btn-primary"> </form> </div> </body> </html> エラーメッセージを日本語に変更 以下を修正します。 models/user.js 'use strict'; module.exports = (sequelize, DataTypes) => { const User = sequelize.define('User', { name: { type:DataTypes.STRING, validate: { notEmpty: { msg: "名前は必ず入力してください。" } } }, pass: { type: DataTypes.STRING, validate: { notEmpty: { msg: "パスワードは必ず入力してください。" } } }, mail: { type: DataTypes.STRING, validate: { isEmail: { msg: "メールアドレスを入力して下さい。" } } }, age: { type: DataTypes.STRING, validate: { isInt: { msg: "ゼロ以上の値が必要です。" }, min: { args: [0], msg: "ゼロ以上の値が必要です。" } } } }, {}); User.associate = function(models) { // associations can be defined here }; return User; }; バリデーション一覧は以下のPer-attribute validationsから見れます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む