- 投稿日:2020-04-26T23:31:15+09:00
【Rails】deviseを用いたユーザー新規登録機能の実装(基礎〜少し応用)
はじめに
Ruby on Rails を用いてWEBアプリを作成中です。
ユーザー新規登録の機能を実装するために、「devise」というgemを用いることにしました。
備忘もかねて、本文に実装した内容を残しておきます。
errorで困ったポイントも残しておきますので、参考にしていただけると幸いです^^専門用語や参考にさせていただいた記事は最後に記載させていただいております。
「これ、なんで記述してるんだろう?」と、私自身が初めて作成した時に感じたポイントでもありますので、
初心者の方は気になるところかとも思います。
そちらも参照していただければと思います。今回の方法はあくまで一つの実装方法でしかなく、やり方は色々あるのと、
私もまだ未熟なため、わかりにくい記述や余分な記述もございますし、調べきれてない、試しきれてないところもございます。
共にブラッシュアップしていければとも思ってますので、ご指摘もいただければと思います。記載しきれなかった部分は、随時更新か、別途記事を用意いたします。
実装の目標
今回は以下の画像のような表示を目標として実装しました。
全てを解説するのは大変だったので、「ニックネーム」「メールアドレス」「パスワード」「生年月日」のみに絞っておりますのでご了承ください。
カラムのカスタマイズ、エラー表示、パスワードの表示/非表示、生年月日の選択など、「devise」の基本だけでなく、少し工夫が必要な内容も網羅してるかと思いますので、参考になれば幸いです。
1. deviseのインストール手順
1-1. Gemfileに追記
(前略) gem 'devise' (後略)※注意
「development、test、production」のgroup内に記述すると特定の環境でのみ使用する設定となりますので、group外に記述するようにしてください。1-2. コマンドの実行(インストール)
$ bundle install $ rails g devise:install2. Userモデルを作成
インストール後、モデルとテーブルを作成するために、以下をターミナルで実行してください。
通常のモデル作成とはコマンドが違うので注意してください。$ rails g devise userマイグレーションファイルとモデルファイルが出来るので、以下のように記述ください。
2020*****_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :nickname, null: false t.string :email, null: false, default: "" t.string :password, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.date :birthday, null: false # 〜省略〜 end add_index :users, :email, unique: true # 〜省略〜 end endapp/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i # 〜省略〜 validates :nickname, presence: true, length: { maximum: 20 } validates :email, presence: true, uniqueness: true, format: { with: VALID_EMAIL_REGEX } validates :password, presence: true, length: { minimum: 7 }, format: { with: VALID_PASSWORD_REGEX } validates :birthday, presence: true # 〜省略〜 endモデル「user.rb」について
「VALID_EMAIL_REGEX」「VALID_PASSWORD_REGEX」は正規表現によって、特定の文字を弾くようにしております。
「presence: true」は記述することで、空で登録することを弾くようにしてます。
「length: { maximum: 20 }」と「length: { minimum: 7 }」は文字数制限です。ここで、以下の「devise.rb」に記述されてる「config.password_length = 6..128」についても、次のように編集しておきます。
この数字は文字制限を表してます(つまり、minimumが「6」です)。
理由はモデル「user.rb」より、今回passwordは7文字以上としているため、minimumが「7」である必要があります。
また、こちらを編集後はサーバーの再起動をしないと、反映されませんのでご注意を。「devise.rb」の「config.password_length = 6..128」を編集した理由は、そのままにするとモデル「user.rb」側のバリデーション「length: { minimum: 7 }」と「devise.rb」側のバリデーション「config.password_length = 6..128」が共存することになるため、2つのバリデーションに引っかかって、2つのエラー表示されてしまうからです。
どちらか片方を削除する方法もありかと思いますが、経験もかねて、どちらも残す方法しか試せておりません。config/initializers/devise.rb# frozen_string_literal: true # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| Rails.application.credentials[:secret_key_base] # 〜省略〜 config.password_length = 7..128 # 〜省略〜 end最後にmigrationファイルをデータベースに反映するために、以下のコマンドを実行。
$ rails db:migrate3. コントローラーの編集
Viewなどを先に提示してもよかったのですが、エラー表示などについての説明を一緒にした方が良いと判断し、ルーティングやコントローラーの設定を先に説明いたします。
まずはコントローラーから。
今回はユーザー新規登録(サインアップ/sign_up)の実装についてですので、コントローラーは「application_controller.rb」のみで大丈夫です。
以下のように記載します。「configure_permitted_parameters」メソッドの定義をしてますが、deviseをインストールすることでdevise_parameter_sanitizerのpermitメソッドが使えるようになります。これがストロングパラメータに該当する機能です。サインアップ時に入力された「nickname、email、password、birthday」のキーの内容の保存を許可しています。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters added_attrs = [ :nickname, :email, :password, :birthday ] devise_parameter_sanitizer.permit :sign_up, keys: added_attrs end end4. ルーティングの編集
以下のように記載してください。
注意点としては、「routes.rb」の順番です。
「users/:id」が「users/sign_in」を包括してエラーが発生しないように、「devise_for :users」を「resources :users」より先に書く必要があります。また、deviseでサインアップする際に、例えばパスワードを忘れて保存しようとしてエラーが発生すると、親ページにリダイレクトされます。
つまり、サインアップページ「/users/sign_up」でエラーが発生した場合、「/users」にリダイレクトされてしまいます。
そのまま登録するとルーティングエラーが表示されます。これを回避するために、「devise_scope :users」以下の記述を追記して、任意のルーティングをさせています。
方法はいくつかありますが、今回は手っ取り早そうです。config/routes.rbRails.application.routes.draw do devise_for :users devise_scope :users do get '/users', to: redirect("/users/sign_up") end # 〜省略〜 end5. Veiwの編集
まずは、以下のコマンドを実行してください。Modelに対応するViewが生成されます。
Modelには「users」などを入れる文献が多ので、以下は「$ rails g devise:views users」で実行してます。
私が学んだ某スクールで最初に学んだ時は「devise」でしたので、ユーザーマイページと分けるために、私の場合は「devise」で生成してますが。$ rails g devise:views Model※生成されるViewファイル
app/views/users/confirmations/new.html.erb
app/views/users/mailer/confirmation_instructions.html.erb
app/views/users/mailer/password_change.html.erb
app/views/users/mailer/reset_password_instructions.html.erb
app/views/users/mailer/unlock_instructions.html.erb
app/views/users/passwords/edit.html.erb
app/views/users/passwords/new.html.erb
app/views/users/registrations/edit.html.erb
app/views/users/registrations/new.html.erb
app/views/users/sessions/new.html.erb
app/views/users/shared/_links.html.erb
app/views/users/unlocks/new.html.erb
5-1. HTML/HAMLの記述
「registrations/new.html.erb」をユーザー新規登録ページとして編集していきます。
また、以下の通り、HTMLからHAMLに変換して記述してます。app/views/users/registrations/new.haml.erb.signup__main .signup__main__content %h2.signup__main__content__head 会員情報入力 = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| # 〜省略〜 .field .field-label = f.label 'ニックネーム' %span.form-require 必須 .field-input = f.text_field :nickname, class: "field-input-full", autofocus: true, autocomplete: "nickname", placeholder: "例)メルカリ太郎" .input-error = resource.errors.full_messages_for(:nickname)[0] .field .field-label = f.label 'メールアドレス' %span.form-require 必須 .field-input = f.email_field :email, class: "field-input-full", autofocus: true, autocomplete: "email", placeholder: "PC・携帯どちらでも可" .input-error = resource.errors.full_messages_for(:email)[0] .field .field-label = f.label :password, 'パスワード' %span.form-require 必須 .field-input.toggle = f.password_field :password, class: "field-input-full", autocomplete: "off", autocomplete: "password", placeholder: "7文字以上の半角英数字", id:'password' .checkbox-field %input#js-passcheck.checkbox.js-password-toggle{type: "checkbox"} %label.btn-label.js-password-label{for: "js-passcheck"} %i.fas.fa-eye-slash{style: "font-size:20px;color:#808080"} .input-error = resource.errors.full_messages_for(:password)[0] .field-info ※ 英字と数字の両方を含めて設定してください .field .field-label = f.label '生年月日' %span.form-require 必須 .birthday-select = raw sprintf(f.date_select( :birthday, use_two_digit_numbers: true, prompt: "--", start_year: Time.now.year, end_year: 1900, date_separator: '%s'), '年 ', '月 ') + "日" .input-error = resource.errors.full_messages_for(:birthday)[0] # 〜省略〜 .actions = f.submit "登録", class: 'btn'
5-2. エラー表示
今回のエラー表示は、ActiveRecordのvalidatesでエラーになった時に表示されるメッセージを利用します。
上記のように、バリデーションエラーは「errors.full_messages_for(:attribute_name)」で各attributeのエラーメッセージは取得してます。なるほど!
ん?「各attribute」って何?まずは何も考えずに、ネット上から「devise.ja.yml」をダウンロードし、「/config/locales」に保存してください。
次に、「devise.ja.yml」に以下を追記。
ここに追記した、「birthday、nickname、email、password」が「attribute」です。ついでに、日本語化も実施。
「ja.yml」をネットからダウンロードし、先ほどと同じく「/config/locale/」以下に入れる。
「"%{attribute}%{message}"」とあるように、バリデーションエラーの内容に合わせて、「attribute」と「message」を選択してくれる。config/locales/devise.ja.ymlja: activerecord: attributes: user: birthday: "生年月日" nickname: "ニックネーム" email: Eメール password: パスワード # 〜省略〜config/locales/ja.yml# 〜省略〜 errors: format: "%{attribute}%{message}" messages: accepted: を受諾してください blank: を入力してください # 〜省略〜
5-3. パスワードの表示/非表示
「/registrations/new.haml.erb」のパスワード入力は、何もしなければ非表示です。
何かしらのアクションを起こしたら、表示出来るようにしないと、利用者にとってわかりにくかったりします。
今回は、最近よく見る「目のマーク」を押したら表示/非表示を切り替えられるようにjavascriptとSCSSを駆使して表現しました。
参考までに一部コードを提示します。
ポイントとしては、「(password).attr('type','text');」「(password).attr('type','password');」を切り替えることで、「f.password_field」が持ってる「type」を切り替えることができ、表示/非表示を切り替えることができます。app/views/users/registrations/new.haml.erb# 〜省略〜 .field-input.toggle = f.password_field :password, class: "field-input-full", autocomplete: "off", autocomplete: "password", placeholder: "7文字以上の半角英数字", id:'password' .checkbox-field %input#js-passcheck.checkbox.js-password-toggle{type: "checkbox"} %label.btn-label.js-password-label{for: "js-passcheck"} %i.fas.fa-eye-slash{style: "font-size:20px;color:#808080"} # 〜省略〜stylesheets/modules/users.scss.toggle{ position: relative; .checkbox-field{ position: absolute; right: 15px; top: 45px; .checkbox { display: none; } } }app/assets/javascripts/registrations_new.js$(function(){ var password = '#password'; var passcheck = '#js-passcheck'; $(passcheck).change(function(){ const passwordLabel = document.querySelector('.js-password-label'); if ($(this).prop('checked')){ $(password).attr('type','text'); passwordLabel.innerHTML = '<i class="fas fa-eye" style="font-size:20px;color:#808080"></i>'; } else { $(password).attr('type','password'); passwordLabel.innerHTML = '<i class="fas fa-eye-slash" style="font-size:20px;color:#808080"></i>'; } }) })5-4. 生年月日の選択
以下の「new.haml.erb」の通り、「date_selectタグ」という方法を使って実装しました。
超簡単です。app/views/users/registrations/new.haml.erb# 〜省略〜 .birthday-select = raw sprintf(f.date_select( :birthday, use_two_digit_numbers: true, prompt: "--", start_year: Time.now.year, end_year: 1900, date_separator: '%s'), '年 ', '月 ') + "日" # 〜省略〜ですが1点、注意点があります。
バリデーションエラーが発生すると、「field_with_errors」クラスのdivタグが挿入され、「+ "日"」が切り離されてしまい、以下の画像のようにズレてしまいます。
【バリデーションエラー発生時】app/views/users/registrations/new.haml.erb# 〜省略〜 .birthday-select = raw sprintf(f.date_select( :birthday, use_two_digit_numbers: true, prompt: "--", start_year: Time.now.year, end_year: 1900, date_separator: '%s'), '年 ', '月 ') .field_with_errors + "日" # 〜省略〜これを回避する方法はいくつかあるようですが、今回は以下のように、「config/application.rb」に「config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }」を追記しました。
追記後、サーバーを再起動すると、追記が反映され、Railsによる自動挿入が回避できます。config/application.rb# 〜省略〜 module FleamarketAppTeamA class Application < Rails::Application # 〜省略〜 config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag } end end最後に
最後まで読んでいただきありがとうございます。
以上で、ユーザー新規登録についての実装は終わりです。本記事はカスタムの部分で、大枠の作業フローと、小技的なところで参考にはなるかと思いますので、活用いただければ幸いです。
もっとわかりやすい記事、個々の機能で詳しく記載された記事はたくさんございますので、そこに至るまでのキッカケにもなればとも思っております。今回私も、以下の記事を主に参考にさせていただきました。
作者の方々には感謝申し上げます。量が多いため割愛させていただいておりますが、他にも参考にした記事はたくさんありますので、それら記事にも感謝です。
本記事を参考にされる方は、それらの記事も参考にしていただければと思います。参考記事
・deviseについて
-> rails devise完全入門!結局deviseって何ができるの?
-> 【Rails】deviseの使い方を徹底解説!
-> Deviseでログイン機能をつくる [Ruby on Rails]
-> Deviseの設定手順をまとめてみた。 その1 導入編・encrypted_password
->Gem Deviseによるパスワードの保存及び保安方法・add_index
->データベースにindexを張る方法・正規表現とは
-> https://www.megasoft.co.jp/mifes/seiki/about.html・正規表現(ライブラリ)
-> https://github.com/kkos/oniguruma/blob/master/doc/RE.ja
-> http://k-takata.o.oo7.jp/mysoft/bregonig.html・正規表現(確認ツール)
-> https://rubular.com/・protect_from_forgery with: :exception(CSRF対策)
-> RailsのCSRF保護を詳しく調べてみた(翻訳)・日本語化
-> https://qiita.com/kusu_tweet/items/b534c808ac1ee0382f05)・エラー表示
-> ActiveRecordのvalidatesで表示されるエラーメッセージのフォーマットを変更する
-> 【Rails】バリデーションのエラーメッセージを取得・表示・日本語化する方法を完全解説!・生年月日の選択
-> 【Rails】date_selectタグの使い方メモ
-> Railsのバリデーションエラーで、「field_with_errors」によるレイアウト崩れを防ぐ辞書
・gem
便利な機能をひとまとめにしたもの(ライブラリ)・devise
ユーザー新規登録/ログインといった認証機能を簡単に実装できるgemのこと・encrypted_password
暗号化されたパスワードを保存するカラム・add_index
特定のカラムからデータを取得する際に、テーブルの中の特定のカラムのデータを複製し検索が行いやすいようにする・正規表現
「検索」や「置換」で指定する文字列をパターン表現する方法で、プログラミング言語やテキストエディタなどで利用できる・protect_from_forgery with: :exception
セキュリティ対策。このコードがあると、Railsで生成されるすべてのフォームとAjaxリクエストにセキュリティトークンが自動的に含まれ、セキュリティトークンがマッチしない場合ははじかれる。ユーザー認証が完了したwebアプリのページに悪意のあるコードやリンクを仕込むCSRF(Cross-Site Request Forgery)という攻撃手法から保護出来る。・before_action
全てのアクションが実行される前に、この部分が実行される
- 投稿日:2020-04-26T22:25:02+09:00
rails開発でハマったto_modelのエラー
railsでフリマアプリをチーム開発してる時、あまり見かけないエラーに遭遇したので、具体的な原因はよくわかっていませんが、残しておきます。
rubyバージョン :2.5.1
railsバージョン :5.2.4.2
データベース :mysqlエラーが発生したコード
_product.html.haml=image_tag product.images.first.imagesproductモデルとimageモデルが一対多の関係で結びついており、productモデルにはaccepts_nested_attributes_for :imagesが書かれています。
エラー画面
to_modelという記述はどこにもしていませんし、to_xmlというxml形式で出力させる形式のメソッドをどう使えばいいのかわかりません。
解決したコード
_product.html.haml= image_tag product.images.first.images.urlこのエラーの"to_model”の意味は調べてみたもののよくわかっていませんが、データの呼び出しに失敗しているエラー(このオブジェクトにはこんなメソッドは存在しないよという意味のエラー)だと思うので呼び出し方を変えたらうまくいきました。
あまり中身のない記事ですが、参考になれば幸いです。
- 投稿日:2020-04-26T21:16:43+09:00
RubyでBOM付UTF-8のCSV(Excelで直接読めるCSV)を出力する方法
- 投稿日:2020-04-26T20:56:29+09:00
競技プログラミングでよく出てくる書き方
input = gets.split.map(&:to_i)
gets・・キーボードで入力した値を文字列で取得
split・・文字列を分割して配列にする、引数を指定しないばあい、空白文字で区切られる
map・・配列の要素の数だけ繰り返し処理を行う、collectと同じ
- 投稿日:2020-04-26T20:30:15+09:00
Railsのダウングレードでハマった話
Railsのダウングレードでハマった話
Railsのダウングレードでハマってしまった内容を記録します。
初歩的なミスですが、同じような初心者の方に参考になればと思います。目次
動作環境
OS : macOS Mojave 10.14.6
ruby : 2.6.3p62
rails : 5.2.4.2 -> 5.2.3
問題
ローカル開発環境をRails 5.2.4.2 -> 5.2.3にダウングレードする必要がありました。
Railsをアンインストール -> 指定バージョンをインストールしても、
なかなかバージョンのダウングレードができない状況でした。既存バージョンのRailsのアンインストール
1. gem uninstall rails 5.2.4.2
2. gem uninstall railties 5.2.4.2
指定バージョンのRailsのインストール
gem 'rails', '~> 5.2.3' # Gemfileに記載bundle install
rails -v #バージョン確認 Rails 5.2.4.2 #変わっていない。原因と解決法
Gemfile内のこの~>部分がある場合は指定されたバージョン以上で最新のものが利用されるとのこと。
つまり 5.2.3を利用するなら~>を使わずに記載します。*バージョン指定についてはこちらの記事が参考になりました。
https://qiita.com/awakia/items/5745938c192ca1139c63誤gem 'rails', '~> 5.2.3' # 5.2.3以上5.3.0未満のなかで最新のもの。5.2.4.2がインストールされてしまう。正gem 'rails', '5.2.3' # 5.2.3を使用!bundle install #改めてgemをインストール rails -v Rails 5.2.3 #指定のバージョンに変わりました。学んだこと
今回の件で以下のことを学びました。
1.gemfile
の~>
は記載されたバージョン以上で最新のものがインストールされる
- 投稿日:2020-04-26T20:03:43+09:00
Capistranoを噛み砕く
近況報告
実はコーヒーマイスターを前職で取得した経緯がありまして,若干のコーヒーの知識があるので,少しひけらかしたいと思います。まず,コーヒーってどんな飲み物のイメージがあります?多分,苦いイメージですよね。では,現在世界的に高品質なコーヒーはどのように評価されているでしょうか。実は苦さの評価はありません。酸味の評価が主流です。
理由はいたって簡単。苦味は焙煎によって生まれるものであり,酸味はコーヒー豆がそもそも持っているものだからです。細かい説明はしませんが,生のコーヒー豆は食べられたものではありません,それを美味しくするために火を入れます。その時に豆の成分が焦げて苦味になります。酸味は熱によって分解されていくので,結果として深煎りのコーヒーは酸味のないものになります。一方,苦味は焙煎度合いや焙煎師の腕,設備により変化します。ということは,豆が本来持っている酸味が評価の基準になるのはまあ納得ですね。
ただ,この評価はスペシャリティコーヒー(世界のコーヒー生産のうち10%程度に該当する)の概念が生まれた10数年前のものであり,以前は苦味,そもそもそんな評価なかったかも。。。今後も同じ評価をしていくとは限りません。やはり常に情報は更新されていきます。だから,常にアンテナを張っていないと時代遅れになっちゃいますね。全てが動いているのに自分が動かなかったら動いている相手から見たら不安定です。だから動くこと,不安定であることこそが安定ってね。
今回の目標
Capistranoで実施していることの言語化
大まかな流れ
・Capistranoについて
・Capistrano導入
・各ファイルの設定事前準備
デプロイ環境整備
rails5.2以降ならマスターキーを本番環境に環境変数にして入れといてね
ruby 2.5.1Capistranoについて
一言で言えば,自動デプロイツールです。
デプロイには
SSH内の情報(アプリケーション)の更新
SSH接続
アセットコンパイル更新
Unicorn再起動
といくつかコードを打ち込んでいく必要があります。ただCapistranoを導入さえできれば,
** bundle exec cap production deploy**
これだけで上の作業が終了します。
個人的にはCircleCiを勉強して導入したかったのですが,間に合わずカリキュラムのこちらをCapistrano導入
railsにおいてCapistranoにはGemが存在します。そこからチョチョイと生成しましょう。
gemfile.group :development, :test do gem 'capistrano' gem 'capistrano-rbenv' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano3-unicorn' endterminal.$ bundle install $bundle exec cap install ⇨gemfileにあるものを参照してcap(istrano)の関連ファイルをインストールこれで1つのフォルダと2つのファイルが生成されます
◆capfile----capistranoで実行することを決めるファイル
◆deploy-----デプロイする環境ごとに設定されるファイル
・staging.rb-----ステージング環境(つまり開発環境,テスト環境)に適用される
・pruduction.rb--本番環境に適用される
◆deploy.rb--デプロイする内容を決めるフォルダ
capfileで実行することをきめて,残りがGithubへの接続に必要なsshキーの指定、デプロイ先のサーバのドメイン、AWSサーバへのログインユーザー名、サーバにログインしてからデプロイのために何をするか、といった設定が入るわけです。各ファイルの設定
capfile
capfile.require "capistrano/setup" ←準備しますー(これ抜けてたら動かない) require "capistrano/deploy" ←デプロイ実行するねー require 'capistrano/rbenv' ←rbenvの状態みるね require 'capistrano/bundler' ←必要なGem確認するね require 'capistrano/rails/assets' ←アセットファイルをコンパイルするね require 'capistrano/rails/migrations' ←DB:migrateするね require 'capistrano3/unicorn' ←unicorn再起動するね Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r } ⇨ディレクトリ内の.rakeを昇順で抽出に編集
pruduction.rbpruduction.rbserver '12.345.678.90'←用意したElastic I, user: 'ec2-user', roles: %w{app db web} |「どのサーバーつなぐ?」,「ユーザー名は?」「マイグレートするのは(データベース選択)」
staging.rbは今回必要ないので無視deploy.rb
deploy.rb# capistranoのバージョンを記載。固定のバージョンを利用し続け、バージョン変更によるトラブルを防止する lock '<Capistranoのバージョン>'←ローカルで確認 # Capistranoのログの表示に利用する set :application, '自身のアプリケーション名' # どのリポジトリからアプリをpullするかを指定する set :repo_url, 'git@github.com:<Githubのユーザー名>/<レポジトリ名>.git' # バージョンが変わっても共通で参照するディレクトリを指定 set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads') set :rbenv_type, :user set :rbenv_ruby, '<このアプリで使用しているrubyのバージョン>' #ローカルで確認 # どの公開鍵を利用してデプロイするか set :ssh_options, auth_methods: ['publickey'], keys: ['****.pem 自分のに書き換える'] # プロセス番号を記載したユニコーンファイルの場所はここだよ set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" } # Unicornの設定ファイルの場所(ローカルの位置と同じ) set :unicorn_config_path, -> { "#{current_path}/config/unicorn.rb" } set :keep_releases, 5 # デプロイ処理が終わった後、Unicornを再起動するための記述 after 'deploy:publishing', 'deploy:restart' namespace :deploy do task :restart do invoke 'unicorn:restart' end endに編集
◆set :xx, xx ⇨DSL(Domain-Specific Language)の一種
ある特定の処理における効率をあげるために特化した形の文法を擬似的に用意したプログラムです。
上記のset :名前, 値について、これは言わば変数のようなものです。
例えばset: Name, 'value' と定義した場合、fetch Name とすることで 'Value'が取り出せます。
また、一度setした値はdeploy.rbやproduction.rbなどの全域で取り出すことができます。
また、ファイル内には、desc '◯◯'やtask:XX doといった記述がよく見受けられます。これは、先ほどCapfileでrequireしたものに加えて追加のタスクを記述している形です。ここで記述したものもcap deploy時に実行されることとなります。Capistranoによる自動デプロイ後のディレクトリ構成について
一度Capistranoによる自動デプロイを実行すると、本番環境のアプリケーションのディレクトリが変化します。
Capistranoによるアプリのバックアップなど、複数のディレクトリが作成されます。その中でも特に重要なのが、releases、current、sharedディレクトリです。releasesディレクトリ
capistranoを通じてデプロイされたアプリは、releasesというフォルダにひとまとめにされます。
ここに過去分のアプリが残っていることにより、デプロイ時に何か問題が発生しても一つ前のバージョンに戻ったりすることができます。
そして、その過去分の保存数を指定しているのがdeploy.rbのset :keep_releasesの記述となります。今回は5つ、過去のバージョンを保存するよう設定しました。currentディレクトリ
releasesフォルダの中で一番新しいものが、自動的にcurrentというフォルダ内にコピーされているような状態になります。そのため、このcurrent内に入っているアプリの内容が、現在デプロイされている内容ということになります。
db:seedもここに入れないと反映されない。
sharedディレクトリ
バージョンが変わっても共通で参照されるディレクトリが格納されるディレクトリです。具体的には、log、public、tmp、vendorディレクトリが格納されます。config/unicorn.rbapp_path = File.expand_path('../../', __FILE__) worker_processes 1 working_directory app_path pid "#{app_path}/tmp/pids/unicorn.pid" listen "#{app_path}/tmp/sockets/unicorn.sock" stderr_path "#{app_path}/log/unicorn.stderr.log" stdout_path "#{app_path}/log/unicorn.stdout.log" ↓↓↓↓↓↓↓ 以下のように変更 ↓↓↓↓↓↓ # ../が一つ増えている app_path = File.expand_path('../../../', __FILE__) worker_processes 1 # currentを指定 working_directory "#{app_path}/current" # それぞれ、sharedの中を参照するよう変更 listen "#{app_path}/shared/tmp/sockets/unicorn.sock" pid "#{app_path}/shared/tmp/pids/unicorn.pid" stderr_path "#{app_path}/shared/log/unicorn.stderr.log" stdout_path "#{app_path}/shared/log/unicorn.stdout.log"nginxの設定ファイル
同様に、Nginxの設定ファイルも変更が必要です。これまでは/var/www/以下のアプリケーションに対して連携を設定していたので、/var/www/chat-space以下のcurrent、sharedなどのディレクトリと連携するように設定を変更する必要があります。全て消して編集
$ sudo vim /etc/nginx/conf.d/rails.confupstream app_server { # sharedの中を参照するよう変更 server unix:/var/www/<アプリケーション名>/shared/tmp/sockets/unicorn.sock; } server { listen 80; server_name <Elastic IPを記入>; # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく client_max_body_size 2g; # currentの中を参照するよう変更 root /var/www/<アプリケーション名>/current/public; location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; # currentの中を参照するよう変更 root /var/www/<アプリケーション名>/current/public; } try_files $uri/index.html $uri @unicorn; location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } error_page 500 502 503 504 /500.html; }各サーバー再起動
$ sudo service nginx reload
$ sudo service nginx restart
$ sudo service mysqld restart
$ ps aux | grep unicorn
$ kill [master number]
$ bundle exec cap production deploy
- 投稿日:2020-04-26T18:09:16+09:00
bundlerバージョン違いのエラーを解消する
Factory Botをインストールしようとしたらエラー。
version
- ruby 2.4.9
- Rails 5.1.1
- factory_bot_rails ~> 4.10.0
bundle install The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`. Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Bundler could not find compatible versions for gem "bundler": In Gemfile: rails (~> 5.1.1) was resolved to 5.1.1, which depends on bundler (< 2.0, >= 1.3.0) Current Bundler version: bundler (2.1.4) This Gemfile requires a different version of Bundler. Perhaps you need to update Bundler by running `gem install bundler`? Could not find gem 'bundler (< 2.0, >= 1.3.0)', which is required by gem 'rails (~> 5.1.1)', in any of the sources. bundler -v Bundler version 2.1.4bundler (< 2.0, >= 1.3.0)が必要なのに2.1.4とバージョンが違うからエラーになるらしい。
# bundlerをインストールできるバージョンを調べる gem search ^bundler$ --all *** REMOTE GEMS *** bundler (2.1.4, 2.1.3, 2.1.2, 2.1.1, 2.1.0, 2.0.2, 2.0.1, 2.0.0, 1.17.3, 1.17.2, 1.17.1, 1.17.0, 1.16.6, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16.0, 1.15.4, 1.15.3, 1.15.2, 1.15.1, 1.15.0, 1.14.6, 1.14.5, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14.0, 1.13.7, 1.13.6, 1.13.5, 1.13.4, 1.13.3, 1.13.2, 1.13.1, 1.13.0, 1.12.6, 1.12.5, 1.12.4, 1.12.3, 1.12.2, 1.12.1, 1.12.0, 1.11.2, 1.11.1, 1.11.0, 1.10.6, 1.10.5, 1.10.4, 1.10.3, 1.10.2, 1.10.1, 1.10.0, 1.9.10, 1.9.9, 1.9.8, 1.9.7, 1.9.6, 1.9.5, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9.0, 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8.0, 1.7.15, 1.7.14, 1.7.13, 1.7.12, 1.7.11, 1.7.10, 1.7.9, 1.7.8, 1.7.7, 1.7.6, 1.7.5, 1.7.4, 1.7.3, 1.7.2, 1.7.1, 1.7.0, 1.6.9, 1.6.8, 1.6.7, 1.6.6, 1.6.5, 1.6.4, 1.6.3, 1.6.2, 1.6.1, 1.6.0, 1.5.3, 1.5.2, 1.5.1, 1.5.0, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, 1.3.1, 1.3.0, 1.2.5, 1.2.4, 1.2.3, 1.2.2, 1.2.1, 1.2.0, 1.1.5, 1.1.4, 1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.22, 1.0.21, 1.0.20, 1.0.18, 1.0.17, 1.0.15, 1.0.14, 1.0.13, 1.0.12, 1.0.11, 1.0.10, 1.0.9, 1.0.7, 1.0.5, 1.0.3, 1.0.2, 1.0.0, 0.9.26, 0.9.25, 0.9.24, 0.9.23, 0.9.22, 0.9.21, 0.9.20, 0.9.19, 0.9.18, 0.9.17, 0.9.16, 0.9.15, 0.9.14, 0.9.13, 0.9.12, 0.9.11, 0.9.10, 0.9.9, 0.9.8, 0.9.7, 0.9.6, 0.9.5, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.8.1, 0.8.0, 0.7.2, 0.7.1, 0.7.0, 0.6.0, 0.5.0, 0.4.1, 0.4.0, 0.3.1, 0.3.0) # バージョン指定でインストール gem install bundler -v 1.9.9bundler -v Bundler version 2.1.4
バージョンが変わらない?
こうやるとバージョンを指定して、インストールできるらしい。
エラーなくFactory Botをinstallできた。bundle _1.9.9_ install
- 投稿日:2020-04-26T17:53:27+09:00
Rails で render の後に書かれた処理は実行されるけどレスポンスを返すのは全処理が終わった後
背景
- こちらの記事を読んで Rails で response を返した後の処理が実行されるのかが気になった
- アクションの中のrender(), redirect_to()の後の処理は実行される
- 書かれたのが10年以上前だったので最近だとどうなのかを調べたい
- 先に response を返せると何が嬉しいか?
- タイムアウトまでの時間制限が厳しいシステムや機能と連携する際に非同期処理にしなくてもよくなる
- 例えば Slack とか
- https://api.slack.com/interactivity/slash-commands#responding_to_commands
This confirmation must be received by Slack within 3000 milliseconds of the original request being sent, otherwise a Timeout was reached will be displayed to the user.
環境
➜ ruby -v ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19] ➜ rails -v Rails 6.0.2.2調べた結果
- 普通にタイムアウトした
![]()
render
head
などのレスポンス系のメソッドの後に書かれた処理も実行される- ただ、アクションの中で書かれたすべての処理が実行された後に response を返すっぽい
- 処理の順番が逆になるわけではないので最後に render するのが自然
class HelloController < ApplicationController def hello render status: 200 sleep 3.0 slack_client = Slack::Web::Client.new( token: ENV['SLACK_TOKEN'] ) res = slack_client.chat_postMessage( channel: params[:channel_id], text: 'hello world' ) end end
after_action
系を使っても同じ挙動class HelloController < ApplicationController after_action :slack_post def hello render status: 200 end def slack_post sleep 3.0 slack_client = Slack::Web::Client.new( token: ENV['SLACK_TOKEN'] ) res = slack_client.chat_postMessage( channel: params[:channel_id], text: 'hello world' ) end end
- ただ
before_action
で render すると処理がそこで終わるclass HelloController < ApplicationController before_action :before_render def before_render render status: 200 end def hello # ここは実行されない sleep 3.0 slack_client = Slack::Web::Client.new( token: ENV['SLACK_TOKEN'] ) res = slack_client.chat_postMessage( channel: params[:channel_id], text: 'hello world' ) end end
- 投稿日:2020-04-26T16:42:01+09:00
複数の Enumerable なオブジェクトで tally したい【結論】deep_each
前置き
これまで、複数の Enumerable なオブジェクトで tally するためにあれこれ考え、
複数の Enumerable なオブジェクトで tally したい【追記あり】
を書き、@obelisk68 さんと色々やり取りをして、こんな示唆もいただきました。
Enumeratorを返すArray#flatten(Ruby)
現時点でのまとめ
それで、あれこれ考えてみたところ、結局、
deep_each
があればいいんじゃないか。世の中にはいろんな実装例がありますが、簡単なのは、
module Enumerable def deep_each(&block) return to_enum(__method__) unless block_given? each do |e| case e when Enumerable e.deep_each(&block) else block.call(e) end end end endこれがあれば、Array 以外のオブジェクトにも対応可能です。
enums = Enumerator.new(20) do |y| 20.times do y << Enumerator.new(20) do |yy| 20.times do yy << Enumerator.new(20) do |yyy| 20.times do yyy << rand(1..5) end end end end end end enums.deep_each.tally => {4=>1579, 5=>1664, 2=>1564, 3=>1586, 1=>1607} 毎回答えは変わります。
- 投稿日:2020-04-26T16:30:10+09:00
【Rails】has_secure_passwordでパスワードのセキュリティを強化
目的
パスワードのセキュリティを強化する。
手段
has_secure_passwordを使ってパスワードをハッシュ化する。
・ハッシュ化は、訳のわからない暗号みたいな文字列に変換すること。
・has_secure_passwordでハッシュ化されたパスワードは、同じ文字列で生成すれば常に同じ値になるので一致しているかどうかをチェックする際に使える。
・has_secure_passwordでハッシュ化したパスワードは、元のパスワードそのものに戻すことができないので、ハッシュ化されたパスワードを奪われたとしても何の問題もないのでパスワードのセキュリティが強固になる。
手順
1.Userモデル作成時のパスワード属性をpassword_digestとする。
➡︎has_secure_passwordを使う際の命名規則なので必須。
2.Gemfileにbcryptというgemを追加して、インストールする。
➡︎bcryptというgemをインストールすることで、has_secure_passwordを使えるようになりパスワードをハッシュ化できるようになる。
➡︎$ bundle installコマンドを忘れずに。3.Userモデルにhas_secure_passwordを記述。
➡︎Userモデル内にhas_secure_passwordを記述したことにより、password属性とpassword_confirmation属性の2つの属性が追加される。データベースのカラムとは対応していない属性。
➡︎どういうことかというと、この2つはユーザーに入力を求めるためだけの属性で、
この2つの属性をユーザーに入力させる
ことで、Railsはこの2つの一致をチェック
した後、一致していたらそのパスワードをハッシュ化
してデータベースのpassword_digest属性に格納される
ようになっている。以上の記述を行うことで、ユーザーの新規登録時に入力したパスワードはハッシュ化されるようになる。
ターミナル$ rails g model user ... ... password_digest:stringdb/migrate/[timestamps]_create_users.rbclass CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| . . . t.string :password_digest . . . end end endターミナル$ rails db:migrateGemfilegem 'bcrypt', '~> 3.1.7'ターミナル$ bundle installapp/models/user.rbclass User < ApplicationRecord has_secure_password . . . end
試しにコンソールで確認してみる。$ rails c --sandbox > user = User.new(..., password: '123456', password_confirmation: '123456') > user.save => true >user.password_digest => 'fflafbnalwefhhhawkleufhb'ユーザーにpasswordとpassword_confirmationに任意の値を入力させれば、2つの属性が一致しているかどうかを検証した後に、ちゃんとハッシュ化されたパスワードがpassword_digest属性に保存されている事がわかる
参考
- 投稿日:2020-04-26T14:41:10+09:00
【ruby】paizaのための覚えておくと便利なメソッド1(ruby編)
1.読者対象
緊急事態宣言で外出禁止令が敷かれ切ない日々を送っている皆様が読者対象です。
三密を徹底的に排除するべく、飲食店関係や大好きなカラオケまでもが休業状態。
密かに楽しみにしていたフェスも、多分今年はいけないだろう。私事で恐縮だが、暫く封印していたポケモンにも、ジュラシックワールドにも、新しいキャラが増えすぎて何だかついていけない。
そんなこともあって休日を持て余していた。そんな時に目に入ったのが
『paiza スキルチェック』
だった。
プログラマの実力を測れるという存在だ。
いきなり高レベルの問題に取り組んでも、くじけてしまうかもしれない。
中々イケイケの言語が並んでいる。
業務で使わない言語でDランクから試してみる。
足し算のプログラムができただけでも、100点とか出るので気分は上がる活きたプログラミング言語の勉強にいいかも!!
『緊急事態宣言でつまらない日々のお供にpaizaを』
有り余る暇な時間を問題によっては『6時間近く格闘』なんてこともざらだ。
このスキルチェックを進めるには、知っておく必要のある関数がいくつかある。
paizaスキルチェックでは、入力変数を受け取って、その内容を元に処理を記述していく
流れになる。
以下に役立ちそうなメソッドをピックアップした。(初級程度ならいけそうかも)2.役立つメソッド一覧
(ⅰ)chompメソッド
getsで入力内容を受け取る時に、文字列の最後に改行が入っていたりする。
この改行を取り除いてくれるのがこのメソッド。paiza_memo1.rbdino_name1=gets puts dino_name1+"3" #改行を削除 puts dino_name1.chomp+"5"実行結果
c:\ruby_pg>ruby paiza_memo1.rb Tyrannosaurus Tyrannosaurus 3 Tyrannosaurus5chompを使わないと、改行も出力されている事がお分かりだろう。
ここで最後の改行を削除することが第一歩となる。(ⅱ)countメソッド
これが素晴らしいメソッド。
ある文字列に含まれる特定の文字列の個数を数えることができるメソッド。
中々貴重。paiza_memo1.rb#略 dino_name2='Tyrannosaurus' #指定文字列の中に、nが含まれる個数 puts dino_name2.count('n') #指定文字列の中に、oが含まれる個数 puts dino_name2.count('o') #指定文字列の中に、xが含まれる個数 puts dino_name2.count('x')実行結果
c:\ruby_pg>ruby paiza_memo1.rb ・・・ 2 1 0 c:\ruby_pg>(ⅲ)sliceメソッド
文字列を部分的に抽出するメソッド。
..と...で、処理が違うので注意
slice(開始位置..終了位置)
slice(開始位置...終了位置)
⇒開始位置を含む終了位置-開始位置の長さの文字列が抽出
slice(位置):指定した位置の文字列を抽出。paiza_memo1.rb#略 dino_name3='IndominusRex' puts dino_name3.slice(3) puts dino_name3.slice(0..dino_name3.length-3) puts dino_name3.slice(0...dino_name3.length-3) puts dino_name3.slice(2..5) puts dino_name3.slice(2...5)実行結果
c:\ruby_pg>ruby paiza_memo1.rb o IndominusR Indominus domi dom c:\ruby_pg>(ⅳ)to_iメソッド
間違った例
paiza_memo1.rb#略 numstr=gets.chomp! puts numstr+5実行結果
c:\ruby_pg>ruby paiza_memo1.rb
33
paiza_memo1.rb:36:in+': no implicit conversion of Fixnum into String (TypeError)
'
from paiza_memo1.rb:36:inc:\ruby_pg>
自動的に型を認識してくれないので、加算ができないのである
修正後
paiza_memo1.rbnumstr=gets.chomp! puts numstr.to_i+5実行結果
c:\ruby_pg>ruby paiza_memo1.rb 33 38 c:\ruby_pg>(ⅴ)gsubメソッド
gsub(変換前文字列,返還後文字列)という文字列置換メソッド。
これも出番が多い関数。実行例
paiza_memo1.rb#略 dino_name5=gets.chomp! tmpstr=dino_name5 puts tmpstr.gsub(dino_name5,"IndominusRex")実行結果
c:\ruby_pg>ruby paiza_memo1.rb cat IndominusRex c:\ruby_pg>猫がインドミナスレックスに変身してしまった。
(ⅵ)splitメソッド
split(区切り文字)で区切り文字を指定すると、文字列を配列に変換できるメソッド。
これはもう超鉄板。実行例
paiza_memo1.rbdinostr="Tyrannosaurus Velociraptor Stegosaurus" ar_dino=dinostr.split(' ') puts ar_dino[0] puts ar_dino[1]実行結果
c:\ruby_pg>ruby paiza_memo1.rb Tyrannosaurus Velociraptor c:\ruby_pg>最後に
paizaにトライするのに最低限必要になりそうな関数をまとめてみました。
『ソースコードに恐竜を』をテーマに終えることが出来てよかった。。。
それでは皆様良き自粛ライフを!!
- 投稿日:2020-04-26T13:54:42+09:00
HTML Rubyに絵文字を追加する
HTMLとRubyに?の様な絵文字を入れる方法をご紹介いたします。
絵文字の表示にはunicordを使います。
絵文字の検索はこちらで行いました。
https://lets-emoji.com/emojilist/HTML
😀
Ruby
下線部分を\u{}で囲むことで表示できる様になります。
\u{1F600}最後に
Line botを作った際にRubyへの絵文字挿入を行いました。
是非ご活用ください。
- 投稿日:2020-04-26T13:53:31+09:00
chmod 600 ←600ってなんやねん
近況報告
とりあえずデプロイは完了しました。readmeを書いて,投稿物を揃え,エラー対応すれば見世物としての体裁はできあがるのかな。某雑食系さんのツイートに,ポートフォリオはサーバーサイドの実力はもちろんのこと,コンテンツ力,そして見た目も評価の対象になりうるとありましたね(めっちゃ噛み砕いた)。自分のはサーバーサイドの記述,実力はまだまだですけど,見た目は手を抜かなければよくできるので,今の自分の最善を尽くした作品を作っていこうと思います。
今回の目的
chmodに続く数字を知る。
結論
ファイルへの権限の種類だよ
詳細
chmodは「change mode」の略で,桁数,数字の組み合わせによって編集の権限とかを設定しています。
これにより,第三者からの不正アクセスの予防に繋がります。
桁数 意味 1桁目(百の位) 所有者のアクセス権限の範囲 2桁目(十の位) グループのアクセス権限の範囲 3桁目(一の位) その他のユーザーのアクセス権限の範囲
数字 意味 4 読み出し許可 2 書き込み許可 1 実行許可 0 権限なし 数字の足し算で権限は増えていきます。例えば全ての権限なら
4+2+1+0で7に
読み出しと書き込みだけなら4+2で6になります。
このように編集できるユーザーを適宜設定できます。おわりに
Linuxのコマンドは他にもごっそりあるのでそれの一部と考えていただければ。
微量でも参考になったらLGTM,ご指導はコメント欄にお願いします!
- 投稿日:2020-04-26T13:50:02+09:00
なぜany?はpresent?より高速と言われるのか
はじめに
「present?メソッドとany?メソッドだったらany?メソッドが高速なのか・・・なぜだろう?」
この疑問を解決すべく、present?メソッドとany?メソッドの処理の違いについて調べてみました。環境
macOS Catalina Version 10.15.4
Ruby: 2.7.0
Ruby on Rails: 6.0.2.2present?メソッド、any?メソッドの違い
どちらもテーブルにデータが存在するかを確認するメソッドです。
けれども内部処理はどちらも異なっています。侍エンジニアブログさんの、any?メソッド記事の一部を抜粋します。
present?メソッドとany?メソッドとの違いについて紹介します。
結論からいうとany?メソッドの方が高速です。
present? → 全てのデータを取得する
any? → 1件のみデータを取得する
Railsが実行する
SQLを比較して違いを確認してみましょう。> Sample.where(name:"侍1").present? Sample Load (0.4ms) SELECT `samples`.* FROM `samples` WHERE `samples`.`name` = '侍1' => true > Sample.where(name:"侍1").any? Sample Exists (0.4ms) SELECT 1 AS one FROM `samples` WHERE `samples`.`name` = '侍1' LIMIT 1 => trueこのように、SQLの最後にLIMIT 1 が付与されています。
any?メソッドがpresent?よりも優れているように見えます。
ではなぜこのような処理になっているのか、Ruby on Railsのコードを追ってみました。なお、modelは侍エンジニアブログさんと同様のSampleモデル(stringのname属性のみ)を作成しています。
present?メソッドの内部処理
present?メソッド実行時のコードの場所はblank.rbとなっています。
このコードを追ってみます。>Sample.where(name: "侍1").method(:present?).source_location => ["/Users/xxxxx/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activesupport-6.0.2.2/lib/active_support/core_ext/object/blank.rb", 25]blank.rbdef present? !blank? endrelation.rbalias :loaded? :loaded def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {}) @klass = klass @table = table @values = values @offsets = {} @loaded = false @predicate_builder = predicate_builder @delegate_to_klass = false end def records # :nodoc: load @records end def load(&block) unless loaded? @records = exec_queries(&block) @loaded = true end self end def blank? records.blank? endよってpresent?メソッドを呼び出した場合、クエリ未発行ならば、exec_queryメソッドでクエリを発行します。
このクエリは、指定されたテーブルの全レコード検索となります。
その後、結果に応じてblank?を行います。
もしクエリ発行済であれば、クエリを発行せずにblank?を行います。any?の内部処理
any?メソッド実行時のコードの場所はrelation.rbとなっています。
このコードを追ってみます。>Sample.where(name: "侍1").method(:any?).source_location => ["/Users/xxxxx/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activerecord-6.0.2.2/lib/active_record/relation.rb", 277]relation.rbdef empty? return @records.empty? if loaded? !exists? end def any? return super if block_given? !empty? end def load(&block) unless loaded? @records = exec_queries(&block) @loaded = true end self endfinder_method.rbdef exists?(conditions = :none) if Base === conditions raise ArgumentError, <<-MSG.squish You are passing an instance of ActiveRecord::Base to `exists?`. Please pass the id of the object by calling `.id`. MSG end return false if !conditions || limit_value == 0 if eager_loading? relation = apply_join_dependency(eager_loading: false) return relation.exists?(conditions) end relation = construct_relation_for_exists(conditions) skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false endよってany?メソッドを呼び出した場合、毎回exists?メソッドにて、テーブルにレコードが1件あるかどうかクエリを発行します。
その後、結果を確認しています。
もしload変数がtrueになった場合は、クエリ発行せずに結果を確認するのみとなります。まとめ
最初に記載した疑問の答えです。
any?メソッドがpresent?よりも優れているように見えます。
ではなぜこのような処理になっているのか、Ruby on Railsのコードを追ってみました。present?メソッドの場合、初回のみ全レコードを取得するクエリを発行して判定します。
2回目以降の呼び出しはクエリを発行せずに判定します。any?メソッドの場合、基本的に毎回、テーブルから1件レコードを取得するクエリを発行して判定します。
このため、全レコードを取り出さないany?メソッドが高速と言われているだと思われます。
ご指摘等あればコメントにご記載をお願い致します。
参考記事
【Rails入門】any?メソッドの便利な使い方を紹介
RailsのActiveRecord::FinderMethodsのSQLクエリ発行の有無について調べる
ActiveRecord::QueryMethodsのselectメソッドについて深掘りしてみた
週刊Railsウォッチ(20191216前編)Rails 6.0.2がリリース、平成Ruby会議01開催、古いRailsのfindメソッド置き換えほか
RailsのArelを調査してみた
- 投稿日:2020-04-26T13:41:35+09:00
AWS Cloud9でRuby on Railsを動かしてみた
こんにちは!モリタケンタロウです!
今回はAWSのCloud9で、Ruby on Railsを動かす方法について紹介します。AWS Cloud9とは
AWS Cloud9については↓をご参考にどうぞ
Ruby on Railsとは
Ruby on RailsはRubyで動作するMVCモデルのフレームワークです。
Webアプリケーション開発に向いていて、世の中のあらゆるサービスがこのRuby on Railsでできています。
Railsはオワコンと言われていたりもしますが、僕が会社でRailsのWebアプリ開発をやっていたときに、勉強しやすくて書きやすかったので、とりあえず今回はRailsを使ってみようと思います。とにかくやってみよう!
AWS Cloud9では最初からRubyもRailsもインストールされています。
ruby -v
とrails -v
のコマンドで確認できます。
確認できたら早速アプリを作成してみましょう。
rails new [アプリ名]
コマンドで作ります。
そうすると、指定した名前のアプリのディレクトリが作成されました!
作ったアプリのディレクトリの中に入って、rails server
コマンドでアプリを動かしてみましょう。
動いている様子は、Preview > Preview Running Application で確認できます。
上手くいくと、こんな画面が出てきます。めでたしめでたし!
上手くいかないと、こんな画面が出てくるかもしれません。
そんなときは、↓を参考にしてみてください。ちょっとつまづきながらも無事に「Yay!…」という画面が出せたので、これからコツコツRails開発を始めていきます!
それでは~
- 投稿日:2020-04-26T13:40:32+09:00
Railsで新しいアプリを作ったらActiveRecord::ConnectionNotEstablishedが出てきた
こんにちは!モリタケンタロウです!
今回はRailsでアプリを新規作成して動かしてみたら、「ActiveRecord::ConnectionNotEstablished」というエラーが出てきたので、それを解決する方法について紹介します。開発環境
- ruby 2.6.3p62
- Rails 5.0.0
エラー内容
rails server
コマンドでアプリを動かすと、画面にはこんなエラーが出てきます。
ActiveRecord::ConnectionNotEstablished
No connection pool with id primary found
なにこれ!?分からん…
ということでググると、RailsのORM機能であるActiveRecordが、sqlite3
の新しいバージョンに対応してないことが原因らしい。(参考:ActiveRecord::ConnectionNotEstablished No connection pool)対処内容
ということで、Railsがインストールしているパッケージを管理しているGemfileを編集します。
gem 'sqlite3', '~> 1.3.6'Gemfileを編集したら、
bundle install
コマンドでインストールパッケージを更新します。
そしてrails server
コマンドでアプリを起動すると…
見事、アプリが正常に起動しました。めでたしめでたし!
ということで一件落着(^^)
それでは~
- 投稿日:2020-04-26T13:10:22+09:00
【Rails】モデルのオブジェクト生成に対する制限・制御を行ってくれる機能
はじめに
備忘録
目的
データベースに不正なデータが保存されないようにすること。
手段
1.データベースカラムに対して制御を記述する。
2.モデルに対して検証を記述する。両者の違い
データベースカラムに対する制御
➡︎一意性の検証➡︎ユーザーへエラーメッセージを届けられない
➡︎モデルでは弾けないような、直接データベースに他のシステムから操作を加える作業に対しての制御
モデルに対する検証
➡︎データベースでは制御しきれない部分の補完➡︎ユーザーへエラーメッセージを届ける事ができる
※今回は、制御に関する機能の説明のみです。
1.データベースカラムへの制御でよく行われる方法4つ
※データベースカラムへの制御はマイグレーションファイルに記述していくこと。
1.データ型を付与する。
➡︎データ型を付与する事で、そのデータ型以外のデータが格納されることを阻止する。
→例えば、「名前カラムには文字列しか格納させたくない」場合には、名前カラムに文字列のデータ型を付与すると良い。2.NOT NULL制約を付与する。
➡︎カラムに対して、必ず何かしらの値が格納されるようにしたい場合に空の値が格納されることを阻止する。
→例えば、ユーザーが新規登録する際に「名前が空のまま保存されることを阻止したい」場合には、この制約を追加すると良い。3.文字列の長さを制御する。
➡︎カラムに対して、文字列の長さを指定することで指定した文字列以上の長さのデータが格納されることを阻止する。
→例えば、ユーザーが新規登録する際に「名前が20文字以上になることを阻止したい」場合には、文字列の長さを制御してあげると良い。4.ユニークインデックスを付与する。
➡︎カラムに対して、ユニークインデックスを付与する事でそのデータの一意性が確保され、同じデータが格納されることを阻止する。
→例えば、ユーザーが新規登録する際に「メールアドレスが他のユーザーと被ることを阻止したい」場合には、メールアドレスカラムに対してユニークインデックスを付与してあげると良い。コマンドを実行してモデルのクラスファイル(マイグレーションファイル)を作成 $ rails g model Userdb/migrate/[timestamps]_create_users.rbclass CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :name, limit: 20, null: false t.string :email, null: false t.timestamps t.index :email, unique: true end end endマイグレーションファイルに変更を加えたらデータベースに変更を保存する $ rails db:migrate
t.string :name
➡︎データ型の付与
limit: 20
➡︎文字列の長さを制御
null: false
➡︎NOT NULL制約(SQLのnullとRubyのnilを混同させないこと)
t.index :email, unique: true
➡︎ユニークインデックス付与で一意性確保
2.モデルに対する検証方法は主に2つ
※モデルに対する検証はモデルファイルに記述していくこと。
※モデルに対する検証の仕組みは「検証結果が不正だった場合は、エラーメッセージを生成する」であることに注意。なので、例えばユーザーに新規登録をさせる場合は「検証で失敗した結果、何が原因で登録できなかったのかをユーザーに知らせる」事が目的。1.Railsであらかじめ用意されている、検証用のヘルパーメソッドを使う。
➡︎モデルに対して、validatesオプションを使って検証したいヘルパーメソッドを適用させることで、メソッドの内容に準じて検証を行う事ができる。
→例えば、ユーザーが新規登録する際に「名前未入力による登録する事を阻止したい」場合には、validatesオプションに対してそれ用のヘルパーメソッドを適用させる。
→その他にもたくさんの検証ヘルパーが用意されている。2.検証用のメソッドを自分で定義しちゃう。
➡︎モデルに対して、「どんな検証を行いたいか」「どんなエラーメッセージを表示させたいか」を考えてメソッドを定義していく。
→例えば、ユーザーが新規登録する際「名前にハイフンを入れる事を阻止したい」ときには「名前にハイフンを含ませた場合、"名前にハイフンを入れることはできません"というエラーメッセージを生成する」といったメソッドを定義すれば良い。➡︎メソッドを定義したら、validate(単数形であることに注意)オプションに適用させる。
app/models/user.rbclass User < ApplicationRecors validates :name, presence: true validate :validate_name_not_include_hyphen def validate_name_not_include_hyphen errors.add(:name, 'にハイフンを入れる事はできません') if name&.include?('-') end end
validates :name, presence: true
➡︎Userモデルのname属性の値が入力されていることをチェックする。
validate_name_not_include_hyphen
➡︎メソッド名。
errors.add(:name, 'にハイフンを入れることはできません') if name&.include?('-')
➡︎名前にハイフンが含まれていた場合、「(名前)にハイフンを入れることはできません」というエラーメッセージを生成する。➡︎nameに「&」を付けているのは、名前がnilだった場合に例外を発生させないため。nilだった場合はnilを代入させることができる。そうすることでvalidatesオプションのpresence: trueで検証させる。
※エラーメッセージを表示させるまでがゴール
エラーメッセージを生成・表示させるには(ユーザー新規登録を例にする)
1:新規登録ならユーザーコントローラのcreateアクション内で、送信されてきたデータからオブジェクトを
@user.save
メソッドで保存・更新する作業を行ってあげる。
➡︎ビューで再利用するためにインスタンス変数でオブジェクトを定義してあげること。2:不正なデータが送信された場合は、saveメソッドの効果により検証が実行され保存されずにfalseを返し、errorsという配列に保存に失敗したオブジェクトが格納される。
➡︎saveメソッドやupdate_attributesメソッドなど保存・更新時に検証を行ってくれるメソッド
を適用させないと、検証を実行してくれないので注意。
➡︎例えば、ユーザーが名前を空のまま保存したとしたら@user.errorsの配列には「@messages ={:name=>["を入力してください"]}
」という旨のエラーメッセージが格納される。3:
@user.errors.full_messages
と記述することで、errors配列に格納されているエラーメッセージを取得できる。
➡︎名前を入力してください
4:取得した上記のエラーメッセージをビューで表示することで、ユーザーにエラーメッセージを届ける事ができるようになる。
以上の手順を踏む必要がある。
参考
- 投稿日:2020-04-26T13:08:00+09:00
Paizaのスキルチェック(Ruby)を解きたいけど標準入力でつまづいた
プログラミングの勉強を始めたあたりの頃、
条件分岐(if,elsif,else...)とか繰り返し処理(each...)とか色々なメソッドを学び、「さぁこれでワイもプログラマーや!、ちょっと腕試しするか」
「スキルチェックぽち〜」
「うわ、めちゃ簡単や、ここで条件分岐して、このメソッドで一発やろ!、ワイに任せろ!」
「...」
「標準入力ってなんや...、解き方はわかるけど、値が受け取れんわ...」
って感じでpaizaのスキルチェックを始めた時に標準入力で困ったので、同じような人のために、paizaの標準入力の受け取り方を書いていきます。
標準入力の受け取り方
例えば下図のような標準入力があったとします。
標準入力 5 getsメソッドで受け取れます。
input = getsPaizaの標準入力は文字列で与えられます、今回は数字ですのでこのままだと計算したり大小比較ができないので、文字列から数値に変換しましょう。to_iメソッドを使うと可能です。
input = gets.to_igetsは複数回使うと次の標準入力を受け取ってしまうので、受け取った値を何回も使いたいときは変数に代入しておきましょう。今回はinputという名前の変数にしていますが、
a = gets
,number = gets
とかでも大丈夫です。1行の標準入力で複数の値を受け取る
1行に複数の値があった場合です。
Paizaだと複数の値に半角スペースを挟んだ文字列が渡されます。
標準入力 5 10 20 後ろに
.chomp!.split(" ")
をつけます
.chomp!
が改行を消すメソッドです、これをつけないと末尾に改行の記号がくっついてしまいます。
.split(" ")
が文字列を分解して配列に変換するメソッドです。引数に" "
を渡すことで半角スペースを区切りにして配列になります。input = gets.chomp!.split(" ")出力してみると
p input => ["5", "10", "20"]文字列でなく数値として受け取りたい場合はさらにmapメソッドを使いましょう。配列の値を一個ずつ取り出して数値に変換していきます。
input = gets.chomp!.split(" ").map{|n| n.to_i}出力してみると
p input => [5, 10, 20]複数行の標準入力を受け取る
複数行に値があった場合です。paizaの場合大抵一つ目の標準入力にこの後の標準入力の行数を与えてくれるので、それを利用します。
今回で言うと3ですね。
標準入力 3 5 10 20 まず最初の標準入力を受け取りましょう。
N = gets.to_i続いてこの値を用いて複数行の標準入力を受け取っていきます。
今回は5, 10, 20をそれぞれ配列に入れていく形で受け取っていきましょう。
timesメソッドを使います。
numbers = [] N.times do numbers << gets.to_i endnumbersと言う空の配列を用意して、N回標準入力を受け取ってnumbersに入れていくと言う流れです。
出力すると
p numbers => [5, 10, 20]これで標準入力が受け取れるので、受け取った値を使って問題を解いていけますね!
- 投稿日:2020-04-26T13:08:00+09:00
【Ruby】paizaのスキルチェックを解きたいけど標準入力でつまづいた
プログラミングの勉強を始めたあたりの頃、
条件分岐(if, elsif, else...)とか繰り返し処理(each...)とか色々なメソッドを学び、「さぁこれでワイもプログラマーや!、ちょっと腕試しするか」
「スキルチェックぽち〜」
「うわ、めちゃ簡単や、ここで条件分岐して、このメソッドで一発やろ!、ワイに任せろ!」
「...」
「標準入力ってなんや...、解き方はわかるけど、値が受け取れんわ...」
って感じでpaizaのスキルチェックを始めた時に標準入力で困ったので、同じような人のために、paizaの標準入力の受け取り方を書いていきます。
標準入力の受け取り方
例えば下図のような標準入力があったとします。
標準入力 5 getsメソッドで受け取れます。
input = getspaizaの標準入力は文字列で与えられます、今回は数字ですのでこのままだと計算したり大小比較ができないので、文字列から数値に変換しましょう。to_iメソッドを使うと可能です。
input = gets.to_igetsは複数回使うと次の標準入力を受け取ってしまうので、受け取った値を何回も使いたいときは変数に代入しておきましょう。今回はinputという名前の変数にしていますが、
a = gets
,number = gets
とかでも大丈夫です。1行の標準入力で複数の値を受け取る
1行に複数の値があった場合です。
paizaだと複数の値に半角スペースを挟んだ文字列が渡されます。
標準入力 5 10 20 後ろに
.chomp!.split(" ")
をつけます
.chomp!
が改行を消すメソッドです、これをつけないと末尾に改行の記号がくっついてしまいます。
.split(" ")
が文字列を分解して配列に変換するメソッドです。引数に" "
を渡すことで半角スペースを区切りにして配列になります。input = gets.chomp!.split(" ")出力してみると
p input => ["5", "10", "20"]文字列でなく数値として受け取りたい場合はさらにmapメソッドを使いましょう。配列の値を一個ずつ取り出して数値に変換していきます。
input = gets.chomp!.split(" ").map{|n| n.to_i}出力してみると
p input => [5, 10, 20]複数行の標準入力を受け取る
複数行に値があった場合です。paizaの場合大抵一つ目の標準入力にこの後の標準入力の行数を与えてくれるので、それを利用します。
今回で言うと3ですね。
標準入力 3 5 10 20 まず最初の標準入力を受け取りましょう。
N = gets.to_i続いてこの値を用いて複数行の標準入力を受け取っていきます。
今回は5, 10, 20をそれぞれ配列に入れていく形で受け取っていきましょう。
timesメソッドを使います。
numbers = [] N.times do numbers << gets.to_i endnumbersと言う空の配列を用意して、N回標準入力を受け取ってnumbersに入れていくと言う流れです。
出力すると
p numbers => [5, 10, 20]これで標準入力が受け取れるので、受け取った値を使って問題を解いていけますね!
- 投稿日:2020-04-26T12:40:51+09:00
AWSを用いてrailsアプリをデプロイするプロセスを頑張って噛み砕いてみるvol.6
近況報告
大海に糸を垂らして魚を釣るのと鱒がそこにいるとわかっている生簀で鱒を釣るの,どちらが先に釣れるでしょうか。価値があるから売れるのと,売れるから価値がある,どちらが始まりなのでしょうか。鶏と卵論争ではないけれども,考えていくべきことですよね。
ついに最後,Nginxですね。
まだやりたいことはあって,予定ではCapistranoとベーシック認証があるのでvol.8以上あるのか笑
さあいってみようかぁ!今回の内容
・インフラ整備での各アクションの言語化
・コードを単に打っているだけでは理解しきれないし,他に応用できないので言語化して整理
・テックキャンプ受講生支援()大まかな流れ&設定
Nginxインストール
事前準備
Nginxインストール&設定
EC2.sudo yum -y install nginxsudo yum の解説は前の項で触れています。
インストールできたら設定を編集していきます。むやみやたらにいじられたくないファイルなので権限も強いです。sudo権限でvim形式で編集していきます。EC2.$ sudo vim /etc/nginx/conf.d/rails.confrails.confupstream app_server { server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock; } ⇨Unicornと連携させるための設定。アプリケーション名を自身のアプリ名に書き換えることに注意。upstreamは上流の意。ここでunixが登場していることはよくわかんなかった。 server { ⇨ {}で囲った部分をブロックと呼ぶ。サーバの設定ができる listen 80; ⇨このプログラムが接続を受け付けるポート番号 server_name <Elastic IP>; ⇨接続を受け付けるリクエストURL client_max_body_size 2g; ⇨クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガ root /var/www/<アプリケーション名>/public; ⇨接続が来た際のrootディレクトリ location ^~ /assets/ { ←assetファイルはここに入っているのを参照するよ gzip_static on; ←圧縮状態のものを配信。容量が小さくなるのでメモリの負担減らせる expires max; ←キャッシュの有効期限。maxは限界までの意 add_header Cache-Control public; ←キャッシュを受け取る範囲の選択 ⇨assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定 } try_files $uri/index.html $uri @unicorn; ⇨ファイルの選択,右の$からアクセスされる location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; ⇨Nginxからユニコーンにむけた設定 } error_page 500 502 503 504 /500.html; ⇨エラーが表示された時のページ }と<アプリケーション名>計三箇所直したら,脱出(:wq)
補足
プロキシ
ブラウザとウェブサーバーの中間役。ウェブサーバーの情報をブラウザで写すが,プロキシはウェブサーバーの代理としてウェブサーバーからの情報を写す。 ⇨わかりやすかった説明
location unicornではHTMLメソッドの受け取る方法とか表示の仕方とか設定してるっぽい。権限変更を行ったあと,再起動をします。
EC2.$ cd /var/lib $ sudo chmod -R 775 nginx ←-RはNginxに対してって意味 $ cd ~ $ sudo service nginx restart ⇨初めにfailed出ても再起動でOKがでれば大丈夫カリキュラムで分からなかった点
POSTメソッドを用いるとエラーが発生する可能性があるから権限変更を行うらしいのですが,このコマンドが通信量の多いPOSTメソッドのエラーを防ぐのかまだ理解できていません。●補足chmodについて
UnicornをNginxに接続
config/unicorn.rblisten 3000 ↓以下のように修正 listen "#{app_path}/tmp/sockets/unicorn.sock"githubに反映後,EC2に読み込み。
unicorn再起動処理をして,ブラウザにElastic IPを直打ちしてアプリケーションのルートページが表示できれば成功。うまく表示できない場合はもう一回やり方を見直す。URLが見つからないことで表示されてない可能性があるので注意して見る。終わりに
テックキャンプのカリキュラム,はしょりすぎぃ!!!
まあ多分目的は完全理解というより大枠を捉えよ的な教科書みたいなアプローチですな。
10週間でやれることなんてたかがしれてるし,Nginxひとつとっても理解しようとすれば数百ページの本を読まないとだから無難なのかな(しかもオープンソースだから今この瞬間にアップデートされているかもしれない...)。微量でも参考になったらLGTM,ご指導はコメント欄にお願いします!
- 投稿日:2020-04-26T12:34:09+09:00
【Rails】Could not find a JavaScript runtime となる時の解決方法
【事象】
bundle exec rake db:create すると下記のエラーが出る。rake aborted!
ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime.
See https://github.com/rails/execjs for a list of available runtimes.【解決策】
Gemfileに下記を追加し、bundle installすると解決した。
ExecJSとは、RubyからJavaScriptコードを実行できるもの。
エラーの原因は、RubyからJavaScriptを呼び出す役割を持つ
ExecJSのランタイムが見つからないためのようなのでランタイムを追加してあげれば良いと推測。ExecJSのことを https://github.com/rails/execjs
で見たが、gem therubyracerをインストールするとエラーになったので
また調べてgem mini_racerをインストールすると解決した。
- 投稿日:2020-04-26T11:33:02+09:00
【Rails tutorial】 Herokuへのデプロイ&二回目以降のデプロイ方法
現在レイルズチュートリアルを進めているのでその経過をアウトプットしていきます。
今回はタイトル通りHerokuのデプロイ方法と二回目のデプロイ方法についてです。
チュートリアル通りに進めていましたが、git push heroku の部分でつまずきました。
結論から言うとconfigのdatabase.ymlの記述に問題がありました。
下の方にあるproduction: の部分を以下のように書き直します。
production:
<<: *default
adapter: postgresql
encoding: unicode
pool: 5簡単に言うとpostgreSQLを使うという宣言をする記述のようですね。
もしチュートリアル通りにやってうまくいかないという方はここを治すとデプロイできるかもしれないです。
そして二回目以降のデプロイ方法ですが演習の部分で元々のhello worldの表示をgoodbyeアクションの結果を表示できるようにしろという問題がありますが、指示通りにそのままgoodbyeアクションを記述してターミナルに git push heroku と入力するとupdate heroku Everything と出てうまくいったような感じになりますが heroku を開くと変わらずhello worldとなっています。
これは私の場合ですが変更した結果をgit?にコミットしていなかったのが原因だったようです。
なので下のように記述しました。
git commit -a -m "Update Gemfile for Heroku"
そして再度プッシュしたところ変更が反映されていました!
今回は以上です。
- 投稿日:2020-04-26T10:52:50+09:00
[rails] migrate:reset でのエラー
はじめに
railsでアプリを作成していた際、db:migrateをした際に、エラーが発生しめmigrate:resetをしたのですがその際初めてのエラーが発生したので、その備忘録として書きたいと思います。
最初のエラー
新しくテーブルを作成するためにマイグレーションファイルを編集して実行したところファイル内に記述していたテーブル名に記述ミスがあり、エラーが発生しました。
class CreateHoges < ActiveRecord::Migration[5.2] def change create_table :hoges do |t| t.references :huge t.text :text t.timestamps end add_foreign_key :hoges, :missname, column: :huge_id # missnameが記述ミス end endそのため、記述を直し改めてマイグレーションファイルを実行したところ以下のエラーが発生しました。
rails aborted! StandardError: An error has occurred, this and all later migrations canceled: SQLite3::SQLException: table "hoges" already exists: CREATE TABLE "hoges"どうやらテーブルは既に存在しているといって、エラーが起きているようです。
まさかと思いテーブルを確認しても出来ていません。
rails db:migrate:status で確認してもステータスは downになっていました。原因
どうやらmigrationの際に、処理が途中まで進んで、残りでエラーが起きているときは、テーブルは生成されているけれどもテーブルを生成したmigrationは未実行のステータスになっていることがあるようです。
(create_tableのあと、add_foreign_keyしたところにエラーがあって、というパターン)migrate:reset
ならば、一度データベースを全て削除した上で、再度実行したら直りそうです。
以下のコマンドを実行rails db:migrate:resetそしたら、またもやエラー
rake aborted! ActiveRecord::NoEnvironmentInSchemaError: Environment data not found in the schema. To resolve this issue, run: bin/rails db:environment:set RAILS_ENV=developmentなんだこれは、と思い調べたところ、どうやら指示されるようにコマンドを入力したら直りそうです。
以下の記事が、とても参考になります。
ActiveRecord::NoEnvironmentInSchemaErrorについて解決
まず指示されるまま以下のコマンドを実行
rails db:environment:setそして、再度以下のコマンドを。
rails db:migrate:resetようやく正常にテーブルを作成することができました。
おわり
今回はmigrate:resetで解決しましたが、もし他のテーブルに影響を与えない方法があるならば、教えていただければ幸いです。
最後まで読んでいただき、ありがとうございました。
- 投稿日:2020-04-26T09:46:38+09:00
【Rails】wheneverを用いたバッチ処理の実装
目標
登録ユーザー全員に、Googleメールを1日毎に送信する。
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
・メール送信機能を実装済み。
メール送信機能 ➡︎ https://qiita.com/matsubishi5/items/c88e8c58b1ce39302868
メール送信機能を編集
1.
「login_mailer.rb」
を編集daily_mailer.rbclass DailyMailer < ApplicationMailer def send_mail(user) @user = user mail to: @user.email, subject: "定期配信" end def self.send_when_everyday @users = User.all @users.each do |user| DailyMailer.send_mail(user).deliver end end end2.
「send_when_login.html.erb」
を編集daily_mailer/send_mail.html.erb<%= @user.name %> 様 <p>定期配信メールです。</p>3.
「application_controller.rb」
を編集application_controller..rb#コメントアウト又は削除 def after_sign_in_path_for(resource) LoginMailer.send_when_login(current_user).deliver root_path endバッチ処理を実装
1.
Gem
を追加Gemfilegem 'whenever', require: false
require: false
➡︎ アプリケーションには反映させずに、ターミナルにのみ反映させるターミナル$ bundle2.
「schedule.rb」
を作成ターミナル$ bundle exec wheneverize .3.
「schedule.rb」
を編集config/schedule.rbenv :PATH, ENV['PATH'] #絶対パスから相対パス指定 set :output, 'log/cron.log' #ログの出力先ファイルを設定 set :environment, :development #環境を設定 every 1.day do #1日毎に実行 #「DailyMailer」の、「send_when_everyday」メソッドを実行 runner "DailyMailer.self.send_when_everyday" end4.
「cron」
を反映ターミナル$ bundle exec whenever --update-crontabバッチ処理でよく使うコマンド
$ bundle exec whenever
➡︎ cronの設定を確認
$ bundle exec whenever --update-crontab
➡︎ cronを反映
$ bundle exec whenever --clear-crontab
➡︎ cronを削除参考サイト
- 投稿日:2020-04-26T09:35:06+09:00
Rubyの『テスト自動化』(Minitest)について、簡単にまとめてみた。
はじめに
これは、プロを目指す人のためのRuby入門(チェリー本)を読んで理解を自分なりにまとめて書き記した物です。
個人的にわからない箇所を書き記したものとなっていますので、全て書いているわけではありません。
しかし、みんながつまずく箇所は似通っているのでは?と思うのでその点に関しては、要点を絞った内容が書けているのではと思います(たぶん)。今回書くのは、その中でも『第3章:テストを自動化する』(Minitestの基本)についてです。
それでは、内容の方へ入りましょう!
テストを自動化する
ここで学ぶ事は、
・Minitestの基本
です。そして、テスト自動化とは名前の通り『勝手にテストを行ってくれて、ミスがないか確認してくれるものの事』です。
ミスがないかの確認を毎回毎回行うことは効率が悪いためです。●Minitestの基本
まずは、テスト用のフレームワークを用意します。
Rubyにおいてはそのフレームワークの一つとしてMinitestがあります。Minitestを使うメリットは、
・Rubyと一緒にインストールされるため、セットアップが不要
・学習コストの低さ
・Railsのデフォルトのテスティングフレームワークのため、Railsを開発するときにも知識を生かしやすい。今回のテストを行うにおいての簡単な手順としては、
1. Rubyプログラム(テストコード)を書く
2. テストコードの実行
3. テスティングフレームワークが結果をチェックして、結果報告では、実際にテストコードを書いていってみましょう。
test_ruby.rbrequire 'minitest/autorun' # Minitestのライブラリの読み込み class RubyTest < Minitest::Test def test_ruby #メソッド名はtest_で始めるのが必須 assert_equal 'RUBY', 'ruby'.upcase #この部分が検証される部分。 #assert_equalはMinitestのメソッド。意味は後で説明 end endassert_equal 期待する結果, テスト対象となる値や式この本で紹介されているのは、以下の3つのメソッド
(他にもメソッドは存在します。知りたい方は、MinitestのAPI公式ドキュメントへ)#①aとbが等しければテストはパス assert_equal b, a #②aが真であればパス assert a #③aが偽であればパス assert aそして、先ほどの
test_ruby.rb
のテストを実行した結果が$ ruby ruby_test.rb Run options: --seed 35176 # Running: . #←テストの進歩状況を表しています。(今回はテストメソッドが1個だけのためドットが一つだけ) Finished in 0.000979s, 1021.4507 runs/s, 1021.4507 assertions/s. # テストの実行スピード 1 runs, 1 assertions, 0 failures, 0 errors, 0 skipsfailuresとerrorsがどちらも0ならテストをパスしたことになります。
今回はテストにパスした例になりますが、次は失敗例をみてみましょう。●テストの実行結果、失敗例
test_ruby.rbrequire 'minitest/autorun' class RubyTest < Minitest::Test def test_ruby assert_equal 'Ruby', 'ruby'.upcase # assert_equal 'Ruby'に変更 end end$ ruby ruby_test.rb Run options: --seed 18225 # Running: F Failure: RubyTest#test_ruby [ruby_test.rb:5]: ←ruby_test.rb:5からruby_test.rbの5行目でテストが失敗していることが確認できる。 Expected: "Ruby" ←期待された結果 Actual: "RUBY" ←実際の結果 rails test ruby_test.rb:4 Finished in 0.001320s, 757.5753 runs/s, 757.5753 assertions/s. 1 runs, 1 assertions, 1 failures, 0 errors, 0 skips実行結果の説明をします。
今度はドットではなく、『F』に変わりましたが、これはFailureのFです。
その後は、どこで失敗したかが記載されています。●実行結果がエラーの場合
$ ruby ruby_test.rb Run options: --seed 35712 # Running: E Finished in 0.001649s, 606.4282 runs/s, 0.0000 assertions/s. 1) Error: RubyTest#test_ruby: NoMethodError: undefined method `upcase' for nil:NilClass Did you mean? case ruby_test.rb:5:in `test_ruby' 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips今度は、『F』だったところが、Errorの『E』へと変わりました。
1) Error:以降はエラー内容の詳細になります。
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
から、1件のエラーで終わったことが確認できました。
- 投稿日:2020-04-26T09:16:38+09:00
Ruby on Railsでサーバー起動に苦労した話
起こった現象
Ruby on Railsで
rails new hoge
としてファイルを作ったが、run git init from "."
のところで止まってしまった。
当然、rails s
としてもサーバーは起動せず、webpacker:install
しろというようなエラーがでた。現象としては下記のブログと同じ。
https://yoji4910.hatenablog.com/entry/2020/02/06/184457
ただ、このブログ記事にある通り-Gをしても治らなかった。対処法
色々調べたら下記Qiita記事を見つけた。
https://qiita.com/libertyu/items/1eb74adc817ab8971100
この記事の通り、rails webpacker:install
をしたら、下記のようなエラーが出た。'node' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 'nodejs' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
というわけで下記からNode.jsをダウンロード、インストールした。
https://nodejs.org/ja/download/こんどこそと思い、
rails webpacker:install
をするとYarnがないとエラーがでた。
これは上記のQiita記事と同じエラーなので、下記からYarnをダウンロード、インストールした。
https://classic.yarnpkg.com/ja/docs/install/#windows-stableそしてもう一度
rails webpacker:install
をするとやっと成功した。
rails s
をしてサーバー起動できた!
http://localhost:3000/
にアクセスすると、ちゃんと動いてることが確認できました。
感想
めんどくさかった。
どのRuby on Railsの記事を見ても、ほとんどがrails new hoge
でファイルが作成できることしか書いてなかった。
- 投稿日:2020-04-26T07:55:48+09:00
windows10(WSL2)でRailsの環境構築をしてみた~Rails導入/起動まで~(2)
はじめに
前回記事にてWSL2の導入ができましたが、今回はWSL2を用いて実際にUbuntu 18.04に環境を構築していきます。
Ruby(Rails)導入
@ksh-fthr さんの以下記事を参考にしました。
Windows10 で WSL を使って Rails 環境を構築したときのメモ
見出しRails 環境を構築しよう
の1~8
を実施してください。今回しようとしているのは上記の記事と若干違うので、以下の点だけ異なっています。
・Ruby 2.6.6
を導入
・sqlite3ではなくmysqlを導入するので7.sqliteを入れよう
は実施不要WebPackerの導入
rails6
からWebpacker
が必須となり、Webpackerを入れないと、Railsアプリ作成の際にエラーが出てしまいます。
Ubuntu 18.04 LST
にて以下コマンドを実行してください。まず、
Webpacekr
をインストールするためのyarn
をインストールします。
単純にapt-get install yarn
だけだとバージョンが古くてWebpackerをインストールできなかったので、以下コマンドでバージョンの新しいyarnを入れます。Ubuntu18.04curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - sudo apt-get update sudo apt-get install yarn本命のWebpackerを導入します。
Ubuntu18.04rails webpacker:installmysqlの導入
今回はsqliteの代わりに
mysql
を導入します。
Ubuntu 18.04 LST
にて以下コマンドを実行してください。mysqlの導入
Ubuntu18.04sudo apt-get install mysql-server mysql-clientmysqlのバージョン確認
Ubuntu18.04実行コマンド mysql --version 実行結果 mysql Ver 14.14 Distrib 5.7.29, for Linux (x86_64) using EditLine wrapperバージョンが表示されれば導入完了です。
mysql
にはデフォルトでroot
ユーザが用意されていますが、これをrails上で使用するとすると、権限の問題で弾かれてしまいます。
root以外のユーザを作成し、きちんと権限も与えてあげましょう。
以下、コマンド例になります。ユーザ作成例(rootで実行)
CREATE USER railsuser@'localuser' IDENTIFIED BY '******(パスワード)'権限付与例(rootで実行)
GRANT ALL ON *.* TO railsuser@'localuser';Atom導入
今回はエディターとして
Atom
を利用します。
Ubuntu 18.04 LST
にて以下コマンドを実行してください。Ubuntu18.04sudo apt-get install mysql-server mysql-client以下コマンドを実行すると、Atom がGUIで立ち上がってきます。
Ubuntu18.04atomRails サーバ起動
Ubuntu 18.04 LST
上でRailsサーバを起動していきます。1. アプリ作成
新しいアプリ作成します。
Ubuntu18.04rails new sample -d mysql cd sample2. mysql設定ファイル編集
/config/database.yml
にmysqlのログイン情報を記載します。database.yml# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver # gem install mysql2 # # Ensure the MySQL gem is defined in your Gemfile # gem 'mysql2' # # And be sure to use new-style password hashing: # https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html # default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: railsuser password: ******(パスワード) socket: /var/run/mysqld/mysqld.sock
username
とpassword
をmysql導入時に設定した内容にしてください。また、テスト・開発・本番用のDBはあらかじめmysqlにて作成しておいてください。
3. サーバ起動
サーバを起動します。
Ubuntu18.04rails s
- 投稿日:2020-04-26T05:20:55+09:00
WSL2でRailsの環境構築をしてみた~WSL2導入まで~(1)
はじめに
web開発に関してはmacユーザが多いと思うが、windowsでも WSL( Windows Subsystem for Linux) なるものでLinuxでのRailsの開発環境をある程度整えることができたので、備忘として残そうと思います。
環境 Windows 10 Home 64bit WSLを導入する
WSLの導入には@yoshigeさんの以下記事が非常に参考になりました。
まずは、以下の記事を参考にWSL1を導入し、初期設定まで済ませます。
Microsoft StoreでLinuxのディストリビューションを選んで導入することになるが、自分はUbuntu 18.04 LTS を導入しました。
初心者のためのWSL( 1 ) ~初期設定,CUI設定編~GUIも使えた方が便利なので、以下記事を参考にGUI設定まで済ませます。
初心者のためのWSL( 2 ) ~GUI設定,デスクトップ環境設定編~WSL2を導入する
WSL2の導入は少し複雑です。
1. Windows10 Insider Preview に登録 ⇒ ビルド更新
WSL2はビルドが
18917
以上でないと導入できません。以下URLの手順に沿ってWindows10 Insider Preview に登録しビルドを更新してください。
https://insider.windows.com/ja-jp/getting-started/#register2. ビルドを確認する
設定
⇒システム
⇒バージョン情報
でOSビルド欄をみて、18917
以上であることを確認してください。3. 仮想マシン有効化
以下コマンドを管理者権限のPowerShellで実行し、再起動してください。
powershell
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
4. WSL2へ切り替え
以下、コマンドを管理者権限のPowerShellで実行してください。
ビルドが18917
以上でないと、以下コマンドは実行できません。現在のWSLバージョンを確認する
実行コマンド wsl -l -v 出力結果 NAME STATE VERSION * Ubuntu-18.04 Running 1WSLバージョンを2へ切り替える(結構時間がかかるかもしれません)
wsl --set-version Ubuntu 2切り替え後のバージョンを確認する
実行コマンド wsl -l -v 出力結果 NAME STATE VERSION * Ubuntu-18.04 Running 2WSLのバージョンが「2」になっていることを確認出来たらWSL2の導入は完了です。
- 投稿日:2020-04-26T05:20:55+09:00
windows10(WSL2)でRailsの環境構築をしてみた~WSL2導入まで~(1)
はじめに
web開発に関してはmacユーザが多いと思いますが、windowsでも WSL( Windows Subsystem for Linux) なるものでLinuxでのRails開発環境をある程度整えることができました。
備忘として残そうと思います。
環境 Windows 10 Home 64bit また、今回導入したものは以下となります。
導入したもの Ruby 2.6.6 Rails 6.0.2.2 mysql for linux 14.14 Atom 1.45.0 WSLを導入する
WSLの導入には@yoshigeさんの以下記事が非常に参考になりました。
まずは、以下の記事を参考にWSL1を導入し、初期設定まで済ませます。
Microsoft StoreでLinuxのディストリビューションを選んで導入することになるが、自分はUbuntu 18.04 LTS を導入しました。
初心者のためのWSL( 1 ) ~初期設定,CUI設定編~GUIも使えた方が便利なので、以下記事を参考にGUI設定まで済ませます。
初心者のためのWSL( 2 ) ~GUI設定,デスクトップ環境設定編~WSL2を導入する
WSL2の導入は少し複雑です。
1. Windows10 Insider Preview に登録 ⇒ ビルド更新
WSL2はビルドが
18917
以上でないと導入できません。以下URLの手順に沿ってWindows10 Insider Preview に登録しビルドを更新してください。
https://insider.windows.com/ja-jp/getting-started/#register2. ビルドを確認する
設定
⇒システム
⇒バージョン情報
でOSビルド欄をみて、18917
以上であることを確認してください。3. 仮想マシン有効化
以下コマンドを管理者権限のPowerShellで実行し、再起動してください。
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform4. WSL2へ切り替え
以下、コマンドを管理者権限のPowerShellで実行してください。
ビルドが18917
以上でないと、以下コマンドは実行できません。現在のWSLバージョンを確認する
実行コマンド wsl -l -v 出力結果 NAME STATE VERSION * Ubuntu-18.04 Running 1WSLバージョンを2へ切り替える(結構時間がかかるかもしれません)
wsl --set-version Ubuntu 2切り替え後のバージョンを確認する
実行コマンド wsl -l -v 出力結果 NAME STATE VERSION * Ubuntu-18.04 Running 2WSLのバージョンが「2」になっていることを確認出来たらWSL2の導入は完了です。
WSL2へ切り替えた後の設定
1. .bash_profileを編集
WSL2に切り替えた後だと、ターミナル立ち上げの際に
.bashrc
を読み込んでくれない仕様になっているようです。参考
WindowsTerminalやPowerShellからWSL2を実行した際に~/.bashrcが読み込まれない自分は
.bash_profile
に以下を追加することで回避しました。if [[ -f ~/.bashrc ]] ; then ~/.bashrc fi3. GUI設定の変更
WSL2はWSLと違い、仮想マシン上でLinuxを動作させています。
参考
https://www.atmarkit.co.jp/ait/articles/1906/14/news019.htmlなのでWSLと違い、window環境 ⇔ Linux環境のIPアドレスが別々に扱われます。
以下、windowsのコマンドラインでipconfigを実行した例になります。
Wireless LAN adapter Wi-Fi: IPv4 アドレス . . . . . . . . . . . .: xxx.xxx.xxx.xxx サブネット マスク . . . . . . . . . .: 255.255.255.0 デフォルト ゲートウェイ . . . . . . .: xxx.xxx.xxx.1 イーサネット アダプター vEthernet (WSL): IPv4 アドレス . . . . . . . . . . . .: yyy.yyy.yyy.yyy サブネット マスク . . . . . . . . . .: 255.255.240.0 デフォルト ゲートウェイ . . . . . . .: yyy.yyy.yyy.1新しく
イーサネット アダプター vEthernet (WSL)
が追加されていることがわかります。
IPが起動するたびに変更されるので、Xlaunchの待受け先もそれに伴い修正する必要があります。GUI設定にて.bashrcに
export DISPLAY=localhost:0
と記載していた部分を以下のように修正します。export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0これで、IPアドレスが変更されても、設定しなおすことなくGUIが立ち上がります。
- 投稿日:2020-04-26T05:06:34+09:00
AWS Service health dashboardのRSSを、Slackに一括登録する
背景
- Personal Health dashboardがありつつ、やはりService health dashboardの情報は、それはそれとして購読したい。
- SlackにRSSリーダーがあるけど、1 URLずつ
/feed subscribe https://.....rss
と実行する必要があり拷問である。複数をベタっと貼ってもエラーになる。どうにか一括登録したい。- https://status.aws.amazon.com/rss/all.rss という全部入りがあるけど、使ってないリージョンのまで入ってるので、購読すると無駄にうるさい。また直近15記事しかなく、広域障害発生時は猛烈に流れて使い物にならないことが想定できる。製品ごとリージョンごとRSSで見るしかなさそう
- ググると手製の東京リージョンOPMLとか見つかるけど、数年前のものだったりする。常に最新のRSSであってほしい
解法
- https://status.aws.amazon.com/ からRSSのURLを、グローバルサービス、リージョナルサービスにバラして、ほしいリージョンだけにする。CLIで。
- Slack API から
/feed subscribe
コマンドを実行して登録するRSSのURLぜんぶ取ってくる
curlしたものをモゴモゴして取ってきます。
curl -s https://status.aws.amazon.com/ \ | perl -wpl -e 's|\"|\n|g' | grep "/rss/" \ | perl -wpl -e 's|^|https://status.aws.amazon.com|g' \ | sort -u \ > all.txtグローバルとリージョナルに分割する
URLリストを眺めると、リージョナルサービスにはリージョン名がURLに含まれており、グローバルサービスはサービス名だけであることがわかります。すっごく雑に、
- ハイフンが複数個なければグローバルサービス
- ハイフンが複数個あるならリージョナルサービス
とバラせそうでした。
cat all.txt \ | grep -Ev '.*-.*-.*-' > global-products.txt cat all.txt \ | grep -E '.*-.*-.*-' > regional-products.txt最初はハイフンの有無で分けてみたのですが、以下の例外があることがわかり、「ハイフンが複数個の有無」で、としました。
https://status.aws.amazon.com/rss/import-export.rss https://status.aws.amazon.com/rss/management-console.rss https://status.aws.amazon.com/rss/s3-us-standard.rssリージョンごとに分割
せいぜい2 - 3リージョンしか使ってないでしょうから、欲しいリージョンのものだけに絞りたい、なので分割します。
rm -f regional-products.*.txt cat regional-products.txt \ | rev | awk -F'[.-]' '{print $0 " " $2 "-" $3 "-" $4}' | rev \ | awk '{print "echo " $2 " >> regional-products." $1 ".txt"}' \ | bashSlackのAPIトークンを発行する
ここあまり詳しくなく申し訳ないのですが https://api.slack.com/legacy/custom-integrations/legacy-tokens で生成したトークンで動いたのでヨシとしています。
手元にrubyをインストールする
2.6系で最新を選んでおけばいいのではないでしょうか。この後で使う
slack-ruby-client
も入れておいてください。brew install rbenv ruby-build rbenv install 2.6.6 rbenv global 2.6.6 gem install slack-ruby-clientSlackに一括登録するRubyスクリプトを用意する
https://gist.github.com/sasasin/28fbb22d3e40dd8518be5f2f30df5e42 をテキトーな場所に転がしてください。
以下のように動かすことができます。
export SLACK_API_TOKEN="xoxp-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ./slack_slash_command.rb "#general" "/feed" "subscribe https://status.aws.amazon.com/rss/iam.rss"Slackに一括登録する
これまでの情報を総合して、以下のように実行することで一括登録できます。
export SLACK_API_TOKEN="xoxp-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" export CHANNEL_NAME="#投稿先チャンネル名" cat global-products.txt \ | xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXX cat regional-products.ap-northeast-1.txt \ | xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXX cat regional-products.us-east-1.txt \ | xargs -L1 -I XXX ./slack_slash_command.rb "${CHANNEL_NAME}" "/feed" "subscribe "XXXCodeBuildで定期実行する
一回やってそれきりではないはず。利用するAWS製品もリージョンも増減していくでしょうから、それなり簡単に自動登録したいでしょう。CodeBuildで定期実行させましょう。
こんなbuildspecです。
version: 0.2 env: parameter-store: # 格納先のSSMパラメータストア名は好みで SLACK_CHANNEL_NAME: "/CodeBuild/SLACK_CHANNEL_NAME" SLACK_API_TOKEN: "/CodeBuild/SLACK_API_TOKEN" phases: install: commands: - gem install slack-ruby-client - curl -s -o ./slack_slash_command.rb https://gist.githubusercontent.com/sasasin/28fbb22d3e40dd8518be5f2f30df5e42/raw/0294724cc31abeb2f02b04ac05fd95d28732d37d/slack_slash_command.rb - chmod +x slack_slash_command.rb build: commands: - | curl -s https://status.aws.amazon.com/ \ | perl -wpl -e 's|\"|\n|g' | grep "/rss/" \ | perl -wpl -e 's|^|https://status.aws.amazon.com|g' \ | sort -u \ > all.txt - cat all.txt | grep -Ev '.*-.*-.*-' > global-products.txt - cat all.txt | grep -E '.*-.*-.*-' > regional-products.txt - | rm -f regional-products.*.txt cat regional-products.txt \ | rev | awk -F'[.-]' '{print $0 " " $2 "-" $3 "-" $4}' | rev \ | awk '{print "echo " $2 " >> regional-products." $1 ".txt"}' \ | bash - ls -alF *.txt - | cat global-products.txt \ regional-products.ap-northeast-1.txt \ regional-products.us-east-1.txt \ | while read FEED_URL; do ./slack_slash_command.rb "${SLACK_CHANNEL_NAME}" "/feed" "subscribe ${FEED_URL}" sleep 3 done
- コンテナイメージは
ruby:2.6-buster
で動作確認しています- チャンネル名やSlackトークンは、SSMパラメータストアなどに入れましょう。
SLACK_CHANNEL_NAME
はパブリックチャンネルの場合は#general
のように#
を付ける必要があります- いますぐ使うCodeBuild を参考に、好みの周期で定期実行させます
- 例として東京とバージニア北部リージョンで動かしてます
- 当初
sleep 3
は入れずに動かしたら、途中から「お前やりすぎ3秒後にリトライしろ」でコケるようになったので追加してます参考