- 投稿日:2020-03-20T23:51:33+09:00
Rubyでシーザー暗号の解読
Rubyでシーザー暗号を解読して見た時のコードと解説をします。
シーザー暗号とは?
そもそもシーザー暗号とはなにかなんですが、単一換字式暗号の一種らしいのですが、
簡単に言うと文字を特定数の文字ずらした際にそれが暗号鍵になる暗号の事です。例)
暗号
hsnvld
2文字進めた文字が答えとなると
jupxnf
になります。これをRubyですぐ表示できる様にアルゴリズムを書いてみました。
Rubyでシーザー暗号の解読
暗号文に対して3文字進めるのが答えとします。
暗号文 hgmgkrddef decryption(char) char_ary = char.split("")#1文字ずつに分割する changed_char_ary = []#空の配列を用意する char_ary.each do |char| changed_char_ary << (char.ord - 3).chr #ordメソッドで整数にしchrメソッドで文字に変換する #空の配列に入れる end puts changed_char_ary.join # =>edjdhoa #joinメソッドで配列を連結して文字列にする end char = "hgmgkrd" #暗号文を変数に入れる decryption(char)
- 投稿日:2020-03-20T21:36:09+09:00
【忘備録】Ruby on rails : パスワード登録のバリデーション
前提
今回はユーザーの新規登録する場面を想定しています。
以下がユーザーを登録する為のusersテーブルです。
password_digest カラムが新規登録する際に設定するパスワードを格納しています。+-----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | email | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | | password_digest | varchar(255) | YES | | NULL | | +-----------------+--------------+------+-----+---------+----------------+本題
railsではパスワードを設定する際に便利な機能が既に用意されています。
以下はusersテーブルを操作する為のモデルクラスです。
validates 群の下に has_secure_password とありますがこれはrailsに備わっている
メソッドです。
このメソッドをモデルクラスに追加することで今回の場合、usersテーブルのpassword_digest カラムに
暗号化されたパスワードを保存することが可能になります。(password_digest カラムは自分で作る必要があります。)厳密にはこの他にbcryptというgemが必要になるのでインストールしましょう。
インストールが済んだら正式に完了です。class User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } validates :email, presence: true, format: { with: /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i } validates :password, presence: true, length: { minimum: 6, maximum: 25 }, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,}+\z/i } has_secure_password endあとはこのメソッドを使用すると自動的に通常のパスワードと確認用のパスワードが一致しているかの確認を行ってくれます。フロント側に普通のパスワード用のフォームと確認用パスワード用のフォームを用意してsubmitすれば自動的に確認してくれます。
一応下記がそのフォームです。
<%= form_for @user do |f| %> <div> <%= f.label :name %> <%= f.text_field :name %> </div> <div> <%= f.label :email %> <%= f.text_field :email %> </div> <div> <%= f.label :password %> <%= f.password_field :password %> </div> <div> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation%> </div> <%= f.submit "登録", class: "btn-block btn-white" %> <% end %> <%= link_to "ログイン", "#", class: "text-white" %> </div> </div> </div> </div>これがパスワードフォームで
<%= f.password_field :password %>
これがパスワード確認用のフォームです。
<%= f.password_field :password_confirmation%>
:password
とpassword_confirmation
がparamsのハッシュのkeyとなって送信され、
keyのvalueが一致しているかモデルクラスで確認されますので名前は変えない方がいいと思います。
- 投稿日:2020-03-20T21:36:09+09:00
【忘備録】Ruby on rails : パスワード登録
前提
今回はユーザーの新規登録する場面を想定しています。
以下がユーザーを登録する為のusersテーブルです。
password_digest カラムが新規登録する際に設定するパスワードを格納しています。+-----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | email | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | | password_digest | varchar(255) | YES | | NULL | | +-----------------+--------------+------+-----+---------+----------------+本題
railsではパスワードを設定する際に便利な機能が既に用意されています。
以下はusersテーブルを操作する為のモデルクラスです。
validates 群の下に has_secure_password とありますがこれはrailsに備わっている
メソッドです。
このメソッドをモデルクラスに追加することで今回の場合、usersテーブルのpassword_digest カラムに
暗号化されたパスワードを保存することが可能になります。(password_digest カラムは自分で作る必要があります。)厳密にはこの他にbcryptというgemが必要になるのでインストールしましょう。
インストールが済んだら正式に完了です。class User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } validates :email, presence: true, format: { with: /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i } validates :password, presence: true, length: { minimum: 6, maximum: 25 }, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,}+\z/i } has_secure_password endあとはこのメソッドを使用すると自動的に通常のパスワードと確認用のパスワードが一致しているかの確認を行ってくれます。フロント側に普通のパスワード用のフォームと確認用パスワード用のフォームを用意してsubmitすれば自動的に確認してくれます。
一応下記がそのフォームです。
<%= form_for @user do |f| %> <div> <%= f.label :name %> <%= f.text_field :name %> </div> <div> <%= f.label :email %> <%= f.text_field :email %> </div> <div> <%= f.label :password %> <%= f.password_field :password %> </div> <div> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation%> </div> <%= f.submit "登録", class: "btn-block btn-white" %> <% end %> <%= link_to "ログイン", "#", class: "text-white" %> </div> </div> </div> </div>これがパスワードフォームで
<%= f.password_field :password %>
これがパスワード確認用のフォームです。
<%= f.password_field :password_confirmation%>
:password
とpassword_confirmation
がparamsのハッシュのkeyとなって送信され、
keyのvalueが一致しているかモデルクラスで確認されますので名前は変えない方がいいと思います。
- 投稿日:2020-03-20T21:10:26+09:00
Rails アプリを EC2 にデプロイしよう!(サーバー構築編)
Rails アプリを Amazon Web Service を使ってデプロイするまでの手順をまとめました。
次の順番でデプロイまで持っていきます。1, 準備編
2, サーバー構築編
3, 環境構築編
4, デプロイ編今回は「サーバー構築編」です。
「準備編」を読んでない方は先に読んでください。EC2 インスタンスの作成
EC2とは Elastic Compute Cloud の略で、クラウド上に存在する仮想のサーバーのことです。
サーバーは、サービスを提供する (server) コンピューターのことです。
要するにパソコンを借ります。早速借りましょう。
1, コンソール画面から検索するなりして「EC2」をクリックしてください。
2, 左のメニューバーから「インスタンス」をクリックしてください。
3, 左上辺りにある[インスタンスの作成]をクリックしてください。AMIの選択
最初に「AMIの選択」を行います。
AMIとは Amazon Machine Image の略で、ここでは今作成しようとしているパソコン(EC2)のタイプを選択します。4, 今回は
Ruby
を使用するので、
「Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type」
を選択しましょう。
AMIを間違えるとRubyが動かないので注意しましょう。
OSもここで決まります。今回はAmazon Linuxを使用します。
名称が変わっている場合は、次のような説明文が書かれているものを選択してください。Amazon Linux AMI は、AWS がサポートする EBS-backed イメージです。デフォルトのイメージには、AWS コマンドラインツール、Python、Ruby、Perl、および Java が含まれます。レポジトリには、Docker、PHP、MySQL、PostgreSQL、およびその他のパッケージが含まれます。
インスタンスタイプの選択
次に「インスタンスタイプの選択」を行います。
AWSにはさまざまな種類のCPUやメモリ、ストレージなどを組み合わせたインスタンスが存在しています。
今回は具体的なインスタンスタイプの種類について割愛します。5, 今回は
t2.micro
を使用するので
次のインスタンスタイプを選択してください。
今回は「無料枠」を選択しています。
無料枠が表示されない方もいるかもしれませんが、それについてはご了承ください。インスタンスの詳細の設定
次は「インスタンスの詳細の設定」を行います。
いろいろ項目がありますが、意味は次の通りです。
名称 意味 インスタンス数 作成するインスタンスの数 スポットインスタンスのリクエスト 同じ地域の使用されていないインスタンスを、入札制で使用出来る仕組み。費用削減が期待できる。今回はチェックしない。 ネットワーク 使用するVPCを選択する。準備編で作成したVPCをプルダウンで選択しましょう。 サブネット 使用するサブネットを選択する。準備編で作成したサブネットをプルダウンで選択しましょう。 自動割り当てパブリックIP インターネットを通じてインスタンスにアクセスするためのIPアドレス。有効化します。 配置グループ プレイスメントグループというグループを作成することで、インスタンス間の通信速度を高速化させることができます。今回は使用しません。 キャパシティーの予約 任意の時間やタイミングでキャパシティー(性能)を上げることができます。今回は使用しません。 IAMロール IAMというユーザーの種類別にリソースの使用権限を割り振ったもの。誰がこのインスタンスにアクセス出来て、誰が出来ないかなどを設定できる。今回は設定しない。 シャットダウン動作 EC2をシャットダウンした際に削除するのか停止させるのか選択できる。 停止 - 休止動作 インスタンスの停止中に「休止状態」が選択できるようにする。 終了保護の有効化 インスタンスを誤って削除しないように設定できる。 モニタリング CloudWatchというインスタンス監視サービスを利用するかどうかを選択できる。利用すると追加料金が発生する。 テナンシー ハードウェアを占有するか、それとも他の利用者と共有するかを選択できる。 Elastic Inference 説明を割愛します。 T2/T3 無制限 説明を割愛します。 ストレージの追加
次は「ストレージの追加」を行います。
ストレージシステム(EC2)の管理に役立つ特別なディレクトリと構成ファイルが格納されている場所で、Windowsで言う所の「Cドライブ」に該当します。タグの追加
次は「タグの追加」を行います。
ここでEC2に名前をつけましょう。セキュリティグループの設定
最後に「セキュリティグループの設定」を行います。
準備編で設定したセキュリティグループを選択しましょう。インスタンス作成の確認
これまでの手順を振り返って問題がなければ、
右下にある「起動」をクリックしましょう。クリックすると「既存のキーペアを選択するか、新しいキーペアを作成します。」という画面が出てきます。
新しいキーペアの作成
SSH という通信プロトコルを使って安全な通信を行います。
この通信では、ユーザーはプライベートファイルをAWSから保存して、これを使用してインスタンスに接続します。10, 新しいキーペアを作成して、キーペアをダウンロードしてください。
再度ダウンロードすることはできないので注意してください。
また、安全な場所に保存するようにしてください。これを保存した後、やっとインスタンスを作成することができます。
11, 「インスタンスの作成」をクリックしましょう。
12, 作成ステータスが表示されますが、そのまま「インスタンスの表示」をクリックしましょう。以下のようにインスタンスが作成されていれば OK です。
Elastic IP の設定
今回の最後に Elastic IP を設定していきます。
EC2サーバーはインターネットに接続を行う場合、どのサーバーも例外なくパブリックIPというものを持つ必要があります。そして、先ほど作成したEC2インスタンスにも作成時にパブリックIPが自動で割り振られるのですが、サーバーを再起動させるたびにこのパブリックIPが変わってしまうという欠点を持っています。
そこで Elastic IP を使用します。
これは、先に固定のIPアドレスを他に使用されないように押さえてしまい、それをパブリックIPとしてEC2インスタンスに紐付けることで、インスタンスの起動、停止に関わらず常に同じIPで通信を行うことができます。では早速作成していきましょう。
1, 左のメニューバーから「Elastic IP」をクリックしてください。
2, 右上辺りにある「セキュリティグループの作成」をクリックしてください。
3, 「Amazon の IPv4 アドレスプール」が設定されていると思います。
4, そのまま「割り当て」をクリックしましょう。
ここでは既にName
タグを設定していますが、「タグの管理」をクリックすれば設定できます。次に、このIPを先ほど作成したインスタンスに割り当てましょう。
5, 右上辺りにある「Action」から「Elastic IP アドレスの関連付け」を選択してください。
6, 先ほど作成したインスタンスとそのパブリックIPを選択して「関連付ける」をクリックしてください。
以下の画面のように、インスタンスが関連づけられていれば OK です。
最後に
今回は「サーバー構築編」でした。
次回からやっとコマンドラインを使用することになります(長い!)。それでは次回「環境構築編」お楽しみに。
- 投稿日:2020-03-20T21:06:43+09:00
【Rails】bundler-auditの使い方
bundler-audit
とは
bundler-audit
はプロジェクトで利用しているGemの脆弱性の有無をチェックしてくれるGemです。
システムの脆弱性チェックの一つとして利用できますね。検証した環境
- Ruby 2.7.0
- bundler-audit 0.6.1
準備
bundle install
Gemfileに以下を追加して
bundle install
Gemfilegroup :development do gem 'bundler-audit' end$ bundle install脆弱性チェックに使用するDBを更新する
脆弱性チェックを実行する前に、
bundler-audit
が使用するDBの更新を行いましょう。$ bundle exec bundler-audit updateこのコマンドでは、実際には
$HOME/.local/share
ディレクトリ配下にrubysec/ruby-advisory-dbをgit clone
しているようです。脆弱性の存在するGemをチェックする
実際に
bundler-audit
を実行してGemの脆弱性をチェックしてみましょう。
以下のコマンドで実行できます。
脆弱性が見つからなかった場合はNo vulnerabilities found
と出力されます。$ bundle exec bundler-audit No vulnerabilities foundDBの更新と脆弱性チェックを同時に実行する
以下のコマンドで脆弱性チェックに使用するDBの更新と脆弱性チェックを同時に実行できます。
DBの更新忘れを防ぐためにも、基本的には以下のコマンドを利用するほうがいいでしょう。$ bundle exec bundler-audit check --update実際に脆弱性があるGemをインストールして検証してみる
bundler-audit
の出力を確認するために、実際に脆弱性が存在するGemのインストール~脆弱性チェック~修正までやってみます。脆弱性があるGemをインストール
実際に脆弱性が存在するGemをインストールしてみます。
ここでは試しにbootstrap
のv4.3.0
をインストールしてみます。
Gemfile
に以下を追記してbundle install
。Gemfilegem 'bootstrap', '4.3.0'$ bundle install脆弱性をチェックする
bundler-audit
を実行してみます。$ bundle exec bundler-audit Name: bootstrap Version: 4.3.0 Advisory: CVE-2019-8331 Criticality: Medium URL: https://blog.getbootstrap.com/2019/02/13/bootstrap-4-3-1-and-3-4-1/ Title: XSS vulnerability in bootstrap Solution: upgrade to >= 4.3.1 Vulnerabilities found!脆弱性が見つかったGemとその内容、解決するバージョンまでわかりやすく出力してくれます。
脆弱性を無視する
場合によっては
bundler-audit
によって見つかった脆弱性を無視したいこともあるかと思います。
そういうときは--ignore
オプションに無視したいAdvisoryを指定しましょう。$ bundle exec bundler-audit --ignore CVE-2019-8331 No vulnerabilities found脆弱性のあるGemのバージョンを上げる
先ほど
bundler-audit
で出力された内容にはSolution: upgrade to >= 4.3.1と書いてあったので、それに従って
Gemfile
を修正してみます。
(※実際にはGemfile
にバージョンを指定していない場合の方が多いと思うので、その場合はbundle update
コマンド等を利用してください。)Gemfile-gem 'bootstrap', '4.3.0' +gem 'bootstrap', '4.3.1'$ bundle install
bootstrap
のバージョンを上げたのでもう一度bundler-audit
を実行してみます。$ bundle exec bundler-audit No vulnerabilities found警告が出なくなりました!
参考
- 投稿日:2020-03-20T20:30:36+09:00
bundle install でNokorigiインストール時に「Gem::Ext::BuildError: ERROR: Failed to build gem native extension.」エラーが出た場合の対処方法
bundle install
でnokogiriインストール時に下記のようなエラーGem::Ext::BuildError: ERROR: Failed to build gem native extension.が出てしまった場合
gem install時であれば
--use-system-libraries
オプションを付けて再実行してみるところですがbundlerの場合はどうすればいいかというと
bundle config --local build.nokogiri --use-system-libraries
というような感じでコマンドを実行します。
--local
オプションはapp/.bundle/config
へ設定を書きます。
--global
オプションは~/.bundle/config
に書くようです。まあよほどの事情がない限り、プロジェクトごとの
.bundle/config
に書いておくほうが良いと思います。その他、環境変数にも定義できます。bundle configの優先順位
bundle configですが、mysqlなどと同様、複数の箇所に設定を保持しておけます。用途によって適切な場所に設定を書いておくのがいいと思いますが、bundleコマンドのhelpによると
DESCRIPTION This command allows you to interact with Bundler´s configuration system. Bundler loads configuration settings in this order: 1. Local config (app/.bundle/config) 2. Environmental variables (ENV) 3. Global config (~/.bundle/config) 4. Bundler default configという優先順位で参照されます。
- 投稿日:2020-03-20T18:45:19+09:00
【14日目】Ruby(メソッド,クラス,インスタンス)
はじめに
こんばんは。
今日でprogateのRubyカリキュラムは終了しました!
こんなレベルで大丈夫なのか一抹の不安は残りますが、
とりあえず進んでいこうと思います。本日の学び
- progate Ruby3
- progate Ruby4
- progate Ruby5
Ruby
メソッド
複数の処理を1つにまとめたもの
def print_info #def メソッド puts "わんこでんきへようこそ!" puts "今日はヘッドホンがセール中です!" end引数
複数の処理を1つにまとめたもの
メソッド内で作った変数はメソッド内でしか使えないので注意
キーワード引数は項目が分かりやすくなるdef print_info(item,price) #itemとpriceが引数 puts "わんこでんきへようこそ!" puts "今日は#{item}がセール中で#{price}円です!!" end print_info("SDカード",1200) #引数の値 def buy(item:, price:, count:) #キーワード引数 puts "#{item}を#{count}台のお買い上げです" puts "合計金額は#{price * count}円です" end buy(item:"テレビ", price:15000, count:2)戻り値
戻り値が実行された場合その後の戻り値は実行されないので注意
def shipping_free?(price) #真偽値を返すメソッドには?を付ける return price >= 5000 #戻り値 5000以上 end if shipping_free?(3000) puts "5000円以上のお買い上げなので送料はいただきません" else puts "追加で送料をいただきます" endクラス インスタンス
- クラス
- 情報のまとめ(料理であれば、コース料理という枠組み)
- インスタンス
- クラスが持つ情報(コース料理の中身で前菜、メイン、デザートなど)
- 値
- インスタンスの具体的内容(前菜やデザートの種類)
class Menu #クラスの名前 attr_accessor :name #インスタンスの追加 attr_accessor :price def initialize(name:, price:) self.name = name #インスタンス変数(インスタンスを変数として扱える) self.price = price end def info #インスタンスの設定にはdef インスタンス名 return "#{self.name} #{self.price}円" #戻り値 endget_total_price
def get_total_price(count) #合計値を求めるメソッド total_price = self.price * count #total_priceにpriceを代入 if count >= 3 #条件分岐 total_price -= 100 end return total_price end endmenu1 = Menu.new #menu1に代入 menu1.name = "ピザ" #menu1の名前に代入 puts menu1.name menu1.price = 800 puts menu1.price menu1 = Menu.new(name: "ピザ", price: 800) #まとめた書き方 menu2 = Menu.new(name: "すし", price: 1000) menu3 = Menu.new(name: "コーラ", price: 300) menu4 = Menu.new(name: "お茶", price: 200)menus = [menu1, menu2, menu3, menu4] index = 0 #インデックスに番号を割り振る menus.each do |menu| #menuに対して繰り返し同じ動作をさせる puts "#{index}. #{menu.info}" index += 1 #最初の数字を0ではなく1にするために足す endgets.chomp gets.chomp.to_i
入力された文字数値を受け取る
order = gets.chomp.to_i #数字の入力を受け取る selected_menu = menus[order] puts "選択されたメニュー: #{selected_menu.name}" puts "個数を入力してください(3つ以上で100円割引)" count = gets.chomp.to_i puts "お会計は#{selected_menu.get_total_price(count)}円です"intialize
クラスの初期化が主な役目(?)
理解していません。def initialize(name:,price:) self.name = name self.price = price endファイルの分割
ファイルごとで処理を分けておくのに有効
require "./menu" #menu.rbのファイルを参照するクラスの継承
インスタンス変数とインスタンスメソッドを引き継ぐ
class Food < Menu #MenuからFoodへ継承 end日付
インスタンス変数とインスタンスメソッドを引き継ぐ
require "date" #日付データの読み込み birthday = Date.new(2020,3,20) #区切り方に注意 puts birthday #日付の表示 puts birthday.sunday? #trueかfalse today = Date.today #.todayがクラスメソッド所感
今日感じたのはJavascriptとやれることが似ている?のかなと。
同じ概念も出てきますし、なんとなくまっさらから理解するよりは、
良かったかと思います。
これをどう使っていくのか、う~ん・・・イメージできず。とりあえず明日からはRailsをやっていきます。
ボリュームが結構ありそうなので覚悟してやっていきます。
- 投稿日:2020-03-20T18:13:19+09:00
超最低限のRailsアプリをテストする(モデル編)
この記事の基本的な方針
テストは重要です。
なぜなら、人間は不完全であるからです。
ではもし自分が完全であったら、テストは不要でしょうか?
いいえ。なぜなら他人にコードの妥当性を証明しなくてはならないからです。テストの目的以下です。 ①コードの妥当性を自分で確認すること ②コードの妥当性を他人に示すことここでは別記事、超最低限のRailsアプリを丁寧に作る(もう一度きちんと復習して初心者を卒業しよう)で作ったアプリをテストします。
手を動かしながら読みたいようでしたら、以下でこの3画面アプリを手に入れてください。
Terminal$ git clone https://github.com/annaPanda8170/minimum_rails_application.git $ bundle install $ bundle exec rake db:create $ bundle exec rake db:migrate基本解説はしません。手順のみ示します。
想定する読み手
既に一度Railsアプリをチュートリアルやスクール等で作ったことがある方を想定しております。
Mac使用で、パソコンの環境構築は完了していることが前提です。具体的な手順
①登録条件確認
deviseでデフォルトで設定されたEmailとPasswordの制約を確認します。
見るべきは、(1)devise公式GitHub内のバリデーションに関するファイルと(2)
config/initializers/devise.rb
です。(1)devise公式GitHub内のバリデーションに関するファイルには、「Passwordは空ではならない」、「Emailはユニークで空ではならない」とあります。
(2)
config/initializers/devise.rb
にはconfig/initializers/devise.rb#省略 config.password_length = 6..128 #省略 config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ #省略とあります。
よって今回は、
Passwordは、 6文字から128文字である。Emailは、 ユニークで かつ @の前後に@と空白以外が1文字以上ずつ」である。を確認すべく、テストします。
②準備
Gemfile#省略 group :development, :test do #省略 gem 'rspec-rails' gem 'factory_bot_rails' end group :development do #省略 gem 'spring-commands-rspec' end #省略※spring-commands-rspecは起動時間を速くするためのものでなくても問題はありません。
Terminal$ bundle install $ rails g rspec:install $ rails g rspec:model user $ rails g factory_bot:model user $ bundle exec spring binstub rspec control + c $ rails s.rspec--format documentation※これでRspecの出力が読みやすくなるそうです。
ここで空っぽのまま一度起動してみます。
Terminal$ bundle exec rspecOutput#省略 Finished in 0.00255 seconds (files took 1.69 seconds to load) 1 example, 0 failures, 1 pending※1個のテストに対して0個の失敗があり、1個保留ですという意味です。
③テスト構築
spec/models/user_spec.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる" it "Passwordが5文字で登録できない" #パスワード文字数上限の方は省きます it "passwordとpassword_confirmationが異なっていると登録できない" it "Emailが@がないと登録できない" it "Emailが@が二つあると登録できない" it "Emailが途中に空白があると登録できない" it "2人のユーザーについて、Emailがユニークであれば登録できる" it "2人のユーザーについて、Emailがユニークでなければ登録できない" endTerminal$ bundle exec rspecOutput2020-03-20 00:51:43 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. User Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる (PENDING: Not yet implemented) Passwordが5文字で登録できない (PENDING: Not yet implemented) passwordとpassword_confirmationが異なっていると登録できない (PENDING: Not yet implemented) Emailが@がないと登録できない (PENDING: Not yet implemented) Emailが@が二つあると登録できない (PENDING: Not yet implemented) Emailが途中に空白があると登録できない (PENDING: Not yet implemented) 2人のユーザーについて、Emailがユニークであれば登録できる (PENDING: Not yet implemented) 2人のユーザーについて、Emailがユニークでなければ登録できない (PENDING: Not yet implemented) Pending: (Failures listed here are expected and do not affect your suite's status) 1) User Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる # Not yet implemented # ./spec/models/user_spec.rb:4 2) User Passwordが5文字で登録できない # Not yet implemented # ./spec/models/user_spec.rb:5 3) User passwordとpassword_confirmationが異なっていると登録できない # Not yet implemented # ./spec/models/user_spec.rb:7 4) User Emailが@がないと登録できない # Not yet implemented # ./spec/models/user_spec.rb:8 5) User Emailが@が二つあると登録できない # Not yet implemented # ./spec/models/user_spec.rb:9 6) User Emailが途中に空白があると登録できない # Not yet implemented # ./spec/models/user_spec.rb:10 7) User 2人のユーザーについて、Emailがユニークであれば登録できる # Not yet implemented # ./spec/models/user_spec.rb:11 8) User 2人のユーザーについて、Emailがユニークでなければ登録できない # Not yet implemented # ./spec/models/user_spec.rb:12 Finished in 0.00215 seconds (files took 2.4 seconds to load) 8 examples, 0 failures, 8 pendingspec/factories/users.rbFactoryBot.define do factory :user do email "a@a" password "111111" password_confirmation "111111" end endspec/models/user_spec.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる" do expect(FactoryBot.build(:user)).to be_valid end it "Passwordが5文字で登録できない" #パスワード文字数上限の方は省きます it "passwordとpassword_confirmationが異なっていると登録できない" it "Emailが@がないと登録できない" it "Emailが@が二つあると登録できない" it "Emailが途中に空白があると登録できない" it "2人のユーザーについて、Emailがユニークであれば登録できる" it "2人のユーザーについて、Emailがユニークでなければ登録できない" endTerminal$ bundle exec rspecOutput#省略 8 examples, 0 failures, 7 pendingエラー文は以下のように確認します。
Terminalirb(main):001:0> user = User.new(email: "a@a", password: "11111", password_confirmation: "11111") (0.9ms) SET NAMES utf8, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483 => #<User id: nil, email: "a@a", created_at: nil, updated_at: nil> irb(main):002:0> user.valid? User Exists (0.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'a@a' LIMIT 1 => false irb(main):003:0> user.errors => #<ActiveModel::Errors:0x00007fd9f12cc6f8 @base=#<User id: nil, email: "a@a", created_at: nil, updated_at: nil>, @messages={:password=>["is too short (minimum is 6 characters)"]}, @details={:password=>[{:error=>:too_short, :count=>6}]}>④テスト本番
spec/models/user_spec.rbrequire 'rails_helper' RSpec.describe User, type: :model do it "Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる" do expect(FactoryBot.build(:user)).to be_valid end it "Passwordが5文字で登録できない" do user = FactoryBot.build(:user, password: "11111", password_confirmation: "11111") user.valid? expect(user.errors[:password]).to include("is too short (minimum is 6 characters)") end #パスワード文字数上限の方は省きます it "passwordとpassword_confirmationが異なっていると登録できない" do user = FactoryBot.build(:user, password: "111111", password_confirmation: "211111") user.valid? expect(user.errors[:password_confirmation]).to include("doesn't match Password") end it "Emailが@がないと登録できない" do user = FactoryBot.build(:user, email: "aaa") user.valid? expect(user.errors[:email]).to include("is invalid") end it "Emailが@が二つあると登録できない" do user = FactoryBot.build(:user, email: "a@@a") user.valid? expect(user.errors[:email]).to include("is invalid") end it "Emailが途中に空白があると登録できない" do user = FactoryBot.build(:user, email: "a @a") user.valid? expect(user.errors[:email]).to include("is invalid") end it "2人のユーザーについて、Emailがユニークであれば登録できる" do FactoryBot.create(:user) expect(FactoryBot.build(:user, email: "b@b")).to be_valid end it "2人のユーザーについて、Emailがユニークでなければ登録できない" do FactoryBot.create(:user) user = FactoryBot.build(:user) user.valid? expect(user.errors[:email]).to include("has already been taken") end endTerminal$ bundle exec rspecOutput2020-03-20 02:01:54 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. User Passwordが6文字で、Emailが@が一つだけあり@の前後に@と空白以外が1文字ずつあれば登録できる Passwordが5文字で登録できない passwordとpassword_confirmationが異なっていると登録できない Emailが@がないと登録できない Emailが@が二つあると登録できない Emailが途中に空白があると登録できない 2人のユーザーについて、Emailがユニークであれば登録できる 2人のユーザーについて、Emailがユニークでなければ登録できない Finished in 0.06768 seconds (files took 2.31 seconds to load) 8 examples, 0 failuresまとめ
もし、パスワード全パターンを試すようなことができれば完璧なテストですが、それはできません。
例えば6桁に限定したとしても、数字10種とアルファベット26文字の大文字と小文字で計算すると、
(10 + 26 + 26)^6 = 56,800,235,584
つまり500億パターン以上で、これを128桁まで考えると気が遠くなるパターンがあることがわかります。
そもそも全パターン試せるようなパスワードがあればパスワードとしての価値がありません。
物理的に全パターンを試すことが出来ない我々は、限界値の両端をうまくテストしなくてはなりません。
- 投稿日:2020-03-20T18:09:20+09:00
【ruby】繰り返しについて
rubyの繰り返し文についてまとめておきます。
繰り返しを行うには?
以下のような構文又はメソッドを利用して繰り返し文を書くことが可能です。
今回はそれぞれの使い方をまとめて見ます。・timesメソッド
・for文
・eachメソッドtimesメソッド
一定の回数だけ同じ処理をさせたい場合はtimesメソッドを利用します。
qiita.rb5.times do p "りんご" end実行結果.rb"りんご" "りんご" "りんご" "りんご" "りんご"ブロック内で繰り返しの数値を使いたいときはdoの後に|変数|を加えます。
qiita.rb5.times do |i| p "りんご#{i+1}個を食す" end実行結果.rb"りんご1個を食す" "りんご2個を食す" "りんご3個を食す" "りんご4個を食す" "りんご5個を食す"for文
timesメソッドとは異なりfor文はメソッドとは違います。
1から10まで加算する繰り返し文は以下のようにできます。qiita.rbsum =0 for i in 1..10 do p sum += i end実行結果.rb1 3 6 10 15 21 28 36 45 551..10の部分をオブジェクトに変更することも可能です。
qiita.rbfruits =["りんご","なし","さくらんぼ","みかん"] for i in fruits do p i end実行結果.rb"りんご" "なし" "さくらんぼ" "みかん"fruits配列の要素分処理を繰り返しています。
for文と同じことをeachメソッドでも記載することが可能です。each文
each文は以下のように記述します。
each.rbオブジェクト.each do |変数| 繰り返したい処理 endfor文と同じ処理をeachメソッドで記述すると・・・・
qiita.rbfruits =["りんご","なし","さくらんぼ","みかん"] fruits.each do |i| p i end実行結果.rb"りんご" "なし" "さくらんぼ" "みかん"同じ結果が得られました!
- 投稿日:2020-03-20T18:09:20+09:00
【Ruby】繰り返しについて
rubyの繰り返し文についてまとめておきます。
繰り返しを行うには?
以下のような構文又はメソッドを利用して繰り返し文を書くことが可能です。
今回はそれぞれの使い方をまとめて見ます。・timesメソッド
・for文
・eachメソッドtimesメソッド
一定の回数だけ同じ処理をさせたい場合はtimesメソッドを利用します。
qiita.rb5.times do p "りんご" end実行結果.rb"りんご" "りんご" "りんご" "りんご" "りんご"ブロック内で繰り返しの数値を使いたいときはdoの後に|変数|を加えます。
qiita.rb5.times do |i| p "りんご#{i+1}個を食す" end実行結果.rb"りんご1個を食す" "りんご2個を食す" "りんご3個を食す" "りんご4個を食す" "りんご5個を食す"for文
timesメソッドとは異なりfor文はメソッドではないので記述方法が異なります。
1から10まで加算する繰り返し文は以下のようにできます。qiita.rbsum =0 for i in 1..10 do p sum += i end実行結果.rb1 3 6 10 15 21 28 36 45 551..10の部分をオブジェクトに変更することも可能です。
qiita.rbfruits =["りんご","なし","さくらんぼ","みかん"] for i in fruits do p i end実行結果.rb"りんご" "なし" "さくらんぼ" "みかん"fruits配列の要素分処理を繰り返しています。
for文と同じことをeachメソッドでも記載することが可能です。each文
each文は以下のように記述します。
each.rbオブジェクト.each do |変数| 繰り返したい処理 endfor文と同じ処理をeachメソッドで記述すると・・・・
qiita.rbfruits =["りんご","なし","さくらんぼ","みかん"] fruits.each do |i| p i end実行結果.rb"りんご" "なし" "さくらんぼ" "みかん"同じ結果が得られました!
- 投稿日:2020-03-20T18:05:49+09:00
【Rails】スレッドのレス投稿機能
プログラミング初心者です。
Ruby on Railsで掲示板のスレッドにレスを紐付けて投稿していく機能を作成しました。
結構苦戦したので、備忘のため貼り付けます。【スレッド(親、tree)controller】
def show @tree = Tree.find(params[:id]) @response = Response.new(:tree_id => params[:id]) #ここを投稿用に使う @responses = @tree.responses.all end【レス(子、response)controller】
def create @response = current_user.responses.new(response_params) if @response.save redirect_to tree_url(@response.tree_id), notice: "投稿「#{@response.text}」を登録しました" else render tree_url(@response.tree_id) end end private def response_params params.require(:response).permit(:text, :user_id, :tree_id) end【スレッド(親、tree)viewのshow】
= form_with model: @response, url_for: { controller: :responses, action: :create }, local: true do |f| .form-group = f.label :text, "コメント" = f.text_field :text, class: "form-control", id: "response_text" = f.hidden_field :tree_id = f.submit "投稿", class: "btn btn-primary"【routes.rb】
post "/responses", to: "responses#create" resources :trees感想
特にルーティングエラーが多く発生しました。肝となるコードは以下の2点です。
# 入力フォーム url_for: { controller: :responses, action: :create }# ルーティング post "/responses", to: "responses#create"
- 投稿日:2020-03-20T17:31:23+09:00
[学習ログ]CVE-2020-5267について簡単に調べてみた[Rails]
tl;dr
CVE-2020-5267とは、バージョン6.0.2.2および5.2.4.2以前のActionViewに存在する脆弱性である。
該当バージョンのActionViewにおけるjおよびescape_javascriptメソッドにXSSの脆弱性が存在する可能性がある。railsの場合はGemfile中のrailsをバージョンアップすることで対策が可能
(6.0.2.2 or 5.2.4.2)
。
昨日、Githubから依存関係の脆弱性を指摘する以下のようなアラートが通知された。
We found potential security vulnerabilities in your dependencies.
Only the owner of this repository can see this message.
Manage your notification settings or learn more about vulnerability alerts.セキュリティアラートを確認すると、actionviewに関してアラートが出ていることが分かった。
Remediation
Upgrade actionview to version 5.2.4.2 or later. For example:
gem "actionview", ">= 5.2.4.2"
Always verify the validity and compatibility of suggestions with your codebase.CVE-2020-5267とは?
CVE-2020-5267についてググると、どうやらXSSに関する脆弱性らしい(私の認識が間違っていたら申し訳ないです)。
以下、コピペCVE-2020-5267 Detail
Description
In ActionView before versions 6.0.2.2 and 5.2.4.2, there is a possible XSS vulnerability in ActionView's JavaScript literal escape helpers. Views that use thej
orescape_javascript
methods may be susceptible to XSS attacks. The issue is fixed in versions 6.0.2.2 and 5.2.4.2.There is a possible XSS vulnerability in ActionView's JavaScript literal
escape helpers. Views that use thej
orescape_javascript
methods
may be susceptible to XSS attacks.
Versions Affected: All.
Not affected: None.
Fixed Versions: 6.0.2.2, 5.2.4.2補足:XSS(クロスサイトスクリプティング)とは?
クロスサイトスクリプティングとは、攻撃者の作成したスクリプトを脆弱性のある標的サイトのドメインの権限において閲覧者のブラウザで実行させる攻撃一般を指す。
CVE-2020-5267による影響
この脆弱性を利用した際のコードの一例も載せておきます
<script>let a = `<%= j unknown_input %>`</script> <script>let a = `<%= escape_javascript unknown_input %>`</script>CVE-2020-5267の対処方法(Railsの場合)
対処方法については二種類ある。
1.Railsのバージョンを更新する
冒頭で述べた通り、Railsのバージョンを6.0.2.4か5.2.4.2に更新することで、Railsに依存しているactionviewのバージョンを更新する。
一例Gemfile - gem 'rails' ~>"5.1.4.2" + gem 'rails' ~>"5.2.4.2"https://weblog.rubyonrails.org/2020/3/19/Rails-6-0-2-2-and-5-2-4-2-has-been-released/
2.モンキーパッチをあてる
Railsのバージョンを更新できない場合は、以下のようなモンキーパッチをあてて対処する。
ActionView::Helpers::JavaScriptHelper::JS_ESCAPE_MAP.merge!( { "`" => "\\`", "$" => "\\$" } ) module ActionView::Helpers::JavaScriptHelper alias :old_ej :escape_javascript alias :old_j :j def escape_javascript(javascript) javascript = javascript.to_s if javascript.empty? result = "" else result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP) end javascript.html_safe? ? result.html_safe : result end alias :j :escape_javascript endhttps://github.com/rails/rails/security/advisories/GHSA-65cv-r6x7-79hv
- 投稿日:2020-03-20T17:10:31+09:00
Sinatraでタスク管理アプリ作ってみた
概要
環境構築〜MVCの動きが一通り表現できるまでの道のりを解説します。
ruby on Railsを用いて、Webアプリを作成した経験があったので、MVCの動きをどのように表現できるのかを確認する練習として作成しました。
ruby on Railsでアプリケーションを作成したことがある人向けへの説明になります。環境構築編
ruby,rails,mysqlがインストールされている前提での説明になります。
mysqlでのテーブル作成に関しての説明は他の記事に譲ります。
今回はDB名:sinatra_practice、テーブル名:commentとしています。sinatraのインストール
Sinatraとは、軽量なWebアプリケーションフレームワークです。
gemとして用意されているので、下記のコマンドでインストールします。sinatra.commandgem install sinatra
sinatra_contribのインストール
sinatra_contribとは、コードを変更した際、Webサーバーを再起動せずに変更点を反映してくれるgemです。
このgemは必須ではないですが、開発がとても効率的になるので、インストールすることをおすすめします。gem install sinatra-contrib実装編
まずフォルダ構造、完成コードを掲載します。
フォルダ構造.. ├── myapp.rb ├── views │ ├── index.erbmyapp.rbrequire 'sinatra' require 'sinatra/reloader' require 'active_record' ActiveRecord::Base.establish_connection( adapter: "mysql2", host: "localhost", username: "root", password: "", database: "sinatra_practice", socket: "/tmp/mysql.sock" ) class Comment < ActiveRecord::Base end get "/" do @comments = Comment.all erb :index end post "/new" do Comment.create({body: params[:body]}) redirect '/' end post "/delete" do puts params Comment.find(params[:id]).destroy redirect '/' endindex.erb<!DOCTYPE html> <html lang="ja"> <head> <mata charset="utf-8"> <title>ToDo</title> </head> <body> <h1>ToDoリスト</h1> <ul> <% @comments.each do |comment| %> <li data-id= "<%= comment.id %>"> <%= comment.body %> <form method="post" action="/delete"> <input type="hidden" name="id" value="<%= comment.id %>"> <input type="submit" value="done!"> </form> </li> <% end %> </ul> <form method="post" action="/new"> <input type= "text" name="body"> <input type= "submit" value="追加"> </form> </body> </html>myapp.rbに関して
ruby on Railsを触ったことがある人向けへの解説ですが、普段あまり意識しないことも記載しておきます。
- require
- ライブラリの読み込み
- sinatra/reloaderは環境構築でインストールしたinatra-contribの変更を自動反映してくれる
- active_recordはDBのデータをRubyオブジェクトとして扱えるようにするもの
- railsのインストールが必要
- ActiveRecord::Base.establish_connection
- DBへの接続情報を指定
まとめ
SinatraはMVCを意識せずミニアプリを作成するにはもってこいだと感じました。
コードが動かない、記載について詳しく解説してほしい等あったらご連絡ください
- 投稿日:2020-03-20T17:06:16+09:00
Railsのtext_fieldにCSSをあてる方法
text_fieldにCSSってどうやってあてるんだっけ?
Railsアプリケーション作成時にフロント部分を作成していた時に
example.haml.html.item__name 商品名 .name--input = f.text_field :name, placeholder: "40文字まで"のようなhamlを作成していざscssを記述しようとしたときに
このtext_filed
にどうやってCSSをあてるのかが
ふと考えると分からなかったんです。同じような
number_field
やsubmit
などにも使えるやり方なので
是非覚えておいたほうがよいです。そもそも
text_field
で作られるHTMLは何なのか?上の
= f.text_field :name, placeholder: "40文字まで"
で作られるHTMLを
chromeの検証で確認してみると
<input placeholder="40文字まで" type="text" name="item[name]" id=item_name>
というものが作成されているのがわかるかと思います。text_fieldとかはRailsがviewを簡潔に記述するために用意してくれているヘルパーメソッドのため
簡単な記述で実際はこういうHTML文の作成もしてくれています。
この作成されたHTMLにあてるようにCSSを記述すればOKです。今回はSCSSを使い記述しました。
CSSをあててみよう
example.scss.item__name{ input[type="text"]{ width: 100%; height: 20px; font-size: 14px; } ::placeholder{ padding: 5px 5px; } }と指定して記述すると、
text_field
にCSSをあてることができます。
placholder
はCSSの擬似要素のため上記のような記述をする必要があります。ヘルバーメソッドを使って記述した場合にどのようなHTML文が作成されているのかを確認すると解決できる部分でしたね。
参考先
- 投稿日:2020-03-20T16:47:10+09:00
Railsチュートリアルメモ - 第12章
(メモの目次記事はこちら)[https://qiita.com/yokohama4580/items/dedfd5510080273dc2a0]
(公式Railsチュートリアル第12章へのリンク)[https://railstutorial.jp/chapters/password_reset?version=5.1#cha-password_reset]
サマリ
- パスワードの再設定
- パスワード再設定メールの送信
- トークンによる認証とパスワードの再設定
ポイント
- パスワードリセット機能はUserモデルを拡張して使用するため、MVCのうち新たに作成するのはViewとControllerのみで良い
- 処理のコントローラーのアクションがいろいろ登場するので、流れを整理しないと混乱する
sessions/new.html.erb →password_resets_controller#new →password_resets/new.html.erb →password_resets_controller#create →メール送信 →password_resets_controller#edit →password_resets/edit.html.erb →password_resets#update
@user.authenticated?(:reset, params[:id])
でresetトークンとDBに保存されたダイジェストを照合する- パスワード再設定用メールを送信する際に、パスワードリセットトークンとダイジェストを生成する。
- トークンはメール内のリンクに埋め込んでユーザーに送付する
- ダイジェストはDBに保存し、リンクが開かれた際に両者を照合して本人であることを確認する
- #edit時点では、メール内のリンクに埋め込んだURLパラメーターからメールアドレスを取得できるが、#updateは画面から呼び出すので、同じ方法でメールアドレスを取得することができない。そのため、edit.html.erbの中の隠しフィールドにメールアドレスを持たせて#updateに引き渡す。
<%= hidden_field_tag :email, @user.email %>
感想
- 11章と内容的にはほぼ同じだったが、その分説明が少なくて少し混乱した
- herokuでの動作は問題なかったが、ローカル動作時にパスワード再設定用リンクを開こうとすると画面に
このサイトは安全に接続できませんlocalhostから無効な応答が送信されました。
と表示され、ログに以下が吐かれてしまった2020-03-18 02:53:45 +0900: HTTP parse error, malformed request (): #<Puma::HttpParserError: Invalid HTTP format, parsing fails.>
- 原因はメールリンクがhttpsになっているためで、httpでリンクを開くと画面が正常に表示された
- localhostにhttpsで繋ぐ場合は少し追加の設定が必要 参考記事
- 投稿日:2020-03-20T14:36:55+09:00
Railsでページ毎にsubmitの表記を変えたい
submitボタンの表記を変えたい
submitボタンを実装した場合、デフォルトの日本語表記は下記のような形で表示されます
(色付けなどはCSSで加工済み)'登録する' というのがデフォルトのsubmitボタンとなります。
例えば、作成しているアプリで商品出品するページでは当然、'出品する'という表記にしたいですよね。
しかし、商品を編集して更新する場合は、'出品する'だと違和感があるので
'更新する'と表記をしたいところです。しかし、出品も更新も同じフォームを流用しているので
分岐分けで記入する必要があるところになります。単純にsunmitボタンのテキストを変えたい場合なら
<input type="submit" value="出品する">
を使えば表記は変わるわけなのですが、上記のように分岐わけさせたいときにどうするべきか。
出品と更新のページを別々に作って、各々でテキスト表記を変えるという手段もできますが
メンテナンス上、ほぼ同じ記述のコードのファイルが増えてしまうのは避けたいところです。ja.ymlを利用して分岐させる
ja.ymlといえば、英語表記を日本語化させる指定を記述する場所なのですが
こちらでアクション毎にsubmitの表記を指定させることができます。まずはi18nの導入が必要なので参考先にあるページを参照に導入を済ませておいてください
[初学者]Railsのi18nによる日本語化対応
config/locales/ja.yml
に記述するja.ymlja: helpers: submit: create: "出品する" update: "更新する"このように記述をするとcreate下のsubmitは出品すると表示され
update下のsubmitは更新すると表示されるようになります。実際にcreate時はこのように変更がかかります。
update画面も同様に記述した通りの変更がかかります。これでhtmlをcreateとupdateで別々に表記を分ける必要がなくなるので
ファイルを増やすことなく分岐して表示させることができます。参考先
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-submit
- 投稿日:2020-03-20T14:10:51+09:00
[scss]hamlへの反映方法は2種類あった 備忘録
今までscssのhamlへの反映方法といったら
application.scss
へ@import記述のみと思っていましたが。実はそんなことをしなくてもコマンド入力で作成したscssには
自動的に反映される記述が入っているんです。
知りませんでした。。。
コメントアウトされ得た以下の3行があるとOKらしいscss// Place all the styles related to the reset controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ですので、scssの反映方法を以下2種類をまとめたいと思います
コマンドで作成する方法
importいらないコマンド存在したー!!!
ターミナル$ rails g assets 作成したいファイル名以上です。
あとはscssに記述したものは自動的にhamlに反映されます。手動でファイルを作成する方法
右クリックでファイル作成をした場合scssにimport記述は自動生成されませんので
application.scss
にimportしてhamlにscssが当たるようにしましょう。やり方
・hamlに反映させたいscssのファイル名をアンダーバー「 _ 」始まりにします。
・application.scss
にimportします。
・終わり記述参考は下記
application.scss@import "home"; @import "いれたいscssファイル名(アンダーバーは入れない)"; ⬅︎終わりは必ずセミコロンを入れる #assetsの中でもフォルダの異なるものはURLをちゃんと記載しないと反映されない @import "config/reset"; @import "フォルダ名/ファイル名";参照記事
終わりに
自分のいた学校は極力コマンドを使用しない学校でしたが
コマンドはコマンドで別の仕様があることを今回知りました。
アウトプットもそうですがインプットも必要。
人との情報交換は本当に大事だなと改めて感じました。初学者な為、記事に不備やアドバイ等ございましたらご連絡頂けますと幸いです。
最後まで読んできただきありがとうございます。
- 投稿日:2020-03-20T12:37:38+09:00
【ruby】シーザー暗号を読み解く
シーザー暗号と呼ばれる、アルファベットをある文字数分ずらすという暗号方式をrubyで解読してみます。
3文字数分ずらし(戻し)暗号を解読してみます。
def to_decode(char) char_ary = char.split("") # => ["k","h","o","o","r"] changed_char_ary = [] # 空の配列を用意 char_ary.each do |char| changed_char_ary << (char.ord - 3).chr # 3を引いた文字コードを文字列に変換する =>["h","e","l","l","o"] end puts changed_char_ary.join # => "hello" end char = "khoor" to_decode(char)
- 投稿日:2020-03-20T12:23:07+09:00
【Rails】form_withについて簡単にまとめた
はじめに
form_with
について使いかたを簡単にまとめてみました。
今回はRubyonRailsAPIを色々と参照しました。form_withの機能
フォームを構成するヘルパーメソッド。
form_tag
やform_for
と同じような挙動をするが、
現在はform_with
を使用することが推奨されている。基本的な構文は下記のとおり。
= form_with model: @user do |f| = f.text_field :name = f.submit '登録'テキストフィールドに名前を入力して「登録」をおすとデータが送信される。
このとき、データはハッシュの階層構造であるparams[:user][:name]
という形で送信される。
よってコントローラーでストロングパラメーターを用いる際は下記のようになる。def user_params params.require(:user).permit(:name) endデータの送信先については、
:url
オプションを追加することによっても指定できるが、
渡されたモデルの状態(①新規②既存)によって自動推定をしてくれる。①新規作成されたモデルが渡された場合= form_with model: User.new do |f| = f.text_field :name①で生成されるHTML<form action="/users" method="post" data-remote="true"> <input type="text" name="user[name]"> </form>②既存のモデルが渡された場合= form_with model: User.first do |f| = f.text_field :name②で生成されるHTML<form action="/users/1" method="post" data-remote="true"> <input type="hidden" name="_method" value="patch"> <input type="text" name="user[name]" value="<the name of the user>"> </form>①のパターンでは、
action="/users"
であるのに対して、
②のパターンではaction="/users/1"
となっている上に隠しinputフィールドを利用してメソッドをPatch
に指定している。
これにより、上記①②のパターンでそれぞれ対応するアクションがcreate
になったりupdate
になったりする。ビュー上に表示しないものを送信したいとき
hidden_field
を使用することに対応可能。= form_with model: @user do |f| = f.hidden_field :age, :value => @user.age #ビューに表示されない = f.text_field :name = f.submit上記のように記載をすることで、ビュー上には表示されないが
params[:user][:age]
の中に
@user.age
の値を格納した状態でデータを送ることができる。ビュー上に表示させたいが編集はさせたくないとき
readonly: true
を指定すればOK。= form_with model: @user do |f| = f.text_field :name = f.text_field :age, value: @user.age, readonly: true #ビューに表示されるが編集不可 = f.submitまとめ
form_with
の仕組みが腹落ちしました。
特にモデルの状態の違いから生成されるhtmlが変わり、結果として対応するアクションが自動的に決まる仕組みのあたりは今まで曖昧な理解だったので今回がいい機会になりました。
- 投稿日:2020-03-20T10:27:40+09:00
SequelでPG::ConnectionBad: PQconsumeInput()エラーが出るようになって困った話
急に出始めた PG::ConnectionBad: PQconsumeInput() エラー
RailsでActiveRecordを使わずSequelをORMとして使っているのだが、いつからかRails起動直後のRDS(Postgresql)接続時に「PG::ConnectionBad: PQconsumeInput()」エラーが出るようになってしまった。
PG::ConnectionBad: PQconsumeInput() SSL error: decryption failed or bad record mac PG::ConnectionBad: PQconsumeInput() server closed the connection unexpectedly PG::ConnectionBad: PQconsumeInput() SSL error: sslv3 alert bad record macSequel側は変えていないのでRDSで何か仕様変更があったのか・・・。RDSのCA証明書の変更の影響かと思ったが、変更する前から当エラーは出てた。
状況
- Rails起動直後にいくつかのリクエストでこのエラーになる。全てではない。
- ある程度エラーが出るとその後は出ない。
- ステージング環境などで8時間くらいアクセスがないとまたでるようになる。
- なので、本番環境ではRails再起動直後だけこのエラーがでる。
- 開発環境のRDSではないPostgresqlだと出ない。
このエラーが出たらretryする仕組みも入れたけど、やはりそもそも出ないようにしたい。
connection_validatorを試す
真偽はわからないがpumaのようなマルチスレッドのアプリケーションサーバを使っているとこのエラーが出るらしい。Sequelのコネクションプーリングがスレッドセーフではない?
で、色々ググったところ日本語の情報はさっぱりの中、海外のサイトで以下の設定を入れれば解決するらしい情報を入手。
DB.extension(:connection_validator) DB.pool.connection_validation_timeout = -1https://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/connection_validator_rb.html
コネクションプーリング内のコネクションが有効かどうかチェックして、有効でなければ再接続する設定。
DB.pool.connection_validation_timeout
はチェックする間隔(秒)で、デフォルト3600秒、−1のときは常にチェック。connection_validation_timeoutの値を変えて検証
- -1: エラーが出なくなった!
- 1以上: 起動直後はエラーでる
検証結果
DB.pool.connection_validation_timeout = -1
なら効果あり。
3600で効果出て欲しかったなあ。パフォーマンス試験
公式にもあるように、常にチェックだと気になるのがパフォーマンスの劣化。
connection_validatorありなしでApacheBenchでパフォーマンステストしてみた。connection_validatorなし
$ ab -c 100 -n 10000 "http://xxxxxxxxxx" Concurrency Level: 100 Time taken for tests: 22.620 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 15650000 bytes HTML transferred: 11390000 bytes Requests per second: 442.09 [#/sec] (mean) Time per request: 226.196 [ms] (mean) Time per request: 2.262 [ms] (mean, across all concurrent requests) Transfer rate: 675.66 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.4 0 5 Processing: 5 226 162.3 178 1102 Waiting: 5 226 162.3 178 1102 Total: 5 226 162.3 178 1102connection_validatorあり (connection_validation_timeout = -1)
$ ab -c 100 -n 10000 "http://xxxxxxxxxx" Concurrency Level: 100 Time taken for tests: 26.522 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 15650000 bytes HTML transferred: 11390000 bytes Requests per second: 377.05 [#/sec] (mean) Time per request: 265.216 [ms] (mean) Time per request: 2.652 [ms] (mean, across all concurrent requests) Transfer rate: 576.26 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 2 Processing: 10 264 157.8 231 1126 Waiting: 10 264 157.8 231 1126 Total: 10 264 157.9 231 1126(結果は3回試して一番良かった結果)
テスト結果
1リクエストあたり約40ms遅くなった。
結論
超絶負荷のかかる様なサーバではないので、40msのパフォーマンス劣化は許容範囲としてconnection_validatorを採用することにした。
auto_reconnectオプションとかあれば良いのに。
- 投稿日:2020-03-20T10:21:38+09:00
Rails deviseの導入〜新規登録、ログイン時のカラムの追加まで
初めに
某プログラミングスクールの卒業生です。
スクールに通う中で学んだことや、つまづいたことを備忘録としてまとめてます。
今回は、deviseを扱う際に必ず調べるであろう、独自カラムの追加方法をdeviseの導入からまとめておきたいと思います。環境
・Ruby 2.5.7
・Rails 5.2.4.1deviseの導入
deviseとは、ログインや新規登録機能等を簡単に実装できるgemです。
まず初めに、Gemfileに以下の1行追加して保存します。Gemfilegem 'devise'次にターミナルで下記を実行し、deviseをアプリケーションに読み込ませます。
$ bundle install最後にターミナルで下記を実行し、deviseの初期設定を行います。
$ rails g devise:installRunning via Spring preloader in process 29980 create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================ターミナルに上記のような表示がされれば成功です。
以上でdeviseを使う準備が整いました。deviseでモデルを作成する
準備が整ったので、いよいよdeviseを使ってみましょう。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきます。
まず初めに、モデルを作成します。
ターミナルで下記のを実行し、モデルを作成します。$ rails g devise UserRunning via Spring preloader in process 30045 invoke active_record create db/migrate/20200319222813_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :usersこれで、「User」という名のモデルと、usersテーブル用のマイグレーションファイルが作成されました。
独自のカラムを追加しよう
モデルとマイグレーションファイルの作成ができたので、usersテーブルにカラムを追加しいきましょう。
今回はnameカラムを追加します。
先ほど、作成したマイグレーションファイルに以下の1行を追加します。20200319222813_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :name, null: false ←追加 ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at 以下省略追加したら、ターミナルでマイグレーションを実行しましょう。
$ rails db:migrate実際にカラムが追加できたかschemaファイルで確認します。
schema.rbActiveRecord::Schema.define(version: 2020_03_19_222813) do create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "name", null: false ←追加されている t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end追加されていることが確認できれば成功です。
Viewを追加しよう
カラムの追加がおわったら、次にViewを作成しましょう。
ターミナルで下記を実行しましょう。$ rails g devise:viewsinvoke Devise::Generators::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erbこれでdevise用のViewを作成する事ができました。
deviseをカスタマイズしよう
Viewが作成できたので、いよいよdeviseをカスタマイズしていきます。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきたいと思います。新規登録画面に名前を追加
deviseの新規登録画面はデフォルトで、以下のようになっています。
今回はここに名前(Name)を追加します。
新規登録のViewにNameを追加します。
以下を参考に追加してみてください。
※registrationsが新規登録のviewなので覚えておきましょうviews/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記で名前が追加できた事が確認できます。
これではまだ、名前の登録がデータベースに反映されません。
なので、最後にストロングパラメーターを設定しましょう。controllers/application_controller.rbclass ApplicationController < ActionController::Base # ここから before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end # ここまで endこれでデータベースに名前が登録できるようになりました。
今後、カラムを増やす場合はストロングパラメーターにも忘れずに追加しましょう。名前とパスワードでログインできるように変更
deviseのログイン画面はデフォルトで、以下のようになっています。
今回はEmailを名前(Name)に変更します。
ログインのViewをEmailからNameを変更します。
以下を参考に変更してみてください。
※sessionsがログインのviewなので覚えておきましょうviews/devise/sessions/new.html.erb<h2>Log in</h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで追加 %> <%# ここから %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <%# ここまで削除 %> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit "Log in" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記でEmailが名前(Name)が変更できた事が確認できます。
これではまだ、名前でのログインができません。
devise.rbを書き換えて名前でのログインができるように変更します。config/initializers/devise.rb# ==> Configuration for any authentication mechanism # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. # config.authentication_keys = [:email]devise.rbの中に上記のような記述があるかと思います。
その一番下の行をを変更してください。
※#を外すのを忘れないように注意してください。config/initializers/devise.rb# config.authentication_keys = [:email] ↓ 変更 config.authentication_keys = [:name]これで名前をとパスワードでログインできるようになりました。
以上で新規登録とログインのカスタマイズが終わります。最後に
備忘録程度のまとめになっているので、もしかしたら分かりにくいかもしれませんがご了承ください。
この投稿が少しでも役に立つ事があれば幸いです。
- 投稿日:2020-03-20T10:21:38+09:00
Rails deviseの導入〜新規登録、ログイン時のカラム
初めに
某プログラミングスクールの卒業生です。
スクールに通う中で学んだことや、つまづいたことを備忘録としてまとめてます。
今回は、deviseを扱う際に必ず調べるであろう、独自カラムの追加方法をdeviseの導入からまとめておきたいと思います。環境
・Ruby 2.5.7
・Rails 5.2.4.1deviseの導入
deviseとは、ログインや新規登録機能等を簡単に実装できるgemです。
まず初めに、Gemfileに以下の1行追加して保存します。Gemfilegem 'devise'次にターミナルで下記を実行し、deviseをアプリケーションに読み込ませます。
$ bundle install最後にターミナルで下記を実行し、deviseの初期設定を行います。
$ rails g devise:installRunning via Spring preloader in process 29980 create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================ターミナルに上記のような表示がされれば成功です。
以上でdeviseを使う準備が整いました。deviseでモデルを作成する
準備が整ったので、いよいよdeviseを使ってみましょう。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきます。
まず初めに、モデルを作成します。
ターミナルで下記のを実行し、モデルを作成します。$ rails g devise UserRunning via Spring preloader in process 30045 invoke active_record create db/migrate/20200319222813_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :usersこれで、「User」という名のモデルと、usersテーブル用のマイグレーションファイルが作成されました。
独自のカラムを追加しよう
モデルとマイグレーションファイルの作成ができたので、usersテーブルにカラムを追加していきましょう。
今回はnameカラムを追加します。
先ほど、作成したマイグレーションファイルに以下の1行を追加します。20200319222813_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :name, null: false ←追加 ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at 以下省略追加したら、ターミナルでマイグレーションを実行しましょう。
$ rails db:migrate実際にカラムが追加できたかschemaファイルで確認します。
schema.rbActiveRecord::Schema.define(version: 2020_03_19_222813) do create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "name", null: false ←追加されている t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end追加されていることが確認できれば成功です。
Viewを追加しよう
カラムの追加がおわったら、次にViewを作成しましょう。
ターミナルで下記を実行しましょう。$ rails g devise:viewsinvoke Devise::Generators::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erbこれでdevise用のViewを作成する事ができました。
deviseをカスタマイズしよう
Viewが作成できたので、いよいよdeviseをカスタマイズしていきます。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきたいと思います。新規登録画面に名前を追加
deviseの新規登録画面はデフォルトで、以下のようになっています。
今回はここに名前(Name)を追加します。
新規登録のViewにNameを追加します。
以下を参考に追加してみてください。
※registrationsが新規登録のviewなので覚えておきましょうviews/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記で名前が追加できた事が確認できます。
これではまだ、名前の登録がデータベースに反映されません。
なので、最後にストロングパラメーターを設定しましょう。controllers/application_controller.rbclass ApplicationController < ActionController::Base # ここから before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end # ここまで endこれでデータベースに名前が登録できるようになりました。
今後、カラムを増やす場合はストロングパラメーターにも忘れずに追加しましょう。名前とパスワードでログインできるように変更
deviseのログイン画面はデフォルトで、以下のようになっています。
今回はEmailを名前(Name)に変更します。
ログインのViewをEmailからNameを変更します。
以下を参考に変更してみてください。
※sessionsがログインのviewなので覚えておきましょうviews/devise/sessions/new.html.erb<h2>Log in</h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで追加 %> <%# ここから %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <%# ここまで削除 %> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit "Log in" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記でEmailが名前(Name)が変更できた事が確認できます。
これではまだ、名前でのログインができません。
devise.rbを書き換えて名前でのログインができるように変更します。config/initializers/devise.rb# ==> Configuration for any authentication mechanism # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. # config.authentication_keys = [:email]devise.rbの中に上記のような記述があるかと思います。
その一番下の行をを変更してください。
※#を外すのを忘れないように注意してください。config/initializers/devise.rb# config.authentication_keys = [:email] ↓ 変更 config.authentication_keys = [:name]これで名前をとパスワードでログインできるようになりました。
以上で新規登録とログインのカスタマイズが終わります。最後に
備忘録程度のまとめになっているので、もしかしたら分かりにくいかもしれませんがご了承ください。
この投稿が少しでも役に立つ事があれば幸いです。
- 投稿日:2020-03-20T10:21:38+09:00
Rails deviseの導入〜新規登録、ログイン時のカラム追加まで
初めに
某プログラミングスクールの卒業生です。
スクールに通う中で学んだことや、つまづいたことを備忘録としてまとめてます。
今回は、deviseを扱う際に必ず調べるであろう、独自カラムの追加方法をdeviseの導入からまとめておきたいと思います。環境
・Ruby 2.5.7
・Rails 5.2.4.1deviseの導入
deviseとは、ログインや新規登録機能等を簡単に実装できるgemです。
まず初めに、Gemfileに以下の1行追加して保存します。Gemfilegem 'devise'次にターミナルで下記を実行し、deviseをアプリケーションに読み込ませます。
$ bundle install最後にターミナルで下記を実行し、deviseの初期設定を行います。
$ rails g devise:installRunning via Spring preloader in process 29980 create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================ターミナルに上記のような表示がされれば成功です。
以上でdeviseを使う準備が整いました。deviseでモデルを作成する
準備が整ったので、いよいよdeviseを使ってみましょう。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきます。
まず初めに、モデルを作成します。
ターミナルで下記のを実行し、モデルを作成します。$ rails g devise UserRunning via Spring preloader in process 30045 invoke active_record create db/migrate/20200319222813_devise_create_users.rb create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb route devise_for :usersこれで、「User」という名のモデルと、usersテーブル用のマイグレーションファイルが作成されました。
独自のカラムを追加しよう
モデルとマイグレーションファイルの作成ができたので、usersテーブルにカラムを追加していきましょう。
今回はnameカラムを追加します。
先ほど、作成したマイグレーションファイルに以下の1行を追加します。20200319222813_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :name, null: false ←追加 ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at 以下省略追加したら、ターミナルでマイグレーションを実行しましょう。
$ rails db:migrate実際にカラムが追加できたかschemaファイルで確認します。
schema.rbActiveRecord::Schema.define(version: 2020_03_19_222813) do create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "name", null: false ←追加されている t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end追加されていることが確認できれば成功です。
Viewを追加しよう
カラムの追加がおわったら、次にViewを作成しましょう。
ターミナルで下記を実行しましょう。$ rails g devise:viewsinvoke Devise::Generators::SharedViewsGenerator create app/views/devise/shared create app/views/devise/shared/_error_messages.html.erb create app/views/devise/shared/_links.html.erb invoke form_for create app/views/devise/confirmations create app/views/devise/confirmations/new.html.erb create app/views/devise/passwords create app/views/devise/passwords/edit.html.erb create app/views/devise/passwords/new.html.erb create app/views/devise/registrations create app/views/devise/registrations/edit.html.erb create app/views/devise/registrations/new.html.erb create app/views/devise/sessions create app/views/devise/sessions/new.html.erb create app/views/devise/unlocks create app/views/devise/unlocks/new.html.erb invoke erb create app/views/devise/mailer create app/views/devise/mailer/confirmation_instructions.html.erb create app/views/devise/mailer/email_changed.html.erb create app/views/devise/mailer/password_change.html.erb create app/views/devise/mailer/reset_password_instructions.html.erb create app/views/devise/mailer/unlock_instructions.html.erbこれでdevise用のViewを作成する事ができました。
deviseをカスタマイズしよう
Viewが作成できたので、いよいよdeviseをカスタマイズしていきます。
今回は、ユーザー登録時の名前の追加と、ログイン時は名前とパスワードでログインできるようにカスタマイズしていきたいと思います。新規登録画面に名前を追加
deviseの新規登録画面はデフォルトで、以下のようになっています。
今回はここに名前(Name)を追加します。
新規登録のViewにNameを追加します。
以下を参考に追加してみてください。
※registrationsが新規登録のviewなので覚えておきましょうviews/devise/registrations/new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autocomplete: "email" %> </div> <div class="field"> <%= f.label :password %> <% if @minimum_password_length %> <em>(<%= @minimum_password_length %> characters minimum)</em> <% end %><br /> <%= f.password_field :password, autocomplete: "new-password" %> </div> <div class="field"> <%= f.label :password_confirmation %><br /> <%= f.password_field :password_confirmation, autocomplete: "new-password" %> </div> <div class="actions"> <%= f.submit "Sign up" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記で名前が追加できた事が確認できます。
これではまだ、名前の登録がデータベースに反映されません。
なので、最後にストロングパラメーターを設定しましょう。controllers/application_controller.rbclass ApplicationController < ActionController::Base # ここから before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end # ここまで endこれでデータベースに名前が登録できるようになりました。
今後、カラムを増やす場合はストロングパラメーターにも忘れずに追加しましょう。名前とパスワードでログインできるように変更
deviseのログイン画面はデフォルトで、以下のようになっています。
今回はEmailを名前(Name)に変更します。
ログインのViewをEmailからNameを変更します。
以下を参考に変更してみてください。
※sessionsがログインのviewなので覚えておきましょうviews/devise/sessions/new.html.erb<h2>Log in</h2> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> <%# ここから %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true %> </div> <%# ここまで追加 %> <%# ここから %> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> <%# ここまで削除 %> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password, autocomplete: "current-password" %> </div> <% if devise_mapping.rememberable? %> <div class="field"> <%= f.check_box :remember_me %> <%= f.label :remember_me %> </div> <% end %> <div class="actions"> <%= f.submit "Log in" %> </div> <% end %> <%= render "devise/shared/links" %>上記の追記でEmailが名前(Name)が変更できた事が確認できます。
これではまだ、名前でのログインができません。
devise.rbを書き換えて名前でのログインができるように変更します。config/initializers/devise.rb# ==> Configuration for any authentication mechanism # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. # config.authentication_keys = [:email]devise.rbの中に上記のような記述があるかと思います。
その一番下の行をを変更してください。
※#を外すのを忘れないように注意してください。config/initializers/devise.rb# config.authentication_keys = [:email] ↓ 変更 config.authentication_keys = [:name]これで名前をとパスワードでログインできるようになりました。
以上で新規登録とログインのカスタマイズが終わります。最後に
備忘録程度のまとめになっているので、もしかしたら分かりにくいかもしれませんがご了承ください。
この投稿が少しでも役に立つ事があれば幸いです。
- 投稿日:2020-03-20T09:45:03+09:00
Kinx 実現技術 - Yacc/Bison
コンパイラ・コンパイラの話
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。作ったものの紹介だけではなく実現のために使った技術を紹介していくのも誰の役に立つかもしれないしね。その道の人には当たり前でも、そうでない人にも興味をもって貰えるかもしれないので。ソースを具体的にさらすのは(アドホックにやってる部分もあるので)多少恥ずかしいが、どうせ OSS にしてるし、まぁいいか。
最初のテーマは構文解析。なお、以下のような感じで記事をプランしてみる。
- コンパイル時編
- 構文解析 ... Bison を使っている。kmyacc に変えるかもしれない。(本記事)
- Switch-Case ... 色々条件を判断。結構複雑。
- 実行時編
- VM(Virtual Machine) ... gcc ではダイレクト・スレッディング。
- Garbage Collection ... ザ・マーク・アンド・スイープ。静的スコープの扱い。
- JIT ... ネイティブの機械語コードにコンパイルするために採用した方法。
- Fiber ... 思い付きで実装したら割と動いたのでその方法。
Kinx での構文解析
Yacc/Bison とは
Kinx での構文解析は今現在 GNU Bison を使っている。いわゆる LALR(1) の Yacc 系統のパーサ・ジェネレータ。コンパイラを作る時のジェネレータであるため、俗に コンパイラ・コンパイラ と呼ばれている。GNU Bison 自体は GPLv2 だが、その出力(パーサ自体)は例外条項によって自分でライセンスを付けることができる。
元々コンパイラを書く場合、手書きの再帰下降構文解析で実装するのが好きだったのだが、あとから文法を理解しやすい、変えやすいという点で Yacc にしよう、と思ったので使った。最初は miniyacc という簡易 Yacc を使っていたのだが、エラーリカバリ処理がない という致命的な弱点のため現在は GNU Bison を使うように修正。ただ、Windows で Bison を使うのは面倒なのでここだけ Linux で修正する、という作業が非常に面倒くさいことになっている。それもあって、kmyacc に乗り換えようかなー、というのが現時点のステータス。
ちなみに、再帰下降構文解析(再帰下降パーサ)とは、BNF で書いた時の構文ルールを関数呼び出しの形で表したもの。結構書いてて面白い。例えば、
expr
→ ... →factor
という流れで、factor
には'(' expr ')'
が定義されているとき、factor
関数の中で'('
を認識したら再帰的にexpr
関数を呼ぶことで構文解析していく。トップダウン的に下方向に向かって解析し、途中再帰的に上に戻ってくるので再帰下降と呼ばれている。詳しくは Wikipedia も参照してみるといいかも。構文解析・字句解析
構文定義ファイルは src/kinx.y にあり、構文自体は BNF という記法で書く。尚、Yacc(Bison) の動きに関しては、Rubyソースコード完全解説 にある 第9章 速習yacc がわかりやすくて良いと思ったので紹介しておきます。
今回作ったパーサに関して、特徴的なところをピックアップしてみよう。
字句解析部分
コンパイラを作る場合、実は構文解析の前に 字句解析 というフェーズが入る。だいたい以下のような流れで進む。
字句解析 ↓ 構文解析 ↓ 意味解析字句解析は yacc と対になって lex というツール(Bison の場合 flex)を使うのも標準的なのだが、私は lex は使わない。字句解析は手書きしている。src/lexer.c がソース。いろいろなステータスを細かく制御するのに都合がいいし、手書きでもそれほど面倒な処理ではないので、今回も手書きした。このほうが都合が良いのは、例えば、
using
のような構文は、字句解析レベルで実施しており、入力ソースを動的に入れ替えるようになっている。一般的に構文解析では、主に 見た目 だけ扱う。見た目さえ正しければよい。内容が妥当かどうかは次の意味解析のフェーズで行う。
正規表現リテラル
あと、Factor のところに正規表現リテラルが来るのだが、字句解析レベルで
/=
を DIVEQ と認識してしまっているので、DIVEQ が来た時に/=
で始まった正規表現リテラルと判断するようにしている。状態遷移的に DIVEQ として扱われる場所と異なるのでこれはコンフリクトしない。正規表現の最初の文字が=
であることをきちんと認識すればよいという感じで扱った。kmyacc について
kmyacc は森公一郎氏(故人)が作った素晴らしいパーサ・ジェネレータ。非常に昔からお世話になっているツールの一つ。Yacc を使おうというときはたいがいこれを使っていた。なぜ今回使っていなかったのか、それはビルド環境に yacc 含めたかったのでライセンスの緩い miniyacc にしたから(MIT License)。現時点では Bison に変えてしまったので kmyacc で全然かまわない。正直、森氏は後世に名を遺すべき人であって、kmyacc も遺しておくべき作品だと思う。彼が亡くなったとき(2015年)は、それはもう日本のプログラミング業界でひと騒動あったのも記憶に新しい。
森氏は LSI-C の作者でもあり、試食版というフリーの LSI-C にも(かなり)昔お世話になった。出力アセンブラが美しいことで有名だ。実際、当時は C では遅いのでサブルーチンはアセンブラで書く ということをやっており、これは今でいう Java は遅いのでライブラリは JNI で書く と同じことだと思えばよい。時代が変わってもやってることは変わんないな。扱うレイヤが変わっただけだ。
その時、当時使っていた Turbo C のアセンブラ出力と LSI-C のアセンブラ出力を見比べて 確かになんて美しいんだ、と感動した記憶もある。どう違うかというと、LSI-C は極限までレジスタを割り当てるので、ほとんどスタックを汚さない。Turbo C は関数呼び出しの引数は基本スタック渡しで汚いなー、と。アセンブラでサブルーチンを作る際に LSI-C の出力コードは大いに参考になった。
話は尽きないので、昔話はここでおしまいにしよう。
つまりは、森氏の名前と kmyacc という作品を後世に遺すべく、今後 Bison から kmyacc に鞍替えする計画を立てるかもしれない、ということだ。
おわりに
あまり構文解析処理自体には触れていないが、ソースコードを見てみると何となく理解できるかもしれない。もちろん、バグがあれば教えて下さい。お願いします。
最後はいつもの以下の定型フォーマットで締め括り。
- 最初の動機は スクリプト言語 KINX(ご紹介) を参照してください(もし宜しければ「
いいねLGTM」ボタンをポチっと)。- リポジトリは ここ(https://github.com/Kray-G/kinx) です。こちらももし宜しければ★をポチっと。
- 投稿日:2020-03-20T07:13:52+09:00
【Rails】小数点と3桁ずつ区切るカンマ
1234.50
"#{(product.price).to_f}" => 1234.5 "#{(product.price).to_s(:delimited)}" => 1,234.5
- 投稿日:2020-03-20T04:39:37+09:00
衆議院の質問主意書データをWebページから集計する
国会に提出された質問主意書データをRubyを使って集計する。
集計に使った元データが必要な方は、@ts_3156までご連絡ください。データの各種加工もお引き受けいたします。
集計結果は以下の通り。
国会議員ごとのランキング
1位 初鹿 明博 20回 2位 櫻井 周 17回 3位 松原 仁 16回 4位 丸山 穂高 16回 5位 城井 崇 8回 6位 早稲田 夕季 8回 7位 下地 幹郎 6回 8位 中谷 一馬 5回 9位 阿部 知子 4回 10位 江田 憲司 3回 11位 山井 和則 3回 12位 森山 浩行 2回 13位 岡本 充功 2回 14位 大河原 雅子 2回 15位 柿沢 未途 1回 16位 山崎 誠 1回 17位 中島 克仁 1回 18位 山内 康一 1回 19位 稲富 修二 1回 20位 青山 大人 1回 21位 関 健一郎 1回 22位 赤嶺 政賢 1回 23位 黒岩 宇洋 1回 24位 亀井 亜紀子 1回 25位 大西 健介 1回 26位 階 猛 1回 27位 奥野 総一郎 1回会派ごとのランキング
1位 立憲民主・国民・社保・無所属フォーラム 82回 2位 無所属 42回 3位 日本共産党 1回以下、集計に使ったRubyコード
Gemfilegem 'anemone'require 'anemone' def scrape(url) Anemone.crawl(url, depth_limit: 0) do |anemone| anemone.on_every_page do |page| return page end end end url = 'http://www.shugiin.go.jp/internet/itdb_shitsumon.nsf/html/shitsumon/kaiji201_l.htm' progress_links = [] question_links = [] answer_links = [] scrape(url).links.each do |link| str = link.to_s if str.match?(/[^ab]201\d{3}\.htm/) progress_links << link elsif str.match?(/a201\d{3}\.htm/) question_links << link elsif str.match?(/b201\d{3}\.htm/) answer_links << link end end questions = [] progress_links.each do |link| page = scrape(link.to_s) html = Nokogiri::HTML(page.body) table = html.xpath('//*[@id="mainlayout"]/table') question = {} table.xpath('tr').each do |row| komoku = row.xpath("td[@headers='KOMOKU']").text naiyo = row.xpath("td[@headers='NAIYO']").text next if komoku == '' question[komoku] = naiyo end questions << question sleep 10 end提出者名で順位を集計する場合
ranking = Hash.new(0) questions.each do |question| key = question['提出者名'] # key = question['会派名'] ranking[key] += 1 end; nil ranking.sort_by { |k, v| -v }.each.with_index do |(key, count), i| puts "#{i + 1}位 #{key.chomp('君')} #{count}回" end集計に使った元データが必要な方は、@ts_3156までご連絡ください。データの各種加工もお引き受けいたします。
- 投稿日:2020-03-20T02:33:26+09:00
RailsエンジニアがDDDやクリーンアーキテクチャに触れるためにとりあえずHanamiを始めてみる
Introduction
これまで Rails をそれなりにやってきて、ちょっとしたWebアプリならそれなりサクッと作れるようにはなりましたが、 Fat Controller だの Fat Model と言われるようにどこかで臨界点が来て、従来のMVCアーキテクチャとは違う別の設計を模索してみたい欲が出てきました
そのとっかりとして、巷で話題の クリーンアーキテクチャ に触れるために、 Rails の対抗馬として名乗りを挙げた Ruby 製フレームワーク Hanami を始めてみようかと思いました
Install
まずは Hanami を立ち上げてみます。
$ mkdir hanami-tutorial $ cd hanami-tutorial $ bundle initGemfile を書き換えます。
Gemfile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "hanami"ライブラリをインストールして Rails と同様にサーバーを立ち上げます。
$ bundle $ bundle exec hanami new . $ bundle exec hanami server導入完了!と思いきや、2020年3月20日現在、エラーになりました
Bundler could not find compatible versions for gem "dry-types": In snapshot (Gemfile.lock): dry-types (= 0.12.3) In Gemfile: hanami (~> 1.3) was resolved to 1.3.3, which depends on hanami-validations (>= 1.3, < 3) was resolved to 1.3.6, which depends on dry-validation (~> 0.11, < 0.12) was resolved to 0.11.2, which depends on dry-types (~> 0.12.0) hanami-model (~> 1.3) was resolved to 1.3.2, which depends on dry-types (~> 0.11.0) Running `bundle update` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict.指示に従って、もう一度サーバーを立ち上げます。
$ bundle update $ bundle exec hanami serverhttp://localhost:2300/ を開くと...
Static Page
Rails チュートリアルと同様に、まずは静的なページを作ってみます。
ルーティングは Rails 感があります。
apps/web/config/routes.rbroot to: 'home#index'アクションは Rails と違い独立したクラスを作ります。
apps/web/controllers/home/index.rbmodule Web module Controllers module Home class Index include Web::Action def call(params) end end end end endビューも Rails と違います。 Rails における View は Hanami においては View と Template に分かれていて、 Rails の Helper などの UI に関わるロジックは View で、 HTML テンプレートは Template が担当します。
apps/web/views/home/index.rbmodule Web module Views module Home class Index include Web::View end end end endapps/web/templates/home/index.html.erb<h1>Bookshelf</h1>http://localhost:2300/ を開くとページが差し替わったはずです。
これで自由にページを作れるようになりましたTemplate Engine
Hanami のデフォルトのテンプレートエンジンは Rails と同様に Erb ですが、 Slim や Haml で書きたいですよね。
Slim をインストールして、先ほど作ったテンプレートを書き換えます。Gemfilegem 'slim'$ bundle $ mv apps/web/templates/home/index.html.erb apps/web/templates/home/index.html.slimapps/web/templates/home/index.html.slimh1 Bookshelfこれで Slim は導入できました
Pry
Ruby 2.7 以下だとデバッグのために Pry を導入したいですね。これも簡単。
Gemfilegem 'pry'$ bundle $ bundle exec hanami console[1] pry(main)>Ridgepole
意見は分かれますが、自分はプロトタイピング重視で、 Rails のマイグレーションではなく Ridgepole を使いたいです。
Gemfilegem 'ridgepole'$ bundleRails の
database.yml
に相当するものが無いので、便宜上新たに作ります。config/database.yml# ridgepole を使うために用意 development: adapter: sqlite3 database: db/hanami_tutorial_development.sqliteRidgepole が使う Schemafile を生成します。まだテーブルを定義していないので空ファイルが出力されます。
$ bundle exec ridgepole -c config/database.yml -e > Schemafileテーブルを作ってみます。
Schemafilecreate_table :users, force: :cascade do |t| t.string :email, null: false t.timestamps null: false t.index :email, unique: true end$ bundle exec ridgepole -c config/database.yml -a Apply `Schemafile` -- create_table("users", {}) -> 0.0052s -- add_index("users", ["email"], {:unique=>true}) -> 0.0035sテーブルが作られたのでモデルを作ります。 Rails におけるモデルは Hanami においては Repository と Entity に分かれます。クリーンアーキテクチャが見えてきましたね
lib/hanami_tutorial/repositories/user_repository.rbclass UserRepository < Hanami::Repository endlib/hanami_tutorial/entities/user.rbclass User < Hanami::Entity endコンソールで動作確認してみます。
[1] pry(main)> UserRepository.new.create(email: 'test@example.com') [2] pry(main)> UserRepository.new.find(1) => #<User:0x0000000000000000 ... [3] pry(main)> UserRepository.new.users.where(email: 'test@example.com') => #<ROM::Relation::Composite name=users dataset= ...Hanami は ActiveRecord ではなく Rom という ORM を使っていますが、 Rails エンジニアなら雰囲気で使えそうな気がしますよね?
Job Queue
Rails の ActiveJob に相当する非同期処理モジュールが Hanami にはありませんが、自分の経験上 Job Queue ミドルウェアを移行することはそんなに無いので、ここでは Sidekiq を入れてみましょう。
Gemfilegem 'sidekiq'config/sidekiq.rbSidekiq.configure_server do |config| config.redis = { url: ENV['REDIS_URL'] } end Sidekiq.configure_client do |config| config.redis = { url: ENV['REDIS_URL'] } endワーカーを作ります。引数で与えられた秒数だけ待機して foo! と叫ぶだけのやつです。
lib/hanami_tutorial/workers/sleepy_echo_worker.rbclass SleepyEchoWorker include Sidekiq::Worker def perform(time) sleep time puts 'foo!' end endSidekiq を立ち上げます。
$ REDIS_URL=redis://localhost:6379 bundle exec sidekiq -r ./config/boot.rbコンソールでワーカーを呼び出します。
[1] pry(main)> SleepyEchoWorker.perform_async(3)Sidekiq を立ち上げたターミナルで、3秒間待機した後に foo! とログに出ることが確認できましたね
Conclusion
Rails エンジニアが Hanami でWebアプリを開発するための初期導入についてまとめてみました。今後 Hanami で開発する際にハマったことがあればここに追記していこうかと思います。
ありがとうございました