- 投稿日:2020-03-23T23:41:19+09:00
ActionMailerでメール認証を実装した
バージョン
- rails: ver 6.0.1
- ruby: 2.6.5
- テスト: rspec
はじめに
ActionMailer
を使ってメール認証を実装しました。やりたいこと
この一連の流れを実装していきます
実装
メールを設定する
設定の部分はこの記事を参考にさせていただきました。本記事ではActionMailerにどのようにメール認証機能を持たせたか書きます。
rails g mailer NotificationMailer
でメーラーを作成します
ここにメールの送り先や、メールの件名を指定しますapp/mailers/authenticate_mailer.rbclass AuthenticateMailer < ApplicationMailer def send_authenticate_mail(user) @user = user # メールを誰に送るか、メールの件名を設定 mail to: user.email, subject: '[dot] メール認証' end end
メーラーの名前.html.haml
にメールの本文を記述します
ここではauthenticate_mail.html.haml
app/views/authenticate_mail..htmlhaml%p #{@user.name_sei} 様 %p 以下のリンクをクリックしてメール認証を完了させてください。 -# トークンを含んだメールURL %p= link_to 'メール認証完了する', authenticate_completed_url(@user.auth_token)トークンを作成するためのカラムを作る
参考: Railsでトークン認証のログインAPI実装
ユーザーにトークンを持たせるためにカラムを追加してくださいrails g migration add_token_to_users token:token
rails db:migrate
ユーザーモデルに
has_secure_password
を書くことによってユーザーにトークンを持たせることができるuser.rbclass User < ApplicationRecord ... has_secure_token :auth_token ... endメールに認証機能をつける
ここからがメールに認証機能を持たせるための処理になります
app/controllers/authentications_controller.rbclass User::AuthenticationsController < User::ApplicationController # ログインしていないユーザーのアクセスを許可するかどうかはauthenticate_user!を使用してください # authenticate_user!はdeviseに標準で搭載されているので定義する必要はありません skip_before_action :authenticate_user!, only: [:authenticate_completed] # メールを送信しました def authenticate user = current_user # メールを送信するための処理 AuthenticateMailer.send_authenticate_mail(user).deliver end # メール認証を完了しました def authenticate_completed # 認証メールのリンクからトークンを取得してそのトークンを持つユーザーを探す user = User.find_by(auth_token: params[:auth_token]) if user # トークンを再生成する、古いトークンを新しく書き換える user.regenerate_auth_token # is_confirmed_atに日付がいれて認証が完了していることを表す。済んでいなければnil user.is_confirmed_at = Time.current user.save! else redirect_to root_path end end end適宜viewを作成してください
authenticate.html.haml
,authenticate_completed
AuthenticateMailer.メーラーで作成したメソッドの名前(user).deliver
ここではAuthenticateMailer.send_authenticate_mail(user).deliver
で画面を表示すると同時にサーバーからメールを送信しています。最後に
どんな簡単な質問でも大歓迎です!
(15分考えてわからなければ質問してください!)
※上から下までコピペしてできるものではありません。私の作ったサービス独特なものがあるのでカスタマイズしていただく必要があります。間違っている点や、抜けがある、もっといいやり方があるなどもおしゃってください!
- 投稿日:2020-03-23T19:11:33+09:00
Railsにて検索機能を実装 (全体一致や部分一致などのselectボックスを入れ、複数モデルからの検索を可能にする)
備忘録として、なるべく自分の理解している範囲で、考え方の順序なども記載していく。
railsを触って、数週間なので、初心者の人のために
慣れている人や頭のいい人だと、そんなのわかってるよと言われることまで書いていきます。
間違っていたら教えてください。
devise でログイン機能は追加しており
UserモデルとBookモデルを作っています。
検索フォームをログインしている場合、全てのページに表示させたいので
app/views/layouts/application.html.erb のviewに記載していく。
<% if user_signed_in? %>
<%= form_tag(search_path, method: :get) do %>
<%= select_tag 'range' ,options_for_select([['---選択してください---', ''], ['User', '1'], ['Book', '2']]) %>
<%= select_tag 'search', options_for_select([["前方一致","forward_match"], ["後方一致","backward_match"], ["完全一致","perfect_match"], ["部分一致","partial_match"]]) %>
<%= text_field_tag (:word) %>
<%= submit_tag "検索" %><% end %>
<% end %>
全体を<%= form_tag(search_path, method: :get) do %>と<% end %>でくくって
searchアクションにparamsである'range', 'search',(:word)を飛ばす
<%= select_tag 'range' ,options_for_select([['---選択してください---', ''], ['User', '1'], ['Book', '2']]) %>
これの意味は['User', '1']この[]の中のUserを選んだ場合(ドロップダウンリスト)
’1’を'range'というparamsに入れて、コントローラに飛ばすために書いた。
<%= select_tag 'search', options_for_select([["前方一致","forward_match"], ["後方一致","backward_match"], ["完全一致","perfect_match"], ["部分一致","partial_match"]]) %>
これも同様にドロップダウンリストで選べるようにしているのですが
"前方一致"を選んだら"forward_match"を'search'というparamsに入れてsearchコントローラに飛ばすために書いた。
この2つのコードはselectボックスを作るために
select_tag 'paramsを決めてここに書く', options_for_select
params名はなんでも良い。
<%= text_field_tag (:word) %>
これは検索フォームに入力したワードをwordというparamsに入れて上と同様にsearchコントローラに飛ばすために書いた。
つまり3つのparamsをsearchコントローラに飛ばすコードを書いた。
こんな感じのができる。
続いてsearchesコントローラを書いていく
class SearchesController < ApplicationController
def search
@range = params[:range]
search = params[:search]
word = params[:word]if @range == '1'
@user = User.search(search,word)
else
@book = Book.search(search,word)
endend
viewページから飛ばした3つのparamsをそれぞれインスタンス変数かローカル変数の中に入れるために
@range = params[:range]
search = params[:search]
word = params[:word]を書いた。
searchとwordをローカル変数にしたのはmodelのメソッド(今回だとUserモデルとBookモデル)で利用するため、インスタンス変数じゃなくていいから。
if @range == '1'
@user = User.search(search,word)
else
@book = Book.search(search,word)1をユーザーが選んだ場合、@userをviewページで反映させ、2を選んだら@bookを反映させる条件分岐。
ここで.search(search,word)という searchメソッドを定義しなければいけない。
これはモデルで定義していく。
モデルについて
以下がモデルに検索のメソッドを定義する部分です。
ドロップダウンリストでUserを選んだ場合、
Userモデルにsearchメソッドを書いて、それをsearchコントローラーで呼べるようにする。
app/models/user.rb
def self.search(search,word)
if search == "forward_match"
@user = User.where("name LIKE?","#{word}%")
elsif search == "backward_match"
@user = User.where("name LIKE?","%#{word}")
elsif search == "perfect_match"
@user = User.where("#{word}")
elsif search == "partial_match"
@user = User.where("name LIKE?","%#{word}%")
else
@user = User.all
end
endこの書き方はググって出てきたものを真似した。
注意点は自分で定義した(search,word)2つのparamsを書くこと
searchにはviewページに書いた"forward_match"や"backward_match"が入ってきている。
wordにはユーザーが検索フォームに入れたワードが入っている。
User.where("name LIKE?","#{word}%")
このコードはUserモデルから検索ワードにヒットしているかを確認するコードで
nameはUserテーブルのカラム名を記載する。
名前での検索だと思うのでnameにしてある
続いて、ユーザーBookを選んだ場合のメソッドをBookモデルに書いていく
def self.search(search, word) if search == "forward_match" @book = Book.where("title LIKE?","#{word}%") elsif search == "backward_match" @book = Book.where("title LIKE?","%#{word}") elsif search == "perfect_match" @book = Book.where("#{word}") elsif search == "partial_match" @book = Book.where("title LIKE?","%#{word}%") else @book = Book.all endend
Userモデルと同様の書き方にする
そして検索結果を表示するviewページを作成
今回はsearchesフォルダにsearch.index.html.erbを作成したので
routes.rbに
get 'search' => 'searches#search'
追記した。
続いて
search.index.html.erbには
<h2>Results index</h2> <!--books一覧 --> <table class="table table-hover table-inverse"> <thead> <tr> <th></th> <th>Title</th> <th>Opinion</th> <th colspan="3"></th> </tr> </thead> <tbody> <% if @range == '2' %> <% @book.each do |book| %> <tr> <td> <%= link_to(book.user) do %> <%= attachment_image_tag(book.user, :profile_image, :fill, 50, 50, fallback: "no-image-mini.jpg") %> <% end %> </td> <td><%= link_to book.title, book, class: "book_#{book.id}" %></td> <td><%= book.body %></td> </tr> <% end %> </tbody> <% else %> <thead> <tr> <th>image</th> <th>name</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @user.each do |user| %> <tr> <td><%= attachment_image_tag(user, :profile_image, :fill, 50, 50, fallback: "no-image-mini.jpg") %></td> <td><%= user.name%></td> <td><%= link_to "Show", user, class: "user_#{user.id}" %></td> </tr> <% end %> </tbody> <% end %> </table>終わりに
以上が検索機能の実装方法になります。
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!
- 投稿日:2020-03-23T18:20:23+09:00
3/23 最終課題五日目
3/23
最終課題五日目メモです
できている商品詳細ページをgithubに
出してコードレビューをするコンフリクトが起こっていたので
修正した後にコードレビューをしてもらうaタグはlink_toで書きましょう。
と指摘を頂いたので
修正
修正後無事にLGTMともらうその後マージしてマスターにプッシュする
そして今まで作ったとこに変なところが無いかや修正があるか探すとりあえず簡単な修正をしてコミットし
マスターにプッシュしましたこれで商品詳細ページ(マークアップ)が終わったので次に進む
次はサーバーサイドに進むが
みんなで話し合った結果
先に商品出品のサーバーサイドを進めることに決定
2人で進めることになりました
画像のところとその他で別れることに決定Git hubでブランチを作った後さらに
ブランチを作ることで二人で進めれるようにする
(孫ブランチ?)
子ブランチの状態で新しいブランチを作る
そうするとマスターブランチの小ブランチを作るか
小ブランチの孫ブランチを作るかと選択が出るので
孫の方を選択
作る際のブランチの名前は小ブランチの名前と一緒もしくは似ているものは
エラーの原因になるプルリクエスするときは気をつける
間違ってもマスターにプルリクエストを送ることはしないこと!!!やること
* 商品モデルと商品の画像モデルを作成し、1つの投稿フォームで記事とそれに紐付く複数の画像を投稿できる
* 画像は送信前にプレビューを表示できる
* 上記要件を満たし、1度出品した商品の編集ができる
* 編集画面から、ひもづく画像の変更、削除、追加ができる
* 商品を削除する機能がある
* 商品を削除する際は、削除した商品に紐づく画像が同時に削除されるデータベースを作らないとできないので
データベースを作る
Itemsテーブルを作る際外部キーが原因でエラー
Itemテーブルと関連づけされているテーブルを作っていく調べたこと
Webスクレイピングとは、ウェブサイトのHTMLから必要なデータを取得する事を言い、
それを行うプログラムをスクレイパとも呼びます。Ancestryとは
AncestryはRuby on RailsのActiveRecordモデルのレコードを
ツリー構造(階層)として編成することを可能にするGemです。
カテゴリーを作る際に必要になるgemです
https://qiita.com/Rubyist_SOTA/items/49383aa7f60c42141871
参考ページorderとは
取得した値に対して、条件を指定して並び替えることができる機能
並びの順番を変えることができる
降順にする場合は”DESC”、昇順は”ASC”
https://techacademy.jp/magazine/7727
参考ページカテゴリーにpathカラムがあったので
Pathカラムがわからなかったので調べた
https://kyabatalian.hatenablog.com/entry/2016/12/19/193430
参考ページ
path列に対してパターン比較すれば先祖を取得できます。
メソッドとかもあるので必要みたいですマイグレーションをしてエラーが出たので
結局は原因はわからなかったけど
メモで
Gemfile
gem 'ancestry'ターミナル
$ bundle install
$ rails g migration add_ancestry_to_category ancestry:string:index
$ rake db:migrate
ここでエラー
エラーの原因を探して解決方法を見る
テーブルがおかしなことになっているのでリセットする
$ rake db:migrate reset
またエラー
というのを繰り返した結果
途中でモデルに記述するとうまくいった
記述していなかったのが原因?
初歩ミスっぽいです
- 投稿日:2020-03-23T14:21:59+09:00
ActiveRecord で unscoped を呼ぶとその前のクエリが消える
ブログ記事からの転載です。
unscoped
を使うことでdefault_scope
を取り除くことができるさて、皆さん大好き
default_scope
ですが、モデルでdefault_scope
を定義すると次のように暗黙的にクエリが追加されます。class User < ActiveRecord::Base default_scope { order(:updated_at) } end # 暗黙的に ORDER BY のクエリが追加れる puts User.all.to_sql # => SELECT "users".* FROM "users" ORDER BY "users"."updated_at" ASC puts User.where(name: "Tom").to_sql # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom' ORDER BY "users"."updated_at" ASC毎回
order(:updated_at)
する必要がないので便利ですね。
でも『あ〜今日はdefault_scope
のクエリ追加してほしくないな〜〜〜』って思うときがあると思うんですよ。
そういう時にunscoped
を使うとdefault_scope
のクエリを取り除く事ができます。# unscoped を付けると default_scope はつかなくなる puts User.unscoped.all.to_sql # => SELECT "users".* FROM "users" puts User.unscoped.where(name: "Tom").to_sql # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom'これで
default_scope
をつかっていてもシュッと取り除く事ができて便利ですね!
default_scope
以外のクエリも取り除かれる
unscoped
を使うことでdefault_scope
を取り除く事ができるようになります。
しかしunscoped
はめちゃくちゃ強くて『呼び出すよりも前のリレーション』も取り除いてしまします。# unscoped よりも前に付けた where のクエリも消してしまう puts User.where(name: "Tom").unscoped.to_sql # => SELECT "users".* FROM "users"
unscoped
でdefault_scope
を消したい場合は必ず『一番最初』にunscoped
を呼び出しましょう。
逆に『レシーバのクエリを全部消したい』場合はunscoped
を呼び出すと一括で消すことができるので便利です。
- 投稿日:2020-03-23T12:07:26+09:00
Herokuへのデプロイ手順|Rails + MySQL
はじめに
MySQLで作成したRailsアプリを、Herokuを使ってデプロイすることがあったので備忘録としてまとめました。同じ環境で初めてデプロイする方の参考になれば幸いです。
自分の環境
- macOS 10.15.3
- DB: MySQL
- Rails 5.0.7
Railsアプリケーションの作成
・アプリ作成 [現在作成中]
・Gemfile修正
sqlite3
が入っている場合は、以下のようにしてproduction環境下で反映されないようにしましょう。Gemfile.rbgroup :development, :test do gem 'sqlite3', '~> 1.4' end下記
mysql2
を追加。Gemfile.rbgem 'mysql2'・config/environments/production.rbの設定
Heroku上の本番環境でHTMLにCSSやJavaScriptが反映されるように、以下の記述を書き換えます。
ターミナル# デフォルトのfalseをtrueにします。 config.assets.compile = true作成したRailsアプリをGit管理
Railsプロジェクトに移動します。(ディレクトリへのパスは自身の物へ置き換えてください)
ターミナル$ cd rails/MyApp以下を実行すると、RailsアプリがGit管理されます。
ターミナル# リポジトリを新規作成。 $ git init # 変更があったすべてのファイルがaddされる。 $ git add . # ファイルの変更や追加などを保存。 $ git commit -m "<ここにコミットメッセージをいれる>"Herokuアカウントの登録
https://jp.heroku.com/ にて登録。
Heroku CLIのインストール
Heroku CLIをインストールすると、ターミナル上でHerokuのコマンド操作ができるようになります。
https://devcenter.heroku.com/articles/heroku-cli
上記サイト、もしくは下記コマンドでインストールできます。ターミナルbrew tap heroku/brew && brew install heroku以下のコマンドで、インストールができているか確認します。
ターミナル$heroku -v >>heroku/7.0.47 darwin-x64 node-v10.1.0SSH公開鍵の作成、Herokuへ追加
・SSH公開鍵の作成
まずは公開鍵が作成されているか確認しましょう。
ターミナルcat ~/.ssh/id_rsa.pub作成されてない場合は以下のように表示されます。
ターミナルNo such file or directoryそれでは公開鍵を作成していきましょう。(実行ディレクトリはどこでも大丈夫です)
ターミナル$ ssh-keygen Generating public/private rsa key pair # 鍵の保存先を聞かれます。変更する必要はないので、そのままEnterキーで進みます。 Enter file in which to save the key (/Users/ユーザー名/.ssh/id_rsa): # 鍵のパスワードを設定するか聞かれます。 # 設定しない場合はそのままEnterを、設定する場合はパスワードを入力します。 Enter passphrase (empty for no passphrase): # パスワードの確認をされます。同じパスワードを入力してください。 # 設定していない場合は空欄のままEnterキーで進みます。 Enter same passphrase again:これで公開鍵が作成されました。確認しましょう。
ターミナルcat ~/.ssh/id_rsa.pub #このように文字列が表示されるはずです。 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@mylaptop.local・Herokuに公開鍵を追加
Herokuにログインします。
ターミナル$ heroku login以下のコマンドでSSH公開鍵がHerokuに追加されます。
ターミナル$ heroku keys:add ~/.ssh/id_rsa.pub追加されたか確認しておきましょう。
ターミナル$ heroku keys # SSHキーの一部が表示されます。 ssh-rsa AAAA...BBBB作成したRailsアプリとHerokuの紐付け
Railsプロジェクトに移動します。(ディレクトリへのパスは自身の物へ置き換えてください)
ターミナル$ cd rails/MyAppHerokuへ新しいアプリケーションを作成しましょう。
ターミナル$ heroku apps:create <好きなアプリ名>以下のように表示されたらアプリ名が既に使われちゃってます。
重複は許されないので他のアプリ名へ変更しましょう。ターミナルName myapp is already takenHerokuにDBを追加
・MySQLを追加
以下のコマンドで、
clearDB
というMysqlを使うためのアドオンがignite
プランで追加されます。ターミナル$ heroku addons:create cleardb:ignite以下のような表示が出たら、クレジットカードの登録が必要です。
ターミナル▸ Please verify your account to install this add-on plan (please enter a credit card) For more ▸ information, see https://devcenter.heroku.com/categories/billing Verify now at ▸ https://heroku.com/verify*アドオンを追加するためにクレジットの登録が必要ですが、iginteプランは無料で使えます。
詳しいプラン内容については以下を参照。
https://elements.heroku.com/addons/cleardb・Herokuアプリに環境変数を設定
以下のコマンドで、環境変数に入る値を取得します。
ターミナル$ heroku config === <アプリの名前> Config Vars CLEARDB_DATABASE_URL: mysql://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=trueHerokuアプリの環境変数に、上記で取得した値をそれぞれ設定。
ターミナル$ heroku config:add DB_NAME='<データベース名>' $ heroku config:add DB_USERNAME='<ユーザー名>' $ heroku config:add DB_PASSWORD='<パスワード>' $ heroku config:add DB_HOSTNAME='<ホスト名>' $ heroku config:add DB_PORT='3306' # gemで「mysql2」を使用しているので、mysql://ではなく「mysql2://」とします。 $ heroku config:add DATABASE_URL='mysql2://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true'設定した値を確認しましょう。
以下のように表示されるはずです。$ heroku config === <アプリの名前> Config Vars CLEARDB_DATABASE_URL: mysql://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true DATABASE_URL: mysql2://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true DB_HOSTNAME: <ホスト名> DB_NAME: <データベース名> DB_PASSWORD: <パスワード> DB_PORT: 3306 DB_USERNAME: <ユーザー名>Herokuにデプロイ
以下コマンドでローカルリポジトリをHerokuへpushすると、自動でデプロイが進んでいきます。
ターミナル$ git push heroku master*master以外のブランチをpushする場合は以下を実行
ターミナル$ git push heroku <ブランチ名>:master最後に以下のコマンドを入力して、データベースのマイグレーションをします。
ターミナル$ heroku rake db:migrate以下のコマンドを実行すると、ブラウザでアプリケーションにアクセスできます。
ターミナル$ heroku openお疲れ様でした!
参考サイト・記事
mysqlを使ったRailsアプリをHerokuにデプロイする流れ
Deploying with Git
SSH 公開鍵の作成
- 投稿日:2020-03-23T11:54:51+09:00
ツイッター風Railsアプリをテストする(統合テスト編)
この記事の基本的な方針
今回は別記事、ツイッター風Railsアプリ最短復習(忙しい人の流し読みで開発シリーズ)で作ったアプリの統合テストをします。
手を動かしながら読みたいようでしたら、以下でこのツイッター風Railsアプリを手に入れてください。
Terminal$ git clone https://github.com/annaPanda8170/cheaptweet.git $ bundle install $ bundle exec rake db:create $ bundle exec rake db:migrate基本解説はしません。手順のみ示します。
想定する読み手
既に一度Railsアプリをチュートリアルやスクール等で作ったことがある方を想定しております。
Mac使用で、パソコンの環境構築は完了していることが前提です。具体的な手順
①準備
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:feature cheapTweet $ rails g factory_bot:model user $ rails g factory_bot:model tweet $ bundle exec spring binstub rspec control + c $ rails s.rspec--format documentation※これでRspecの出力が読みやすくなるそうです。
spec/rails_helper.rb#省略 require 'capybara/rspec' include Warden::Test::Helpersここで空っぽのまま一度起動してみます。
Terminal$ bundle exec rspecOutputCheapTweets add some scenarios (or delete) /Users/handaryouhei/Desktop/cheaptweet/spec/features/cheap_tweet_spec.rb (PENDING: Not yet implemented) Pending: (Failures listed here are expected and do not affect your suite's status) 1) CheapTweets add some scenarios (or delete) /Users/handaryouhei/Desktop/cheaptweet/spec/features/cheap_tweet_spec.rb # Not yet implemented # ./spec/features/cheap_tweet_spec.rb:4 Finished in 0.0014 seconds (files took 2.21 seconds to load) 1 example, 0 failures, 1 pendingspec/factories/tweets.rbFactoryBot.define do factory :tweet do text {"hello"} association :user end endspec/factories/users.rbFactoryBot.define do factory :user do sequence(:nickname) { |n| "annaPanda#{n}" } sequence(:email) { |n| "a#{n}@a" } password {"111111"} password_confirmation {"111111"} end end②テスト構築
spec/features/cheap_tweet_spec.rbrequire 'rails_helper' RSpec.feature "CheapTweets", type: :feature do scenario "新規登録するとログアウトが表示されているTOP画面に遷移する" do visit root_path click_link "会員登録" fill_in "user_nickname", with: "annaPanda" fill_in "user_email", with: "a@a" fill_in "user_password", with: "111111" fill_in "user_password_confirmation", with: "111111" click_button "Sign up" expect(page).to have_content 'ログアウト' end scenario "ログインするとログアウトが表示されているTOP画面に遷移する" do user = FactoryBot.create(:user) visit root_path click_link "ログイン" fill_in "user_email", with: "a1@a" fill_in "user_password", with: "111111" click_button "Log in" expect(page).to have_content 'ログアウト' end scenario "非ログイン状態でTOP画面に遷移するとログアウトが表示されていない" do visit root_path expect(page).not_to have_content 'ログアウト' end scenario "投稿したらデータベースにtweetが一つ増える" do user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path expect{ click_link "投稿" fill_in "tweet_text", with: "こんにちは" click_button "投稿" }.to change( Tweet.all, :count ).by(1) end scenario "自分で投稿したtweetをshowして編集するとindexに反映される" do user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path click_link "投稿" fill_in "tweet_text", with: "こんにちは" click_button "投稿" click_link "こんにちは" click_link '編集' fill_in "tweet_text", with: "こんにちは!" click_button '編集' visit root_path expect(page).to have_content 'こんにちは!' end scenario "自分以外が投稿したtweetをshowすれば編集ボタンが表示されない" do tweet = FactoryBot.create(:tweet) visit root_path click_link "a" expect(page).not_to have_content '編集' end scenario "自分で投稿したtweetをshowして削除ボタンを押せばデータベースのtweetが一つ減る" do user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path click_link "投稿" fill_in "tweet_text", with: "こんばんは" click_button "投稿" click_link "こんばんは" expect{ click_link "削除" }.to change( Tweet.all, :count ).by(-1) end scenario "自分以外が投稿したtweetをshowすれば削除ボタンが表示されない" do tweet = FactoryBot.create(:tweet) visit root_path click_link "hello" expect(page).not_to have_content '削除' end scenario "ヘッダーの自分の名前をクリックすると自分の投稿一覧が表示される" do tweet = FactoryBot.create(:tweet) user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path click_link "投稿" fill_in "tweet_text", with: "おはよう" click_button "投稿" click_link "投稿" fill_in "tweet_text", with: "さようなら" click_button "投稿" within 'header' do click_link user.nickname end expect(page).to have_content 'おはよう' expect(page).to have_content 'さようなら' expect(page).not_to have_content 'hello' end scenario "TOP画面の投稿者をクリックするとそのユーザーの一覧が表示される" do tweet = FactoryBot.create(:tweet) user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path click_link "投稿" fill_in "tweet_text", with: "おはよう" click_button "投稿" click_link "投稿" fill_in "tweet_text", with: "さようなら" click_button "投稿" click_link tweet.user.nickname expect(page).not_to have_content 'おはよう' expect(page).not_to have_content 'さようなら' expect(page).to have_content 'hello' end scenario "コメントすると表示される" do tweet = FactoryBot.create(:tweet) user = FactoryBot.create(:user) login_as(user, scope: :user) visit root_path click_link "hello" fill_in "comment_text", with: "ハロー" click_button "コメント" expect(page).to have_content 'ハロー' end end
click_link
とclick_button
で指定しているのはテキストです。
fill_in
で指定しているのはidです。
have_content
で表示されているかを確認しています。Terminal$ bundle exec rspecOutputCheapTweets 新規登録するとログアウトが表示されているTOP画面に遷移する ログインするとログアウトが表示されているTOP画面に遷移する 非ログイン状態でTOP画面に遷移するとログアウトが表示されていない 投稿したらデータベースにtweetが一つ増える 自分で投稿したtweetをshowして編集するとindexに反映される 自分以外が投稿したtweetをshowすれば編集ボタンが表示されない 自分で投稿したtweetをshowして削除ボタンを押せばデータベースのtweetが一つ減る 自分以外が投稿したtweetをshowすれば削除ボタンが表示されない ヘッダーの自分の名前をクリックすると自分の投稿一覧が表示される TOP画面の投稿者をクリックするとそのユーザーの一覧が表示される コメントすると表示される Finished in 0.87206 seconds (files took 2.18 seconds to load) 11 examples, 0 failures
まとめ
読むだけなら割と直感的にいけると思います。
この統合テストさえ済ませていれば、コントローラは不要なのでは?という考えもあるようです。
モデルのテストとこの統合テストを行うことがRailsアプリのテストのスタンダードになるかもしれませんね。
- 投稿日:2020-03-23T11:44:27+09:00
Kinx 実現技術 - Switch-Case
Switch-Case
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。作ったものの紹介だけではなく実現のために使った技術を紹介していくのも貢献。その道の人には当たり前でも、そうでない人にも興味をもって貰えるかもしれない。
前回のテーマは構文解析。今回のテーマは Switch-Case。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- リポジトリ ... https://github.com/Kray-G/kinx
Switch-Case
なぜ Switch-Case を取り上げるかというと、やはり ジャンプテーブル の魅力があるから。基本多分岐なので、複数の条件に対して一発でジャンプできるのが期待値だろう。ただ、そのために結構複雑な処理をしている。
整数値・それ以外
まず、数値(整数)かそれ以外かで動作が異なる。整数値以外は基本
if-else
にするしかないのだが、整数値は可能ならジャンプテーブルにしようと試みる。なので、まずは整数値かどうか確認し、どちらかに分岐させる。整数値の場合
整数値の場合、ジャンプ・テーブル化を試みる。ただし、下限と上限の差がありすぎる場合、無駄なジャンプが増えすぎてしまうという問題がある。そこで、閾値を設定して複数のブロックに分割する。例えば以下のケースをパースした場合、
switch (a) { case 10: break; case 11: break; case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: break; case 51: break; case 52: break; case 53: break; case 54: break; case 100: break; case 'aaa': break; default: break; }1~100 までのジャンプテーブルを作ってしまうと 13 個だけが有効で、残りの 87 個は default にジャンプするだけの無駄が多いテーブルを作ってしまう。アドレス(ポインタ)サイズが 64bit の場合、100 個のジャンプを用意するだけで 800 バイト必要になる。800 バイトが多いかどうかは別にして、無駄なスペースが沢山あることに違いはない。
そこで、まず数値自体をソートして順に確認していき、閾値(デフォルトは 16)以上のインターバルがあった場合、別々のグループ(ブロック)に分けて、それぞれでジャンプテーブル化させるようにする。どのブロックに分岐するかは二分探索で選択する形でコード出力する(場合によっては線形探索)。
ちなみにブロック内の選択肢が少ない場合はあえてジャンプテーブル化はしない。線形探索や二分探索の方が効率が良い場合がある。なぜなら、ジャンプテーブルの場合、上限・下限値を越えないか比較し、評価値から下限値を減算してその上でジャンプさせることになるので都合3回は比較が入る。例えば比較値が 1 種類の場合、単に一発比較するだけの方が効率が良い。したがって、これにもブロック内の要素数を考慮してどの方式を使うかを決定する。
ちなみに、今後触れようと思うが VM コードの実行で Switch-Case を採用する場合のペナルティ(ダイレクト・スレッディングの有効性)は一般的には CPU パイプラインの投機実行ミスを指摘されるが、この比較回数もあるんじゃないかと思う。何せ 1 命令実行するために最低 3 回は比較と分岐が入る。明らかに上限・下限を超えないと判断できない限り、範囲外の条件判断は必要だしね。この辺は投機実行でカバーできているのかもしれないが。
上記の場合、1~11 のブロック、51~54 のブロック、100 だけのブロックに分かれる。評価値(
a
)の値によって二分探索(または線形探索)でどのグループを探索するかを決め、それぞれのグループの中で実際のジャンプ先を決定する。それ以外
それ以外の場合、単に線形探索でジャンプ先を決定する。つまり
if-else
の連続で値をチェックする。出力例
具体的な出力コードは以下のような感じ。
break
しかしてないので結局最後に jmp しているだけで、本気で最適化したらこのコード自体出力されないよなものだが現時点ではサーチのエッセンスは出力されている。.L460 d04: enter 7, vars(1), args(1) .L462 d06: pushvl0 $0(0) d07: dup d08: typeof is integer d09: jz .L463(d1d) d0a: dup d0b: lti 1 d0c: jnz .L464(d22) d0d: dup d0e: gti 11 d0f: jnz .L464(d22) d10: subi 1 d11: jmptbl d12: jmp .L482(d47) d13: jmp .L482(d47) d14: jmp .L482(d47) d15: jmp .L482(d47) d16: jmp .L482(d47) d17: jmp .L482(d47) d18: jmp .L463(d1d) d19: jmp .L463(d1d) d1a: jmp .L463(d1d) d1b: jmp .L482(d47) d1c: jmp .L482(d47) .L463 d1d: dup d1e: pushs "aaa" d1f: eqeq d20: jnz .L482(d47) d21: jmp .L482(d47) .L464 d22: dup d23: lti 51 d24: jnz .L465(d32) d25: dup d26: gti 54 d27: jnz .L465(d32) d28: dup d29: eqeqi 51 d2a: jnz .L482(d47) d2b: dup d2c: eqeqi 52 d2d: jnz .L482(d47) d2e: dup d2f: eqeqi 53 d30: jnz .L482(d47) d31: jmp .L482(d47) .L465 d32: dup d33: neqi 100 d34: jnz .L463(d1d) d35: jmp .L482(d47) .L466 (省略) .L482 d47: ret null d48: halt出力コードを見るとまだまだ改善点はあるものの、初版としては十分かなー、と。
Switch-Case の魅力はやはり ジャンプテーブル と言っても過言ではない。それが無ければ Switch-Case を使う意味は間違いなく半減するよね。それができることを期待して Switch-Case を選ぶということも多いですし。例えば、Yacc で出力された構文解析器なんかは Switch-Case の塊なので、全ての比較が
if-else
で行われていたら正直パフォーマンス的にやってられないレベルで遅くなってしまう。つまり、Switch-Case はジャンプテーブル化しないと使い物にならないので頑張った。おわりに
ここまで読んでいただいてありがとうございます。最後はいつもの以下の定型フォーマットです。
- 最初の動機は スクリプト言語 KINX(ご紹介) を参照してください(もし宜しければ「
いいねLGTM」ボタンをポチっと)。- リポジトリは ここ(https://github.com/Kray-G/kinx) です。こちらももし宜しければ★をポチっと。
- 投稿日:2020-03-23T10:50:33+09:00
headerとflashの間にできた謎の余白を消す(Devise, Bootstrap)
はじめに
先日投稿したこちらで
Bootstrap + jQueryを使ってFlashなどの
<button>xボタン</button>
をクリックした時にFlashを閉じる機能を実装しました。
ただ、ブラウザ場で確認すると、
Flashが消える前、後、双方で との間に余白がないようにぴったり合わしているにも関わらず
<header>
とflash
の間に余白が発生していました。この余白を無くすことができたので紹介します。
開発環境
- bootstrap-sass (3.3.7)
- devise (4.7.1)
- jquery-rails (4.3.1)
- rails (5.2.4.1)
前置き (layoutのデザイン)
header.html<header class= "header-layout navbar navbar-fixed-top navbar-inverse">
- Bootstrapの
navbar-fixed-top
を使ってheaderを固定しております。- headerの下の
<%= yield%>
には画面いっぱいの背景画像を設置した表紙のようになっております。headerの下にHome画面レイアウトの背景画像がぴったりになるように
<body>
padding: top;
でしっかり合わせてあります。)(余白ができていた時のパターン↓)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> //ここ <%= alert %> //ここ <body>*おそらく、ユーザーがログイン後に
flash[:notice]
が呼び出された場合、flash[:alert]は、余白としてflash[:norice]の上に表示されていました。if構文(余白消えない。)
まずこちらを参考にしてみた
https://whatsupguys.net/programming-school-dive-into-code-learning-47/]app/views/shared/_flash_messages.html.erb<% if notice %> //条件 <% elsif alert %> //条件 <% end %>上記のように条件を組んでブラウザ場の検証を確認しても
ブラウザ場の検証(要素) <header> </header> " " //謎の余白 <class= "alert"> "ログインしました" //flash[:notice] </>flashは表示できているけれど
<header>
とflash
が呼ばれる<class= "alert">
の間に" "
と表示され、余白の原因になっています。
おそらく" "
の部分は表示されなかったflash[alert]
だと思います。
if構文を使って条件を書いても、、余分な余白は表示されたままでした。解決方法
解決方法を調べてみました。
まず、deviseとBootstrapを組み合わせる祭、Bootstrapには、
deviseのkey
である[:notice]
,[:alert]
に対応したクラスがないので、key
を置き換えることが最善です。こちらを参考に
(https://hachy.github.io/2019/10/15/flashes-with-devise-and-bootstrap.html)app/helpers/users_helper.rbmodule UsersHelper #Bootstrapに対応できるdevise flash[notice][alert]を変更する def bootstrap_alert(key) case key when "alert" "warning" when "notice" "success" when "error" "danger" end end end
:alert
→:warning
,:notice
→:success
に変更する為にヘルパーメソッドを作成しています。(devise userモデルを使っているのでそのヘルパーを利用しています。)Flashの変更
変更前↓ (deviseのデフォルト)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> //ここ <%= alert %> //ここ <body>変更後↓
app/views/shared/_flash_messages.html.erb<% flash.each do |key, value| %> <div class="alert alert-<%= bootstrap_alert(key)%> close-flash"> <%= value %> <button type="button" class="close close-button" data-dismiss="alert"> × </button> </div> <% end %>
- deviseのデフォルトflashを変更し、Bootstrapに組み合わせれるように作ったヘルパーメソッド
bootstrap_alert(key)
を使ってdeviseflash[:key]
を変更。これでFlash[:key]がしっかりBotstrapにも適用でき、余分な
" "
が呼び出されることなく、特定のflash[:key]だけが呼び出され余白も消えました。参考にしたサイト
- 投稿日:2020-03-23T10:28:44+09:00
Devise <%= notice %> <%= alert %>による余白をなくす方法
はじめに
先日投稿したこちらで
Bootstrap + jQueryを使ってFlashなどの
<button>xボタン</button>
をクリックした時にFlashを閉じる機能を実装しました。
ただ、ブラウザ場で確認すると、
Flashが消える前、後、双方で
<header>
と<%= yield%>
の間に余白が発生していました。この余白を無くす方法を紹介します。
開発環境
- bootstrap-sass (3.3.7)
- devise (4.7.1)
- jquery-rails (4.3.1)
- rails (5.2.4.1)
前置き (layoutのデザイン)
私の場合
<header>
はheader.html<header class= "header-layout navbar navbar-fixed-top navbar-inverse">
- Bootstrapの
navbar-fixed-top
を使ってheaderを固定しております。headerの下の
<%= yield%>
には画面いっぱいの背景画像を設置した表紙のようになっております。(余白ができていた時のパターン↓)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> //ここ <%= alert %> //ここ <body>ユーザーがログイン後に、
flash[:notice]
が呼び出された場合、呼び出されなかったflash[:alert]は、余白としてflash[:norice]の上に表示されていました。if構文(余白消えない。)
まずこちらを参考にしてみた
https://whatsupguys.net/programming-school-dive-into-code-learning-47/]app/views/shared/_flash_messages.html.erb<% if notice %> //条件 <% elsif alert %> //条件 <% end %>上記のように条件を組んでブラウザ場の検証を確認しても
ブラウザ場の検証(要素) <header> </header> " " //謎の余白 <class= "alert"> "ログインしました" //flash[:notice] </>flashは表示できているけれど
<header>
とflashが呼ばれる<class= "alert">
の間に" "
と表示され、余白の原因になっております。
おそらく" "
の部分は表示されなかったflash[alert]
だと思います。
if構文を使って条件を書いても、、余分な余白は表示されたままでした。解決方法
解決方法を調べてみました。
まず、deviseとBootstrapを組み合わせる祭、Bootstrapには、
deviseのkey
である[:notice]
,[:alert]
に対応したクラスがないので、key
を置き換えることが最善です。こちらを参考に
(https://hachy.github.io/2019/10/15/flashes-with-devise-and-bootstrap.html)app/helpers/users_helper.rbmodule UsersHelper #Bootstrapに対応できるdevise flash[notice][alert]を変更する def bootstrap_alert(key) case key when "alert" "warning" when "notice" "success" when "error" "danger" end end end
:alert
→:warning
,:notice
→:success
に変更する為にヘルパーメソッドを作成しています。(devise userモデルを使っているのでそのヘルパーを利用しています。)Flashの変更
変更前↓ (deviseのデフォルト)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> // <%= alert %> // <body>変更後↓
app/views/shared/_flash_messages.html.erb<% flash.each do |key, value| %> <div class="alert alert-<%= bootstrap_alert(key)%> close-flash"> <%= value %> <button type="button" class="close close-button" data-dismiss="alert"> × </button> </div> <% end %>
- deviseのデフォルトflashを変更し、Bootstrapに組み合わせれるように作ったヘルパーメソッド
bootstrap_alert(key)
を使ってdeviseflash[:key]
を変更。これでFlash[:key]がしっかりBotstrapにも適用でき、余分な
" "
が呼び出されることなく、特定のflash[:key]だけが呼び出され余白も消えました。参考にしたサイト
- 投稿日:2020-03-23T10:28:44+09:00
Devise <%= notice %> <%= alert %>による謎の余白をなくす方法
はじめに
先日投稿したこちらで
Bootstrap + jQueryを使ってFlashなどの
<button>xボタン</button>
をクリックした時にFlashを閉じる機能を実装しました。
ただ、ブラウザ場で確認すると、
Flashが消える前、後、双方で
<header>
と<%= yield%>
の間に余白が発生していました。この余白を無くす方法を紹介します。
開発環境
- bootstrap-sass (3.3.7)
- devise (4.7.1)
- jquery-rails (4.3.1)
- rails (5.2.4.1)
前置き (layoutのデザイン)
私の場合
<header>
はheader.html<header class= "header-layout navbar navbar-fixed-top navbar-inverse">
- Bootstrapの
navbar-fixed-top
を使ってheaderを固定しております。headerの下の
<%= yield%>
には画面いっぱいの背景画像を設置した表紙のようになっております。(余白ができていた時のパターン↓)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> //ここ <%= alert %> //ここ <body>ユーザーがログイン後に、
flash[:notice]
が呼び出された場合、呼び出されなかったflash[:alert]は、余白としてflash[:norice]の上に表示されていました。if構文(余白消えない。)
まずこちらを参考にしてみた
https://whatsupguys.net/programming-school-dive-into-code-learning-47/]app/views/shared/_flash_messages.html.erb<% if notice %> //条件 <% elsif alert %> //条件 <% end %>上記のように条件を組んでブラウザ場の検証を確認しても
ブラウザ場の検証(要素) <header> </header> " " //謎の余白 <class= "alert"> "ログインしました" //flash[:notice] </>flashは表示できているけれど
<header>
とflashが呼ばれる<class= "alert">
の間に" "
と表示され、余白の原因になっております。
おそらく" "
の部分は表示されなかったflash[alert]
だと思います。
if構文を使って条件を書いても、、余分な余白は表示されたままでした。解決方法
解決方法を調べてみました。
まず、deviseとBootstrapを組み合わせる祭、Bootstrapには、
deviseのkey
である[:notice]
,[:alert]
に対応したクラスがないので、key
を置き換えることが最善です。こちらを参考に
(https://hachy.github.io/2019/10/15/flashes-with-devise-and-bootstrap.html)app/helpers/users_helper.rbmodule UsersHelper #Bootstrapに対応できるdevise flash[notice][alert]を変更する def bootstrap_alert(key) case key when "alert" "warning" when "notice" "success" when "error" "danger" end end end
:alert
→:warning
,:notice
→:success
に変更する為にヘルパーメソッドを作成しています。(devise userモデルを使っているのでそのヘルパーを利用しています。)Flashの変更
変更前↓ (deviseのデフォルト)
application.html.erb<body> <%= render 'shared/header'%> <%= notice %> // <%= alert %> // <body>変更後↓
app/views/shared/_flash_messages.html.erb<% flash.each do |key, value| %> <div class="alert alert-<%= bootstrap_alert(key)%> close-flash"> <%= value %> <button type="button" class="close close-button" data-dismiss="alert"> × </button> </div> <% end %>
- deviseのデフォルトflashを変更し、Bootstrapに組み合わせれるように作ったヘルパーメソッド
bootstrap_alert(key)
を使ってdeviseflash[:key]
を変更。これでFlash[:key]がしっかりBotstrapにも適用でき、余分な
" "
が呼び出されることなく、特定のflash[:key]だけが呼び出され余白も消えました。参考にしたサイト
- 投稿日:2020-03-23T02:52:01+09:00
重要なgemのうち、開発が止まってしまったgemがいくつあるか集計してみた
core-jsがメンテされていない理由を読みました。この記事によると、core-jsというJavaScript界隈の重要な(しかし一般の開発者にはほとんど知られていない)ライブラリのメンテが止まってしまったとのこと。
JavaScript界隈の特殊な事情があるにせよ、Rubyにも、開発が止まりそうなgemはたくさんある気がします。そこで、重要なgemのうち、開発が止まりそうなものがいくつあるのかを調べてみました。
先に結論
重要なgemのうち、開発が既に止まっているものは0件でした。「利用者数に対して開発者が極端に少ない」という意味で止まる可能性が比較的高いものは minitest gemでした。
補足:minitest gemについては、主なコミッタの人数が少ないだけです。今も活発にコミットされています。今すぐ何かがあるわけではまったくありません。
やったこと
重要なgemのうち、開発が止まっている、もしくは止まる可能性があるものをリストアップしてみました。
「重要なgem」の定義
本記事では、Rails gemから依存関係をたどったときに、二次のつながりまでに含まれるgemの最新バージョンから依存されているgemを「重要なgem」とします。
もっと言うと、下記のgemから依存されているgemであれば、それは重要なgemです。
- 一次のつながり
- sprockets-rails
- railties
- activesupport
- activestorage
- activerecord
- activemodel
- activejob
- actionview
- actiontext
- actionpack
- actionmailer
- actionmailbox
- actioncable
- 二次のつながり
- websocket-driver
- rails-dom-testing
- rack-test
- globalid
- marcel
- concurrent-ruby
- method_source
探索の開始点としてRailsを選んだ理由は、簡易的な集計の結果、もっとも一般に利用されているgemがRailsだったからです。
上記の条件を満たすgemであっても、開発が活発なgemからのスピンオフgemであったり、止まっているというよりは安定しているgemについては除外しています。
集計に使ったデータの出典
当たりを付けるための簡易的な集計には、Libraries.io Open Dataを利用しました。このデータの最終更新は2020年1月12日なので、さらに最新データの裏取りとしてGitHubのデータを利用しています。
集計結果
最終更新に着目した集計
最終更新が半年以上前のgemのうち、本当に開発が止まりそうなgemは0件でした。
最終更新から時間が経っているgemはいくつかあるものの、いずれも、活発なgemからのスピンオフであったり、ドキュメントの更新くらいしか必要なかったりという状況です。
最終候補に残ったgemは下記の通りです。
+------------------+----------------------+------------------------+-------------------------------+----------------------------------+-----------------------------------------------------+ | Project Name | Dependency Name | Repository Stars Count | Repository Contributors Count | Repository Last pushed Timestamp | left(b.`Repository URL`, 100) | +------------------+----------------------+------------------------+-------------------------------+----------------------------------+-----------------------------------------------------+ | actioncable | websocket-driver | 171 | 13 | 2019-09-10 12:55:43 UTC | https://github.com/faye/websocket-driver-ruby | | actionmailbox | mail | 2976 | 184 | 2018-10-13 20:15:01 UTC | https://github.com/mikel/mail | | actionmailer | mail | 2976 | 184 | 2018-10-13 20:15:01 UTC | https://github.com/mikel/mail | | actionmailer | rails-dom-testing | 75 | 15 | 2018-07-04 12:29:01 UTC | https://github.com/rails/rails-dom-testing | | actionpack | rack-test | 770 | 57 | 2018-07-22 10:43:43 UTC | https://github.com/rack-test/rack-test | | actionpack | rails-dom-testing | 75 | 15 | 2018-07-04 12:29:01 UTC | https://github.com/rails/rails-dom-testing | | actionview | rails-dom-testing | 75 | 15 | 2018-07-04 12:29:01 UTC | https://github.com/rails/rails-dom-testing | | activejob | globalid | 650 | 43 | 2019-01-11 13:58:34 UTC | https://github.com/rails/globalid | | activestorage | marcel | 56 | 6 | 2018-09-15 03:06:56 UTC | https://github.com/basecamp/marcel | | activesupport | concurrent-ruby | 4493 | 103 | 2019-03-11 09:52:28 UTC | https://github.com/ruby-concurrency/concurrent-ruby | | concurrent-ruby | ref | 60 | 6 | 2017-11-18 10:41:28 UTC | https://github.com/ruby-concurrency/ref | | mail | mini_mime | 38 | 12 | 2019-07-08 09:42:28 UTC | https://github.com/discourse/mini_mime | | marcel | mimemagic | 176 | 16 | 2018-12-20 08:49:51 UTC | https://github.com/minad/mimemagic | | railties | rake | 1627 | 164 | 2019-09-09 07:15:18 UTC | https://github.com/ruby/rake | | railties | method_source | 244 | 16 | 2019-02-05 15:25:47 UTC | https://github.com/banister/method_source | | websocket-driver | websocket-extensions | 10 | 4 | 2017-11-11 01:27:15 UTC | https://github.com/faye/websocket-extensions-ruby | +------------------+----------------------+------------------------+-------------------------------+----------------------------------+-----------------------------------------------------+開発者数に着目した集計
開発者数が一桁のgemのうち、本当に開発が止まりそうなgemは0件でした。
こちらも基本的には0件です。minitestのみ、開発者が2人しかいなくてピンチに見えますが、GitHubのリポジトリを見る限りプルリクを自分で書き直してコミットしているだけのようです。プルリク作成者まで含めた貢献者は数多くいます。
ただ一方で、この2人のうち主なコミッターは実質1人のようなので、この人物に何かあると、minitestの開発は止まってしまうかもしれません。(何もないことを祈ります)
最終候補に残ったgemは下記の通りです。
+------------------+----------------------+------------------------+-------------------------------+----------------------------------+---------------------------------------------------+ | Project Name | Dependency Name | Repository Stars Count | Repository Contributors Count | Repository Last pushed Timestamp | left(b.`Repository URL`, 100) | +------------------+----------------------+------------------------+-------------------------------+----------------------------------+---------------------------------------------------+ | actionview | erubi | 238 | 9 | 2019-09-25 16:09:05 UTC | https://github.com/jeremyevans/erubi | | activestorage | marcel | 56 | 6 | 2018-09-15 03:06:56 UTC | https://github.com/basecamp/marcel | | activesupport | minitest | 2703 | 2 | 2020-01-12 00:16:05 UTC | https://github.com/seattlerb/minitest | | concurrent-ruby | ref | 60 | 6 | 2017-11-18 10:41:28 UTC | https://github.com/ruby-concurrency/ref | | websocket-driver | websocket-extensions | 10 | 4 | 2017-11-11 01:27:15 UTC | https://github.com/faye/websocket-extensions-ruby | +------------------+----------------------+------------------------+-------------------------------+----------------------------------+---------------------------------------------------+結論
重要なgemのうち、既に開発が止まったものは0件、開発が止まりそうなgemはminitest gemという結果でした。
補足:minitest gemについては、主なコミッタの人数が少ないだけです。今も活発にコミットされています。今すぐ何かがあるわけではまったくありません。
感想
Railsから二次のつながりまでに含まれるgemが思ったよりもだいぶ少なかったのが印象的でした。過去のバージョンからの変遷を見る限り、Railsを始めとしたたくさんのgemは、開発が進むにつれ出来るだけ依存関係を減らしていこうと努力しているようです。ライブラリとしては非常に健全な姿勢であり、今後もこの傾向が続くと良いなと思います。
- 投稿日:2020-03-23T01:33:47+09:00
PHP サイト でも Capistrano (Ruby Gem)
環境
- Ruby 2.6.5
設定手順
Capistrano 設定ファイルの用意
bundle add capistrano bundle exec cap installこれで必要なファイルが作成されます。
あとは
deploy.rb
,config/deploy/*
を変更して設定完了です。ファイルを置けば使えるPHPサイトなら、認証設定程度を記述すればOKです。
設定ファイル例
staging.rb/production.rb# server configuration role :web, %w{ec2-user@123.123.123.123} # file location set :deploy_to, "/var/www/xxx"deploy.rb# application name set :application, "xxxxxx" # repository set :repo_url, "sample@sample.git.jp:/sample.git" # Default branch is :master ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # revision to be kept set :keep_releases, 2デプロイ手順
# config/deploy/staging.rb を使ったデプロイ bundle exec cap staging deploy # config/deploy/production.rb を使ったデプロイ bundle exec cap production deployロールバック手順
cap deploy:rollbackこのほかにも
cap deploy:rollback:code
などがある。