- 投稿日:2020-09-24T23:44:00+09:00
【Rails】ページの上部に戻るボタン
はじめに
・Railsを使用してアプリケーションを開発
・viewsの下部地点から上部に戻るボタンを設置するRuby 2.5.7
Rails 5.2.4.4流れ
・
gem 'jquery-rails'
を導入
・アクションを起こすボタンを用意(画像でなく文字やfont-awesome等でも代用可能)
・viewにボタンを記載しcss及びjavascriptへ追記ボタン画像
適当に準備します・・・
画像ファイルをapp/assets/images配下に格納
viewsへ追加
<span id="top-btn"> <a href="#"> <%= image_tag asset_path('top_btn.png'), class: 'top-btn' %> </a> </span>・asset_path('~~') は、app/assets/images配下の画像を読み込む
css 及び jsファイルへ追記
.top-btn { position: fixed; right: 30px; bottom: 40px; } .top-btn a { width: 50px; height: 50px; }$(function() { $('#top-btn a').on('click',function(event){ $('body, html').animate({ scrollTop:0 }, 1000); event.preventDefault(); }); });初期状態(ページの上部)では表示したくない場合?
$(function() { var topBtn = $('#top-btn a'); topBtn.hide(); $(window).scroll(function(){ if ($(this).scrollTop() > 100) { topBtn.fadeIn(1000); } else { topBtn.fadeOut(); } }); topBtn.click(function () { $('body, html').animate({ scrollTop:0 }, 1000); event.preventDefault(); }); });fadeIn 及びfadeOut のif文にてボタンの表示を設定しています・・
終わり
上記記載内容で、実装できるはず・・・
不明点及び説明がずれている(誤っている等)ございましたら、コメントにてにてお伝えいただければありがたいです。以上、ご参考になれば幸いです。
- 投稿日:2020-09-24T23:22:37+09:00
Alpine Linuxでrails-erd実行時の文字化け対応
はじめに
個人開発のサービスにて、Alpine Linux上でrails-erdを使ったところ、生成されたPDFが文字化けしてしまいました。
この解決に時間がかかってしまったので、備忘録もかねて現象と解決方法を載せておきます。環境
macOS Catalina Version 10.15.5
Ruby on Rails : 5.2.3
Ruby on Railsのコンテナベースイメージ:ruby:2.6.5-alpine3.9課題
個人開発にて開発中、新しくテーブルの追加が必要になりました。その際、既存のテーブルや各テーブルの関係が大事なので、現状どうなっているのかを調べ始めました。幸いにも、少ないテーブルのみで構成されていたのでコードだけで把握することができました。
ただ、今後テーブルが増えていった時を考えると、ER図を用意し、それだけを見れば構成が分かるようにしておくと、把握する時間が短縮できると考えました。さっそくER図を作る方法を考えましたが、テーブル構成をコードから書き起こしていっては本末転倒です。なるべく手間を掛けずにER図を自動生成してくれるツールを探したところ、rails-erdというgemを見つけました。このrails-erdはActiveRecordのモデルからER図を自動生成してPDFに出力してくれるツールです。
これだ!と思ってgemを入れて、コンテナ上でER図を生成するよう
bundle exec erd
を実行したのですが、出来上がったPDFは全部文字化け(すべて白色の四角文字)となっていました。
なお、ローカルで同じコマンドを実行したところ、文字化けされていないPDFが生成されました。
ただ私としては、ローカルを極力汚さずコンテナ上ですべて行いたかったので、この解決策を探りました。対応
まず、文字化けする場合は出力する文字コードがおかしいのではないかと考えました。そのためrails-erdで出力する文字コードには何を使っているのか調べました。
rails-erdのインストール手順を見たところ、出力用のツールとしてGraphvizを使用しているようです。Rails ERD generates diagrams using Graphviz, a visualisation library.
このGraphvizで扱っている文字コードはUTF-8、iso-8859-1の2つであり、デフォルトはUTF-8となっています。
現在、Graphvizがサポートするエンコーディングは、
- UTF-8
- iso-8859-1 (Latin1)の2つです。
Graphvizで日本語を使う (Graphviz version 2.26.3)
Specifies the character encoding used when interpreting string input as a text label. The default value is "UTF-8". The other legal value is "iso-8859-1" or, equivalently, "Latin1".
Node, Edge and Graph Attributes
UTF-8がデフォルトのため、Graphvizが使う文字コードがおかしい線は消えました。
では次に、そもそものベースイメージの文字コードに問題があるのではと考えました。
rails-erdを使っているコンテナのベースイメージにはAlpine Linuxを使っています。
alpineについて調べたところ、alpineには文字コードがセットされていないようでした。
How I use locales in Alpine
試しにalpineを起動してlocaleにen_US.UTF-8をセットし、rails-erdを実行してみましたが、現象は変わりませんでした。ここまでやってみた結果をTwitterでつぶやいたところ、maitubameさんから記事を紹介して頂きました。
https://t.co/zY8KY469I6
— maitubame (@maitubame) August 31, 2020
この方の記事、未読なら参考になりそうですこの記事には、私が抱えている課題と解決策がそのまま書いてありました。せっかくなのでこの記事に書かれているフォントや実行コマンドが何なのか軽く調べてみました。
フォント
- msttcorefonts-installer: Web用のMicrosoftコアフォントが入っているパッケージ
- fontconfig: フォントに関する情報を提供するライブラリ(Wikipedia参照)
- font-bitstream-type1: X Windows Systemのオープンソースを提供しているX.orgプロジェクトのフォント
- ghostscript-fonts: Ghostscriptで配布されているフォント
- ttf-freefont TrueTypeフォント
実行コマンド
update-ms-fonts
、fc-cache -f
を行うことでフォントの更新が完了するようです。
How to install Microsoft true type font on Alpine Linux?
上記のフォントや実行コマンドを入れたコンテナを作り、
bundle exec rails-erd
を行ったところ、文字化けせずに正常に出力されました。まとめ
コマンド1つでER図を出せるのは嬉しいですね。また、CIのパイプラインに載せて、テーブル更新ごとにドキュメントを出力できるようにしておくのも良さそうです。
ただ、rails-erdの開発があまり活発ではなく、2019年のリリースが最後なので、今後別のライブラリにて出力できるようになるかもしれませんね。
- 投稿日:2020-09-24T22:02:21+09:00
[Rails][jQuery] remote:trueとjs.erbを使って非同期のいいね機能実装
概要
Railsプロジェクトで掲示板サイトを作成中、
remote:true
とjs.erbファイル
を用いた非同期のいいね機能を実装する機会がありました。
備忘録としてここに手順を残しておきます。前提
Rails 5.0
favorites_tableの作成
とモデルのアソシエーションを定義
は既にされているものとします。アソシエーション:
users - has_many :posts, has_many :favorites
posts - belongs_to :user, has_many :favorites
favorites - belongs_to :user, belongs_to :post
jQueryの準備
Rails内でjQueryを使えるように準備します。
まずはgemの導入します。Gemfilegem 'jquery-rails'ターミナルで
bundle install
します。
そしてapplication.js
に記述を追加します。application.js# Rails5.1より前の場合 //= require jquery //= require jquery-ujs # バージョンがRails5.1以降の場合 //= require jquery //= require rails-ujs今回は、Rails 5.0 を使っているので
jquery_ujs
をrequire
してあげてください。
この場合、必ずjqueryを先にrequireするようにしてください。ちなみに
rails-ujs
はRails5.1
よりデフォルトで搭載されているので、application.jsにてrequireしてあげるだけで大丈夫です。ルーティングの設定
createアクションをpostメソッド、destroyアクションをdeleteメソッドを使ってルーティングを記述します。
オプションでas:を記述することでPrefixの名前を指定できます。routes.rbpost '/favorite/:post_id' => 'favorites#create', as: 'like' delete '/favorite/:post_id' => 'favorites#destroy', as: 'unlike'favorites_controllerの作成
いいねのcreateとdestroyを定義します。
app/controllers/favorites_controller.rbclass FavoritesController < ApplicationController before_action :set_post def create @favorite = Favorite.create(user_id: current_user.id, post_id: @post.id) end def destroy @favorite = Favorite.find_by(user_id: current_user.id, post_id: @post.id) @favorite.destroy end private def set_post @post = Post.find(params[:post_id]) end end部分テンプレートでviewを作成
使い回ししやすいように、部分テンプレート化しています。
app/views/users/show.html.erb<%= render 'posts/posts', posts: @posts %>app/views/users/_post.html.erb<% posts.each do |post| %> <div id="favorite-<%= post.id %>"> <%= render partial: "favorites/favorite", locals: { post: post } %> </div> <% end %>jsでイベントを発火させるためには、idまたはclassでセレクタを指定しますが、今回はどのpostに対するいいねなのかを判別するために、id内にそのpostのidを含める必要があります。
上のように書くことによって、id="post-1"のようなidを指定することができます。app/views/favorites/_favorite.html.erb<% if Favorite.find_by(user_id: current_user.id, post_id: post.id) %> <%= link_to "いいね", unlike_path(post.id), method: :delete, remote: true, class: "btn btn-default" %> <% else %> <%= link_to "いいね", like_path(post.id), method: :post, remote: true, class: "btn btn-success" %> <% end %> <%= post.favorites.length %>いいねボタンのlink_toにremote: trueを追加します。
この記述により、通常であれば、link_toで呼ばれるアクションに対応するhtml.erbファイルを呼び出すところ、js.erbファイルを呼び出せるようになります。
なのでページ遷移を行わず非同期で通信が行われるようになります。
最後にいいね数を<%= post.favorites.length %>
で表示しています。js.erbファイル作成
まずはcreateとdestroyそれぞれのアクションに対応するjs.erbファイルを作成します。
app/views/favorites/create.js.erb
app/views/favorites/destroy.js.erb
app/views/favorites/create.js.erb$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");app/views/favorites/destroy.js.erb$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");まずはセレクタの指定ですが、
id="favorite-<%= post.id %>
に対応するように指定します。
そして、jQueryのhtml()メソッドで、指定したセレクタのhtmlを置き換えます。置き換える内容が
"<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>"
の部分で、部分テンプレートの_favorite.html.erb
を呼び出しています。
(renderの前にあるjは、escape_javascriptのエイリアスで、改行と括弧をエスケープしてくれるメソッドです。)これで非同期のいいね機能実装完了です!
最後に
ここまで読んでいただきありがとうございます。
間違っている点などがありましたらご指摘いただきますよう、よろしくお願いいたします。
- 投稿日:2020-09-24T20:41:03+09:00
【Docker】function not implemented @ io_fread ~ というエラーの解決方法【超簡単】
まずは解決策からいいます
Dockerデスクトップアプリを再起動するだけ!!
これだけでした、、今までの時間はなんだったんだろう、、
Docker for Windowなら右下のクジラのアイコンを右クリックしてRestartを押せばOKです!(画像参照↓)エラーの経緯
githubからcloneしたRailsアプリを動かすために新たしくDocker環境を構築して色々いじっていたら、なぜか他のプロジェクトで正常に動いていたDockerコンテナがいきなり起動しなくなったという感じです。
【環境】
- windows10 Pro
- Rails: 6.0.3.2
- ruby: 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
- Docker for windows
- MySQL 5.7
- nginx:1.15.8エラー内容
・・・(省略) Function not implemented @ io_fread (ディレクトリやファイル名)見たことないエラーで焦りました。仮想環境であるDockerコンテナが他のコンテナに影響を与えることなんてあるわけない、、なぜだ、、と思い、Dockerfileをあれこれいじってしまったのが地獄の始まりでした。
原因の切り分けがまったくできていませんでしたね。最後まで見ていただきありがとうございました。
エラー解決に少しでも役に立てば幸いです!!
- 投稿日:2020-09-24T18:47:05+09:00
【Rails】ドット(.)とか、コロン(:)とは一体
::
とか、.
とかよくお見かけします。
これはメソッドの呼び出しの違いで、表記が変わるという種明かしなんです。ドット記法
class User def method puts "Hello" end end> user = User.new > user.method Hello => nilコロン記法
class User def method puts "Welcome" end end> user = User.new > user::method Welcome => nilドット記法とコロン記法の違い
ドット記法とコロン記法の違いは、
定数を呼び出せる
かどうか。
記法 メソッドの呼び出し 定数の呼び出し ドット記法 ○ × コロン記法 ○ ○ Rubyでは、クラスやモジュールも定数として扱われる。
require 'uri' require 'net/http' url = URI.parse("http://yahoo.co.jp") http = Net::HTTP.start(url.host, url.port)> document = http.get(url.path) > puts document.body # ドキュメントを表示まとめ
このようにコロン記法だと、指定した別ファイルのクラス内やモジュール内のアイテムにアクセスすることができる。
- 投稿日:2020-09-24T18:40:31+09:00
Rails6のマルチDBの自動切換(ActiveRecord::Middleware::DatabaseSelector)の実装を読んでみる
概要
Rails6.0より実装された複数DB対応に関して、自身のプロジェクトに適用できるか?という判断のために実装を追ってみますRailsガイドでの記載
https://railsguides.jp/active_record_multiple_databases.html#コネクションの自動切り替えを有効にする
自動切り替え機能によって、アプリケーションはHTTP verbや直近の書き込みの有無に応じてprimaryからreplica、またはreplicaからprimaryへと切り替えます。
アプリケーションがPOST、PUT、DELETE、PATCHのいずれかのリクエストを受け取ると、自動的にprimaryに書き込みます。書き込み後に指定の時間が経過するまでは、アプリケーションはprimaryから読み出します。アプリケーションがGETリクエストやHEADリクエストを受け取ると、直近の書き込みがなければreplicaから読み出します。HTTPメソッドによる判定 + 書き込みからの時間による判定 の2種類にて行われているという記載になっている
設定方法としては下記の記載config.active_record.database_selector = { delay: 2.seconds } config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Sessionコードリーディング
まずはミドルウェアの適用部分から追ってみる
Railtieでのミドルウェアの適用部分
activerecord-6.0.3.2/lib/active_record/railtie.rb
class Railtie < Rails::Railtie # :nodoc: config.active_record = ActiveSupport::OrderedOptions.new initializer "active_record.database_selector" do if options = config.active_record.delete(:database_selector) resolver = config.active_record.delete(:database_resolver) operations = config.active_record.delete(:database_resolver_context) config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options end end
database_selector
が設定されていれば実行されるdatabase_resolver
とdatabase_resolver_context
はただ渡されるようになっている続いてミドルウェア部分の実装を追っていく
[補足] OrderedOptionsとは?
https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html
Hashをドットでアクセスできるようにしている機構
deleteで設定されていない場合はnilが返るRuby2.6.5 pry(main)> x = ActiveSupport::OrderedOptions.new => {} Ruby2.6.5 pry(main)> x.delete(:hoge) => nilDatabaseSelectorの実装内容
activerecord-6.0.3.2/lib/active_record/middleware/database_selector.rb
module ActiveRecord module Middleware class DatabaseSelector def initialize(app, resolver_klass = nil, context_klass = nil, options = {}) @app = app @resolver_klass = resolver_klass || Resolver @context_klass = context_klass || Resolver::Session @options = options end attr_reader :resolver_klass, :context_klass, :options def call(env) request = ActionDispatch::Request.new(env) select_database(request) do @app.call(env) end end
database_resolver
が設定されていない場合はDatabaseSelector::Resolver
が設定されるdatabase_resolver_context
が設定されていない場合はDatabaseSelector::Resolver::Session
が設定される続いて重要そうな
#select_database
を見てみるDatabaseSelector#select_database
module ActiveRecord module Middleware class DatabaseSelector private def select_database(request, &blk) context = context_klass.call(request) resolver = resolver_klass.call(context, options) if reading_request?(request) resolver.read(&blk) else resolver.write(&blk) end end def reading_request?(request) request.get? || request.head? end end end end
context
が先に実行され、それをもとにresolver
が作られているため、まずはcontext
のほうを確認してみるResolver::Session.call
class Resolver # :nodoc: class Session # :nodoc: def self.call(request) new(request.session) end def initialize(session) @session = session end attr_reader :session
.call
は#new
しているだけで、ここではActionDispatch::Request
のsessionをセットしているのみ
なので続いてはResolverの.call
を確認Resolver.call
class Resolver # :nodoc: SEND_TO_REPLICA_DELAY = 2.seconds def self.call(context, options = {}) new(context, options) end def initialize(context, options = {}) @context = context @options = options @delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY @instrumenter = ActiveSupport::Notifications.instrumenter end attr_reader :context, :delay, :instrumenterここでもnewしているだけなので、元の
DatabaseSelector#select_database
をもう少し読み進めていく
※ちなみにinstrumenterは通知の仕組み(購読すれば通知を受け取れる)HTTPメソッドの判断部分
def select_database(request, &blk) context = context_klass.call(request) resolver = resolver_klass.call(context, options) if reading_request?(request) resolver.read(&blk) else resolver.write(&blk) end end def reading_request?(request) request.get? || request.head? endここではGETかHEADの場合 => read
それ以外の場合 => write
としてresolverの処理を実行している(Resolverがさらに判定を行っているっぽいまずはreadから見てみる
Resolver#read
class Resolver # :nodoc: def read(&blk) if read_from_primary? read_from_primary(&blk) else read_from_replica(&blk) end end private def read_from_primary(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do instrumenter.instrument("database_selector.active_record.read_from_primary") do yield end end end def read_from_replica(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role, prevent_writes: true) do instrumenter.instrument("database_selector.active_record.read_from_replica") do yield end end endroleをどちらにするかとinstrumentにより通知を行ったうえで処理を進めているよう。
では続いて#read_from_primary?
にて何をどう判定しているのか?private def read_from_primary? !time_since_last_write_ok? end def send_to_replica_delay delay end def time_since_last_write_ok? Time.now - context.last_write_timestamp >= send_to_replica_delay end
context
いわゆるsessionの#last_write_timestamp
というものが、
最初のconfig.active_record.database_selector = { delay: 2.seconds }
のdelay分だけ経過していなかった場合はprimaryにして、
delay分経過している場合はreplicaを見るようになっているということでsessionの
#last_write_timestamp
を確認class Session # :nodoc: # Converts milliseconds since epoch timestamp into a time object. def self.convert_timestamp_to_time(timestamp) timestamp ? Time.at(timestamp / 1000, (timestamp % 1000) * 1000) : Time.at(0) end def last_write_timestamp self.class.convert_timestamp_to_time(session[:last_write]) endただ
sesion[:last_write]
をtimeオブジェクトに直しているのみ
readはこれで終わりなので続いてwriteResolver#write
class Resolver # :nodoc: def write(&blk) write_to_primary(&blk) end private def write_to_primary(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do instrumenter.instrument("database_selector.active_record.wrote_to_primary") do yield ensure context.update_last_write_timestamp end end endこれはただただ書き込みのroleにて書き込んでいるのみ
class Session # :nodoc: def self.convert_time_to_timestamp(time) time.to_i * 1000 + time.usec / 1000 end def update_last_write_timestamp session[:last_write] = self.class.convert_time_to_timestamp(Time.now) endそして、
session[:last_write]
に現在のタイムスタンプを付与まとめ
さすがRailsですね。とても分かりやすく作られていました。
結局はActionDispatch::Requestをもとに処理されているだけで、かつResolverの
#read
と#write
を両方書き換えれば
GETとHEADに限らず好きに書くことができそうでした。ヘッダーやIPアドレス、localhostなどによる判定も、Requestが持っている情報なので使えますし
できることはかなり多いと思いました。
- 投稿日:2020-09-24T18:24:49+09:00
ECサイトにおけるジャンル検索(customer側)
1. 前提条件
app/models/genrehas_many :itemsapp/models/itembelongs_to :genregenreとitemは1対多の関係となっています。
2.genreコントローラ,view, route.rbの作成
以下のコードでジャンルのコントローラとshowページを作ります。
$ rails g controller Genres show
以下のコードをroute.rbに記載します。
config/route.rbresources :genres, only: [:show]以下のコードをgenre_controllerに記載します
app/controllers/genre_controller.rbdef show @genres = Genre.all @genre = Genre.find(params[:id]) end3.showページにgenreに基づいたitem一覧を表示させる
showページに以下のコードを記載
app/views/genre/show<div class="item-index-box"> <!-- ジャンル選択のサイドバー --> <%= render "items/genres_sidebar", genres: @genres %> <!-- ジャンル選択のサイドバー --> <div class="item-index"> <h3>商品一覧</h3> <table> <tbody> <tr class="item-box"> <% @genre.items.each do |item| %> <td class="item"> <%= link_to item_path(item) do %> <%= attachment_image_tag(item, :image, :fill, 300, 300, fallback:"top.image.jpg") %><br> <%= item.name %><br> ¥<%= item.price %> <% end %> </td> <% end %> </tr> </tbody> </table> </div> </div>@genre.itemsとすることでgenreに基づいたitem一覧を表示させることができる。
5. 今回の実装で学んだこと
当初itemsコントローラ内にgenreアクションを追加し、ルートもresources:items内にしていたのだがそうするとルートがitemsのidを取ってしまう為、新たにコントローラとルートを付け加えた。
- 投稿日:2020-09-24T15:48:26+09:00
未経験者が自社開発企業に就職するためのREADME書き方
はじめに
こんにちは!
先月、無事にエンジニアデビューした1年目の者です。
私は某プログラミングスクールに3ヶ月間お世話になり、卒業後、3週間で自社開発企業に転職することができました。
この経験を生かして、私が意識してきたことを伝えていければと思います。まず、前提として転職では見せ方が最も重要だと考えています。
例えば、職務経歴書、面接対策、wantedlyのプロフィールなどなど、、
この記事では、その中でも重要なことの一つである、ポートフォリオの見せ方について共有します。記事の対象者
・未経験からエンジニア転職を考えていて、ポートフォリオを作成している方
・ポートフォリオのREADMEにて書く内容で迷っている方ポートフォリオの見せ方とは
エンジニアの方々は、忙しいので、書類選考の段階で、ソースを細かく見たりサイトを触って見たりしてくれるとは限りません。
ここで活躍するのが、READMEです。
私は、多くの転職成功された方々のREADMEを見て、自分なりの最適解を見つけました。
共通点は、端的でわかりやすく、視覚的に訴えていることでした。
この共通点からREADMEを使ってわかりやすく、視覚的に伝えられるようにすることが大事だと思います。
この記事では内容についてフォーカスしているので、書き方については他の方の記事を参考にしてください。READMEの構成
⬇️私の転職活動時に使用していたREADMEを元に説明していきます。
https://github.com/sora-uzu/The-View/blob/master/README.md書くことは、主に4つです。
1, タイトルと概要、URL
2, 使用技術
3, AWS(インフラ)構成図
4, 機能、非機能一覧1, タイトルと概要、URL
まずは、タイトル、URLはそのままの意味なので、概要について説明します。
概要は、以下の3点を一言で書いてください。
・どういうサイトか
・何ができるのか
・アピールポイントこれがかけたら、あとはサイトの分かりやすい画像を載せます。
載せ方は、癖があるので、
github readme 画像
などでググってください。2, 使用技術
ここには、使用言語や、インフラ周りで使用しているサービスを書きます。
バージョンも書いていると良いです。3, AWS(インフラ)構成図
インフラ周りで力を入れている方や、AWSを使っている方は、draw.ioを使ってインフラ構成図を作成してください。
各サービスの画像は、ググると公式サイトなどから転載可能な画像が取得できます。
インフラ周りでアピールポイントがあればここに記載すると良いと思います。
私の場合は、CircleCIでやっていることを書いています。
4, 機能、非機能一覧
機能と使用したgemを記載します。細かく書くというよりは、主な機能とそれに付随した機能を簡単に書いてください。
次に、非機能一覧では、なにでテストをしたか、何のテストをどのファイルで行っているかを書いてください。
最後に
以上が私が転職活動時にReadmeにおいて意識していたポイントです。私自身も多くの方のポートフォリオを参考にこういった構成になったので、皆さんも一つの参考にしていただけると嬉しいです。
ご覧いただきありがとうございました!会社の紹介
私は現在、株式会社ダイアログという物流×ITの会社に勤務しております。
2020年9月現在、エンジニアの募集はしていませんが、他にも様々な職種を募集しているので、Wantedlyのページをご覧ください。
- 投稿日:2020-09-24T15:03:13+09:00
railsのいいね機能の変数エラーについて
前提・実現したいこと
railsを使ってwebアプリケーションを作成中です。
自分がいいねをつけた投稿を全投稿の中からソートして画面に表示したいです。
しかし、postの部分にエラーが出てしまいました。
その実発生している問題・エラーメッセージ
Showing C:/Users/user/dome/app/views/users/likesline.html.erb where line #26 raised: undefined method `id' for nil:NilClass<% post = Post.find_by(id: like.post_id) %> <div class="users-index-item"> <%# ここから=========%> <%= link_to("/posts/#{post.id}") do %> <%# ここまで=========%> <div class="user-left"> <img src="<%= "/post_images/#{post.image_name}" %>"> </div>該当コード
likesline.html.erb
<div class="users-contents"> <div class="users-index-item-sorce"> <% @like.each do |like| %> <% post = Post.find_by(id: like.post_id) %> <div class="users-index-item"> <%= link_to("/posts/#{post.id}") do %> <div class="user-left"> <img src="<%= "/post_images/#{post.image_name}" %>"> </div> <div class="post-right"> <div class="post-right-link"> <%= post.title %> </div> </div> <%end%> </div> <% end %> </div> </div>users_controller.erb
def likesline @user = User.find_by(id: params[:id]) @like = Like.where(user_id: @user.id) endDB(SQLite)
users
id name email created_at updated_at image_name password
10 たんぽぽ tanpopo@gmail.com 2020-09-03 2020-09-14 10.jpg tanpopo
12 kosumosu kosumosu@gmail.com 2020-09-19 2020-09-19 12.jpg kosumosuposts
id content created_at updated_at user_id image_name title
46 contents1 2020-09-19 2020-09-19 10 46.jpg title1
47 dfsdfsdf 2020-09-19 2020-09-19 10 47.jpg dflikes
id user_id post_id created_at updated_at
1 10 26 2020-09-04 03:57:42.503803 2020-09-04 03:57:42.503803
3 10 31 2020-09-18 12:28:35.206818 2020-09-18 12:28:35.206818
5 10 32 2020-09-19 02:27:20.465790 2020-09-19 02:27:20.465790
7 10 36 2020-09-19 06:27:53.983748 2020-09-19 06:27:53.983748
9 10 47 2020-09-19 10:50:58.208238 2020-09-19 10:50:58.208238
10 10 46 2020-09-20 07:30:15.554143 2020-09-20 07:30:15.554143問題点
posts.idとlikes.post_idの間に共通して存在しないカラムが存在していること。
よって、likesテーブルの中からid: 1,3,5,7をコンソールを使ってdestroyを行いました。likes
**id** **user_id** **post_id** **created_at** **updated_at** 9 10 47 2020-09-19 10:50:58.208238 2020-09-19 10:50:58.208238 10 10 46 2020-09-20 07:30:15.554143 2020-09-20 07:30:15.554143すると、エラーが解消され無事にお気にいり登録されている投稿が表示できるようになりました。
回答してくれた方:tky_7201さん(teratailのurl:https://teratail.com/users/tky_7201#reply)
- 投稿日:2020-09-24T14:38:32+09:00
Catalinaにアップグレード後のbundle installでエラー
エラー内容
$ bundle install Gem::Ext::BuildError: ERROR: Failed to build gem native extension. (省略) An error occurred while installing ffi (1.13.0), and Bundler cannot continue. Make sure that `gem install ffi -v '1.13.0'` succeeds before bundling. In Gemfile: guard-rspec was resolved to 4.7.3, which depends on guard was resolved to 2.16.2, which depends on listen was resolved to 3.2.1, which depends on rb-inotify was resolved to 0.10.1, which depends on ffi試したこと
$ gem install ffi -v '1.13.0' Building native extensions. This could take a while... ERROR: Error installing ffi: ERROR: Failed to build gem native extension. ...エラーの通りにコマンドを実行するもエラー
$ xcode-select --install xcode-select: error: command line tools are already installed, use "Software Update" to install updates既にinstallされていた。
解決策
$ sudo xcodebuild -license acceptを実行したところ解決。
- 投稿日:2020-09-24T14:26:48+09:00
(Ruby on Rails6) 投稿内容を編集する機能を作る
まえがき
こちらでは、投稿ページ制作後を前提に"投稿内容を編集"の作業を忘却録として残します。
投稿内容を編集する機能を作る
編集ページの作成
routes・controllers・view の3点に、編集ページを新規作成してください
また、ページ作成には・コントローラー名→ form
・アクション名→ Editで設定してます。
(例)
config/routesRails.application.routes.draw do get '/' => 'form#index' get '/form' => 'form#form' post "form/create" => "form#create" get "form/:id/edit" => "form#edit" ⇦これ get "form/:id" => "form#post" # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html endapp/views/任意.html.erb<h1>編集ページ</h1>app/controllers/任意.controller.rbclass FormController < ApplicationController def index @forms = Form.all @forms = Form.all.order(created_at: :desc) end def post @forms = Form.find_by(id: params[:id]) end def form @forms = Form.find_by(id: params[:id]) end def create @forms = Form.new(content: params[:content]) @forms.save @forms = Form.new(title: params[:title]) @forms.save redirect_to("/") end def edit ←ここから end ←ここまで endroutesのpostは、フォームデータの取得を行う時に使います。
新規ページ作成ではgetで設定してください。エラーの原因になってしまいます。編集ページでの初期値設定(textarea・input)
controllers
app/views/任意.html.erb・ ・ ・ def edit @forms = Form.find_by(id: params[:id]) ←ここ endeditアクションに @forms = Form.find_by(id: params[:id]) を設定して、URLと同じidのデータを取得させます。
views
app/views/任意.html.erb<h1>編集ページ</h1> <div class="form"> <div> <textarea><%= @forms.content %></textarea> ←ここ <input type="submit" value="保存"> </div> </div><%= @forms.content %> により、入力の初期値を設定しています。
編集内容の保存
コントローラーにアクションの追加
フォームから値を受け取るので、routesでは get ではなく post で実行してください。
config/routes.rbpost "form/:id/new" => "form#new"リダイレクトの設定
アクションにフォームから値を受け取る準備をしたら、submitを押した後にリダイレクトさせる必要があります。
app/views/任意.controllers.rbdef new redirect_to("/") endredirect_to("/") を利用してリダイレクト設定を行います。 / は私が任意で設定しているので個人でアレンジしてください。
Viewsで送信先の指定する
先により フォームからの値の取得・リダイレクト を行いました。
ここでは、Viewsで送信先を指定します。app/views/任意.controllers.erb<h1>編集ページ</h1> <%= form_tag("/posts/#{@post.id}/new") do %> ←ここ <div class="form"> <div> <textarea><%= @forms.title %></textarea> <textarea><%= @forms.content %></textarea> <input type="submit" value="保存"> </div> </div> <% end %> ←ここ↓ 詳細
app/views/任意.html.erb<%= form_tag("/posts/#{@post.id}/new") do %> フォームタグ <% end %>↑により、送信先が指定されます。
投稿内容の更新を行う
データーベースからデータを取得する必要があります。
取得アクションは、アクション・name属性の追加で行えるので、実行しましょう。Viewでname属性を指定する
app/views/任意.html.erb<h1>編集ページ</h1> <%= form_tag("/posts/#{@post.id}/new") do %> <div class="form"> <div> <textarea name="content"><%= @forms.content %></textarea> ←ここ <input type="submit" value="保存"> </div> </div> <% end %>コントローラーで params と save で指定
params では、送られてきたデータを保持するオブジェクトを作成できます。
app/controllers/任意.controller.rbdef update @forms = Form.find_by(id: params[:id]) @forms.content = params[:content] @forms.save redirect_to("/") endあとがき
ここまで読んでいただき、ありがとうございました。
初期値の設定などの処理が理解できるまで、少し時間がかかりそうですが地道に理解を深めたいと思います。
また、ここの紹介だけでは"投稿ページへのリンク"など詳細を省いてしまってるので、自作されるかたは設定することをおすすめします。参考リンク
Myリンク
また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。
- 投稿日:2020-09-24T11:38:15+09:00
コントローラーのアクションについて
Railsで使用するアクションとは何か?
コントローラーで定義されるメソッドを『アクション』と言います。(コメントからご指摘を受け認識誤りでしたので文章を改善いたします。↓の意味合いで間違いないと思います。)
コントローラーで定義されるメソッドを指してアクションと呼びます。
これを理解するになるには、MVCについて理解しないといけないです。それを理解した上で、情報を持ったルーティングからコントロラーに情報が送られ、ビューで様相を整え表示させる。この流れの、ルーティングから情報を持った内容にアクションを組み合わせることで、その情報で何を行いたいかの指針を決める役割になるのです。(そう言う認識でいます)
主として使用するアクションとして7つありますのでそれらを調べていきます。7つのアクションについて
それぞれの役割を要約したものは以下のとおりです。
index(HTTPメソッド = get )
リソースの一覧表をするものです。要は、あるホームページを検索して、検索結果のurlをクリックして、そのホームページの一覧が表示される状態(処理)を指します。
new(HTTPメソッド = get )
リソースを新規作成するものです。要は、ユーザー等の情報をデータベースに登録する際に行う処理を指します。
create(HTTPメソッド = post )
リソースを新規作成して追加(保存)するものです。要は、ユーザー等の情報をデータベースに保存する際に行う処理を指します。
edit(HTTPメソッド = get )
リソースを更新するためのフォームを作成するものです。要は、データベースに保存している情報に編集を加える処理を指します。
show(HTTPメソッド = get)
レコードの内容を表示させるものです。要は、一覧表示されている情報から、ある特定の箇所に遷移する際の処理を指します。例)詳細ページに遷移する
update(HTTPメソッド = patch/put)
リソースを更新するものです。要は、編集した内容を、データベースに反映させる処理を指します。
destroy(HTTPメソッド = delete)
リソースを削除するものです。要は、データベースに保存されている情報を消去する処理を指します。
※リソースについて、プログラムを利用するデータ全般のことを指します。要は、パソコンで使用する情報的なことだと言う認識です。
※HTTPメソッドに関しては、こちらで記述してます。ややこしい違いを調べました
上記でのアクションに、「あれ、同じことを言ってね」と思った箇所がいくつかあったかと思います。なので、それを砕いていきます。
newとcreateって何が違う?
簡単にいきますよ、newはオブジェクトを生成するだけでデータベースに保存されないものです。createは、オブジェクトを生成して、データベースに保存するものです。アプリケーションを作成する際は、臨機応変に使用するといったものだと考えてます。
saveについて
調べていくと、saveメソッドというものがありました。このメソッドは、newの中で使うもので、保存すると言った意味を持ったメソッドです。で、ここで疑問に思うものが、createと何が違うのか?ということです。違いとしては、newでオブジェクトを生成してからsaveを行えるので、その中で行いたい処理等があるのであれば、それをやってから保存すると言った流れができます。(多分こんな感じ、違ったらご指摘ください?)
editとupdateの違いについて
newとcreateとの違いについてと同じで、editはオブジェクトを生成するだけでデータベースに保存されません。updateはオブジェクトを生成して、保存を行うものです。
まとめ
Railsを使用する際には、必要な知識なので覚えるようにしたいと思います。
- 投稿日:2020-09-24T11:21:32+09:00
Ruby on Rails チュートリアル 第一章
はじめに
自分がRailsを勉強するときに、簡単にまとめたやつがあったらいいのにと思ったので学習しながら編集しました。
自分の勉強用です。
AWSでのCloud9の設定はとばします。1.2.2 Railsをインストールする
ターミナル$ echo "gem: --no-document" >> ~/.gemrcRubyドキュメントをインストールしないよう.gemrcファイルを設定する
.gemrcって言うのはgemの設定ファイル
設定は「gemのインストールやアップデートの際にドキュメントファイル生成しない」的な感じ
ドキュメントとは、説明書のこと。
Gemを使うに当たって絶対必要ではなく、サイズも大きくなるし時間もかかるからスルーしますというやつ。
ターミナル$ gem install rails -v 6.0.3 $ rails -v $ ruby -vRailsのインストールとバージョン確認をする。
ターミナル$ source <(curl -sL https://cdn.learnenough.com/yarn_install)JavaScriptの依存関係を管理するYarnというプログラムをインストールする。
1.3 最初のアプリケーション
ターミナル$ cd ~/environment $ rails _6.0.3_ new hello_apprais newを実行する(バージョン番号を指定)
並び順は rails バージョン指定 new アプリ名
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3' gem 'puma', '4.3.4' gem 'sass-rails', '5.1.0' gem 'webpacker', '4.0.7' gem 'turbolinks', '5.2.0' gem 'jbuilder', '2.9.1' gem 'bootsnap', '1.4.5', require: false group :development, :test do gem 'sqlite3', '1.4.1' gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '4.0.1' gem 'listen', '3.1.5' gem 'spring', '2.1.0' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'capybara', '3.28.0' gem 'selenium-webdriver', '3.142.4' gem 'webdrivers', '4.1.2' end # Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]Gemfileを書き換える。
ターミナル$ cd hello_app/ $ bundle installgemをインストールする。
ここでエラーが出てしまったのでbundle uddateする。ターミナル$ bundle uddate再度bundle installする。
ターミナル$ bundle install1.3.2 rails server
config/environments/development.rbRails.application.configure do . . . # Cloud9 への接続を許可する config.hosts.clear endWebサーバーへの接続を許可が必要らしいので、config/environments/development.rbを開いて2行足す。
ターミナル$ cd ~/environment/hello_app/ $ rails server実行したままにしたいので、もう1つターミナルを開いてRailsサーバーを実行する。
ブラウザを開いて、ヾ(´∀`)ノYay! You’re on Rails!ヾ(´∀`)ノわーい みたいのが出たらOK。1.3.4 Hello, world!
ここからMVCモデルに入る。
ターミナル#app/controllers/の中にある〇〇controller.rbと言うファイルは? $ ls app/controllers/*_controller.rb #結果 app/controllers/application_controller.rbファイルを調べる。まずは第一章ではまずコントローラから。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base #helloアクション def hello render html: "hello, world!" #HTMLで表示したい:"表示したい内容" end end3行追加する。これでこの後のルーティングを設定すると"hello, world!"が表示できるようになるらしい
config/routes.rbRails.application.routes.draw do root 'application#hello' end#root(一番上、/)では'application_controller'のhelloアクション'を実行するという意味。
'application_controller'のhelloアクション'というのは1個前に設定したやつ。ここでエラーが出てしまった。エラーの内容は読み込み中がすごい長いというもの。
Rails sを再起動しようと思ってRails sを実行しているターミナルを見ると、終了できなくなってしまっていた。ターミナル$ ps aux | grep [p]uma $ kill -9 <出てきたプロセス番号>これでもう一度Rails sを再起動できた。
ブラウザに、Hello,world!と表示されればOK。1.4 Gitによるバージョン管理
ターミナル$ git config user.name #登録されていればここに表示される $ git config user.email #登録されていればここに表示される #登録されていなければ下記コマンドで登録 $ git config --global user.name "Your Name" $ git config --global user.email your.email@example.comgit configで設定。
ターミナル$ sudo ln -sf `which nano` /usr/bin $ git config --global alias.co checkoutGitで使うデフォルトのエディタを設定。
git coをcheckoutのエイリアスに設定。これから'git checkout' を'git co'と省略できる。
ターミナル$ cd hello_app #アプリのルートディレクトリに移動する $ git init #リポジトリの初期化 $git add -A #すべての更新ファイルをステージに移動 $git status #ステージングの状況を確認 #現状ではすべての更新ファイルがステージングされて緑で表示 $git commit -m "Initialize repository" #メッセージを追加するcommitのコマンド メッセージ→"リポジトリを初期化" $ git log #ログ表示 「q」で終了git initでセットアップする。
1.5.1 Herokuのセットアップ
gemfileを書き換える。
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3' gem 'puma', '4.3.4' gem 'sass-rails', '5.1.0' gem 'webpacker', '4.0.7' gem 'turbolinks', '5.2.0' gem 'jbuilder', '2.9.1' gem 'bootsnap', '1.4.5', require: false group :development, :test do gem 'sqlite3', '1.4.1' gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '4.0.1' gem 'listen', '3.1.5' gem 'spring', '2.1.0' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'capybara', '3.28.0' gem 'selenium-webdriver', '3.142.4' gem 'webdrivers', '4.1.2' end group :production do gem 'pg', '1.1.4' end # Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]Herokuではsqlite3は使えない。PortgreSQLを使う。
本番(production)環境にpg gemをインストールしてRailsがPostgreSQLと通信できるようにする。
sqlite3 gemが本番環境に導入されないようにしておく。ターミナルbundle install --without production本番用以外のgemをインストールする。
ターミナル$ heroku --versionHerokuがインストールされているか確認する。されていなかった。
ターミナル$ source <(curl -sL https://cdn.learnenough.com/heroku_install)Herokuをインストールする。
ターミナル$ heroku --version確認。OK。
ターミナル$ heroku login --interactiveherokuにログインする。 --interactiveはブラウザを開かないようにするやつ。
ターミナル$ heroku createHerokuに新しいアプリケーションを作成する。
ターミナル$ git push heroku masterHerokuにリポジトリをPUSHする。
heroku createの時に出てきたURLを開くとデプロイ完了が確認できる。ターミナル$ rails webpacker:installwebpackerがないと怒られたとき。
- 投稿日:2020-09-24T11:01:46+09:00
小数点以下を切り捨てたい
【概要】
1.結論
2.どのように使うのか
3.ここから学んだこと
1.結論
floorメソッドを使う!
2.どのように使うのか
def cal_points(point) if point < 6000 cal_point = points * 0.05 else cal_point = points * 0.1 end puts "ポイントは#{cal_point.floor}点です" end上記ではif条件式の中で小数点が入った計算を#{cal_point.floor}を小数点以下を切り捨てています。
式展開にfloorメソッドを適用しています。参考URL:
Rubyで数値の切り捨て・切り上げ・四捨五入する
3.ここから学んだこと
他にもroundメソッド(四捨五入),ceilメソッド(切り上げ)があります。また、.round(1)とすることで"小数点第1位まで四捨五入"や.round(-1)とすることで1の位を四捨五入できます。
ex)1.23.round(1) #1.2 ex)123.round(-1) #120
- 投稿日:2020-09-24T09:47:06+09:00
テーブルにテーブルの一番古いデータを削除していくメソッドを作成して実行するようにしたい
環境
・Ruby 2.6.6, Rails 6.0.3.2
・Docker,Docker-compose(開発環境)困ったこと
Newsテーブルにある一番古いデータを削除していくメソッドを作成して実行したいのだが、添付画像のエラーが表示される。
def destroy_oldest_news news = News.all n = news.last(1) n.destroy end調べたこと・確認したこと
①binding.pryで変数の値を確認。配列でデータが返ってきた。
pry(#<Guide::ToursController>)> n => [#<News:0x00007f8084d6e848 id: 5, created_at: Tue, 25 Aug 2020 16:18:18 JST +09:00, updated_at: Tue, 25 Aug 2020 16:18:18 JST +09:00, tourist_id: 1, guide_id: nil, tour_id: 1348, action: "review">]②配列のデータに対してはdestroyメソッドを使う事ができない事が分かり、配列のデータを消してくれるpopメソッド・delete_at(0)をやってみたが、そもそもデータベースからデータは消してくれない事が分かった。
def destroy_oldest_news news = News.all n = news.last(1) n.delete_at(0) enddef destroy_oldest_news news = News.all n = news.last(1) n.pop end解決方法
def destroy_oldest_news news = News.all n = news.last n.destroy end解説
lastメソッドを個数指定で実行すると数に応じた配列を返ってしまう。
一つのデータを削除する場合はlastのみで使う。反省
これまで個数指定でしか使っていたので、個数指定をしなくても使えることを知らなかった。
メソッドを使うときはそのメソッドについての知識を付けないといけない。
- 投稿日:2020-09-24T09:47:06+09:00
Rails6 テーブルの一番古いデータを削除していくメソッドを作成して実行するようにしたい
環境
・Ruby 2.6.6, Rails 6.0.3.2
・Docker,Docker-compose(開発環境)困ったこと
Newsテーブルにある一番古いデータを削除していくメソッドを作成して実行したいのだが、添付画像のエラーが表示される。
def destroy_oldest_news news = News.all n = news.last(1) n.destroy end調べたこと・確認したこと
①binding.pryで変数の値を確認。配列でデータが返ってきた。
pry(#<Guide::ToursController>)> n => [#<News:0x00007f8084d6e848 id: 5, created_at: Tue, 25 Aug 2020 16:18:18 JST +09:00, updated_at: Tue, 25 Aug 2020 16:18:18 JST +09:00, tourist_id: 1, guide_id: nil, tour_id: 1348, action: "review">]②配列のデータに対してはdestroyメソッドを使う事ができない事が分かり、配列のデータを消してくれるpopメソッド・delete_at(0)をやってみたが、そもそもデータベースからデータは消してくれない事が分かった。
def destroy_oldest_news news = News.all n = news.last(1) n.delete_at(0) enddef destroy_oldest_news news = News.all n = news.last(1) n.pop end解決方法
【参考URL】
https://docs.ruby-lang.org/ja/latest/method/Array/i/last.htmldef destroy_oldest_news news = News.all n = news.last n.destroy end解説
lastメソッドを個数指定で実行すると数に応じた配列を返ってしまう。
一つのデータを削除する場合はlastのみで使う。反省
これまで個数指定でしか使っていたので、個数指定をしなくても使えることを知らなかった。
メソッドを使うときはそのメソッドについての知識を付けないといけない。
- 投稿日:2020-09-24T00:57:13+09:00
【Ruby】セキュアなパスワードポリシー設定のための正規表現
1.はじめに
Webアプリケーション作成の際に特に意識をしないとならない箇所はセキュリティ面です。パスワードに関しては慎重に取り扱わなければいけません。
この記事ではパスワードポリシー設定の際に正規表現を使うことが有用という話を聞きましたので、パスワードと正規表現について考察してみました。2.正規表現とはなにか
初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」によると
「パターンを指定して、文字列を効率よく検索・置換するためのミニ言語」
ということみたいです。
実際にRuby用の正規表現エディタのRubularというWebサイトを使用して、正規表現がどういったものか見ていきます。
例えば下記のようなテキストがあります。8月30日学習時間:1時間 8月31日学習時間:3時間 9月1日学習時間:2時間 9月2日学習時間:4時間 9月3日学習時間:6時間 9月4日学習時間:10時間この中で9月の学習時間の数字だけ正規表現を使って抽出します。
正規表現を使うと下記のような文字列になります。
^9.*:(\d*)時間$
^
や.
や*
などの正規表現で使用する特別な文字を「メタ文字」と呼びます。
ここでのメタ文字の意味は後述するとしてRubularで検証していきます。
Rubularの「Your test string」に検証したいテキストを、「Your regular expression」に正規表現を入力していきます。
そうすると下記のような結果になります。
「Match result」の水色の部分が検索して見つかった部分です。
「Match groups」がキャプチャされた部分です。ここで学習時間を抽出します。
こうやって正規表現を使用して文字列を検索していきます。3.この記事で使用する正規表現のメタ文字
参考にしました→基本的な正規表現一覧
メタ文字 意味 ^ 文頭を表す $ 文末を表す [] いずれか1文字を表す文字クラスを作る - []内で使われる文字の範囲を示す . 任意の1文字を表す ? 直前の文字やパターンが1回、もしくは0回現れる * 直前の文字やパターンが0回以上連続する。条件に合う最長の部分に一致 *? 直前の文字やパターンが0回以上連続する。条件に合う最短の部分に一致 + 直前の文字やパターンが1回以上連続する。条件に合う最長の部分に一致 () 内部でマッチした文字列をキャプチャもしくはグループ化する {n,m} 直前の文字やパターンがn回以上、m回以下連続する \ メタ文字をエスケープしたり、\dや\wといった他のメタ文字の一部になったりする \d 1個の半角数字(0123456789) \w 半角英数字とアンダースコア'_' (?=x) xの「直前の位置」を表す(肯定先読み)
4.どういったパスワードポリシーを設定すればよいのか
コンピュータの性能は日進月歩で向上しているため、パスワードの暗号解読(例えば総当り攻撃)のスピードは年々上がっていっています。それに伴いパスワードの複雑化が求められています。
2020年3月31日発行の内閣サイバーセキュリティーセンター「インターネットの安全・安心ハンドブック Ver.4.10」のP30によると、パスワードの安全性を高めるためのポリシーとして「英大文字+英小文字+数字+記号混じりで10桁以上」を推奨しています。
ここではハンドブックに則ったパスワードポリシーを正規表現にて作成していきます。5.パスワードポリシー設定のための正規表現
ここでは段階的にそれぞれの正規表現を考えていきたいと思います。
(1) 10桁以上40桁以下の半角英数記号
(2) 英大文字1桁以上+英小文字1桁以上の条件追加
(3) 数字1桁以上の条件追加
(4) 記号1桁以上の条件追加すべてのパターンを網羅できているわけではありませんが、上から
・9桁の文字
・10桁の英小文字
・10桁の英大文字+英小文字
・10桁の英大文字+英小文字+数字
・10桁の英大文字+英小文字+数字+記号
・41桁の文字で下記のテキストで検証をしていきます。
Aaaaaaa1? aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa1 Aaaaaaaa1? Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1?(1) 10桁以上40桁以下の半角英数記号
正規表現で使用する文字についてはASCIIコードを使用して指定ができます。ここでの半角英数字記号はASCIIコード表の
!
から~
までですので、下記のようになります。Ruby^[!-~]{10,40}$(2) 英大文字1桁以上+英小文字1桁以上の条件追加
理解するのに時間がかかりましたが、段階を踏んで説明します
a.肯定的先読み
(?= )
を使用して、条件の順序の依存をなくす
b.条件の前の文字は、任意の1文字.
を最短一致で0回以上連続*?
する
c.条件を設定する[A-Z][a-z]
参考にしました→パスワード向け正規表現 /^(?=.?[a-z])(?=.?\d)[a-z\d]{8,100}$/i を解読する
Ruby^(?=.*?[A-Z])(?=.*?[a-z])[!-~]{10,40}$成功しました。
(3) 数字1桁以上の条件追加
(2)に数字0-9の条件
\d
を追加しました。Ruby^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)[!-~]{10,40}$成功しました。
(4) 記号1桁以上の条件追加
ASCIIコードを確認して記号を指定しました。
記号とメタ文字がかぶる箇所については、エスケープ\
をしました。Ruby^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)(?=.*?[!-\/:-@\[-`{-~])[!-~]{10,40}$成功しました。
記号確認用にテキストを追加しました。6.まとめ
正規表現は理解するのに骨が折れる部分がありました。パスワードポリシー設定以外にも色々使わせていただきます。