- 投稿日:2020-09-07T23:54:15+09:00
【Rails】paranoia(gem)を使ってイベント終了機能(論理削除)を実装する
そもそも論理削除とは?
RailsのActiveRecordの削除(delete)は、通常、物理削除になっており、実際にデータがデータベースから削除されます。それに対して、論理削除は実際にはデータを削除せずに、削除されたと見なすフラッグと呼ばれるカラムを設定して、ユーザーには削除しているかのように振る舞い、必要時には元の状態に戻せるものです。「ユーザーが退会した後も、システム上一定期間はユーザーのデータを保持しなければならない。」や「違反等があり、一時的にアカウントを凍結したい」などの場合に、論理削除が使えると思います。
Railsではparanoiaというgemライブラリを利用することで簡単に実装することができます。このgemはacts_as_paranoidというgemを再実装したものです。引用 (https://remonote.jp/rails-gem-paranoia)
分かりやすい記事があったので引用させて戴きました。通常は上述されている様に管理ユーザーが違反等があり、一時的にアカウントを凍結したいなどの場合に使われる機能みたいですが僕の場合はイベントの削除機能と終了機能を分けるために論理削除を実装しました。
どういうことかと申しますと、イベント参加アプリケーションを実装しているときにユーザーが過去に参加したイベントが見れたらいいよね。となりました。イベントが終われば当然、イベントのデータは削除されてイベント一覧では見れない様にするのですが僕が実装したかったのは一覧には表示されないけどユーザーのマイページで参加したイベントが見れるというもの。つまり表面的には削除されていながらレコードの情報は残っているということです。ですが、どの様に実装したらいいのか分かりませんでした。
最初は、イベントを削除したときに違うテーブルにそのイベントの情報を丸々移動出来ないかと模索していましたがなかなか情報が見つからないときに論理削除が簡単に実装できてしまうparanoiaというgemを見つけました。
前置きが長くなりましたが、早速導入~実装までの流れをまとめていきたいと思います。
step1: 導入
gem 'paranoia'例の如く
bundle install
続いて、カラムを追加します。
rails g migration AddDeletedAtToEvents deleted_at:datetime:indexイベントモデルにdeleted_atというカラムを追加します。
class AddDeletedAtToEvents < ActiveRecord::Migration[6.0] def change add_column :studies, :deleted_at, :datetime add_index :studies, :deleted_at end endrails db:migrate最後に、対象モデルに acts_as_paranoid を追記します。
Event.rbclass Event < ApplicationRecord acts_as_paranoid end導入完了!!
step2: ルーティングを設定する
routes.rbRails.application.routes.draw do root "events#index" resources :events do member do delete 'finish' end end endresourcesで生成される七つのアクションの中に終了するアクションは無いのでイベントにネストする形でfinishアクションのルーティングを設定します。
step:3 コントローラーにfinishアクションを定義する
events_controller.rbdef destroy @event = current_user.events.find(params[:id]) @event.really_destroy! redirect_to root_path, notice: "イベントを削除しました" end def finish @event = current_user.events.find(params[:id]) @event.destroy! redirect_to root_path, notice: "イベントを終了しました" end上記のdestroyアクションとfinishアクションの違いは
@event
の後に、本当にレコードから削除したい場合はreally_destroy
と記述しています。
では、finishアクションでは普通にdestroy
と記述していますが実際データーベースにどの様な形で残っているのでしょうか?
destroy
されたレコードは画像の様にdeleted_atというカラムに論理削除された時間が残ります。step:4 論理削除されたデータをfindメソッドで取ってくる
users_controller.rbdef show @user=User.find(params[:id]) @events = @user.events.only_deleted endユーザーの詳細ページで過去のイベントを表示したいのでユーザーコントローラーに
only_deleted
と記述することで論理削除されたレコードだけを取ってくることができます。最後に、、
paranoiaは他にも色々なメソッドが使えるみたいなので是非、公式ドキュメントを参考にしてください^^
公式リンク(https://github.com/rubysherpas/paranoia)最後まで見て頂きありがとうございました^^
- 投稿日:2020-09-07T23:10:36+09:00
windows10,Ruby2.6.6でrails serverコマンドを実行して「cannot load such file -- sqlite3/sqlite3_native」がでた
はじめに
@shuheyさんの記事の通りにやればほぼ解決します.
Ruby2.6.6でやったときにうまくいかなかったのでメモ程度に...環境
windows10 Home
Ruby+Devkit 2.6.6-1 (x64)
Rails 5.1.6直したはずなのにエラーが
Ruby on RailsチュートリアルとRails Girls インストール・レシピ (Windows 用セットアップ(WSLが使えない方向け))の通りに環境構築をして
rails server
コマンドを実行したところ以下のようなエラーが出ました.(@shuheyさんの記事ではRuby26-x64 -> Ruby25-x64
,2.6.0 -> 2.5.0
に変わってます)C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/sqlite3-1.3.13-x64-mingw32/lib/sqlite3.rb:6:in `require': cannot load such file -- sqlite3/sqlite3_native (LoadError)ここで@shuheyさんの記事に倣って
C:\Ruby26-x64\lib\ruby\gems\2.6.0\gems\sqlite3-1.3.13-x64-mingw32\lib\sqlite3
に2.5
ディレクトリを新規作成し,その中にsqlite3_native.so
をコピーしてもう一度rails server
コマンドを実行!これで解決かと思いきやまだ同じエラーが...
解決方法
さっきのエラーメッセージの
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/sqlite3-1.3.13-x64-mingw32/lib/sqlite3.rb
を見てみる.すると3,4行目にsqlite3.rbRUBY_VERSION =~ /(\d+\.\d+)/ require "sqlite3/#{$1}/sqlite3_native"なるほど.
2.5
ディレクトリはRubyのバージョンのことだったのか!(なんで気づけなかった笑)というわけで
2.6
ディレクトリを新規作成し,sqlite3_native.so
をコピーしてrails server
コマンドを実行します.
やっとRailsアプリの起動に成功.=> Booting Puma => Rails 5.1.6 application starting in development => Run `rails server -h` for more startup options *** SIGUSR2 not implemented, signal based restart unavailable! *** SIGUSR1 not implemented, signal based restart unavailable! *** SIGHUP not implemented, signal based logs reopening unavailable! Puma starting in single mode... * Version 3.9.1 (ruby 2.6.6-p146), codename: Private Caller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stopブラウザで
localhost:3000
にアクセスして動作確認
- 投稿日:2020-09-07T22:15:41+09:00
【Ruby on Rails】投稿したユーザーのみが編集できるようにする
目標
- URLのベタ打ちでの他ユーザーの編集を防ぐ
- view画面にそもそも表示させない
開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina前提
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。考え方
基本的には、
①if文でcurrent_userなどで絞るか、
②current_userに紐づくモデルを抽出するかで
投稿したユーザーのみが編集可能。
※viewでは前者を、controllerでは後者で実装。controllerの編集
前提の状態での記述
app/controllers/posts_controller.rbdef edit @post = Post.find(params[:id]) end def update @post = Post.find(params[:id]) if @post.update(post_params) redirect_to new_post_path else render :edit end end def destroy @posts = Post.all @post = Post.find(params[:id]) @post.destroy endこのままではURLをベタ打ちすると編集、削除が可能に。
そこで下記のように記述。app/controllers/posts_controller.rbdef edit @post = Post.find(params[:id]) unless @post.user == current_user redirect_to new_post_path end end def update @post = Post.find(params[:id]) if @post.user != current_user redirect_to new_post_path else if @post.update(post_params) redirect_to new_post_path else render :edit end end end def destroy @posts = Post.all @post = Post.find(params[:id]) if @post.user != current_user redirect_to new_post_path else @post.destroy end end
補足
unless 条件 => 条件がfalseの場合を定義。ただしこれでは記述が多くなり、修正する場合に手間が必要。
そこでbefore_actionを活用。app/controllers/posts_controller.rbbefore_action :ensure_user, only: [:edit, :update, :destroy] ... def edit end def update if @post.update(post_params) redirect_to new_post_path else render :edit end end def destroy @post.destroy redirect_to new_post_path end private def ensure_user @posts = current_user.posts @post = @posts.find_by(id: params[:id]) redirect_to new_post_path unless @post end ...
補足
before_actionを活用することにより、アクションが読み込まれる前に行う動作を指定することができる。
定義はストロングパラメーターで行い、current_userでない場合はreditrct_toを定義。viewsの編集
URLベタ打ち以前にそもそもユーザー誤認を防ぐために画面で表示をしない方が望ましい。
app/views/posts/new.html.erb<% @posts.each do |post| %> <tr> <td><%= post.user.name %></td> <td><%= post.title %></td> <td><%= post.body %></td> <td><%= link_to "詳細", post_path(post) %></td> <td><%= link_to "編集", edit_post_path(post) %></td> <td><%= link_to "削除", post_path(post), method: :delete %></td> </tr> <% end %>この部分を修正。
app/views/posts/new.html.erb<% @posts.each do |post| %> <tr> <td><%= post.user.name %></td> <td><%= post.title %></td> <td><%= post.body %></td> <td><%= link_to "詳細", post_path(post) %></td> <% if post.user == current_user %> <td><%= link_to "編集", edit_post_path(post) %></td> <td><%= link_to "削除", post_path(post), method: :delete %></td> <% else %> <td></td> <td></td> <% end %> </tr> <% end %>結論
controllerとviewを編集することにより、他ユーザーの編集を防ぐことが可能。
- 投稿日:2020-09-07T22:00:51+09:00
git push heroku masterする際のエラー解消方法
【概要】
1.結論
2.どのようなエラーか
3.なぜエラーが起きるのか
4.どのように解決するのか
1.結論
githubの左上メニューでCompare to Blanchを押してmasterにmargeする!
2.どのようなエラーか
ターミナル% git push heroku master To https://git.heroku.com/*****.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://git.heroku.com/*****.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.このようなエラーが出てしまいました。
ローカルレポジトリ(master)からherokuへのmasterにpushしようとした際に拒否されてしまったエラーです。
hintが書いてありますが全く解決できずで、調べてもなかなか解決には至りませんでした。
3.なぜエラーが起きるのか
masterとローカルレポジトリにあるブランチが反映されていない状態になっており食違いがあったことが原因でした。
4.どのように解決するのか
なのでgithubの左上メニューでCompare to Blanchを押してmasterにmargeしたところ、エラーは無事に解決しました。
❶github desktopを開きますとMacですと左上にメニューバーが出てきます。そこで"Branch"を押下します。
❸そしてgithub desktopの画面に戻ってhistoryを見ていきます。
❹”1(1以上になっている)⬇︎”になっていると思うのでそれをmasterに統合します。
写真では0⬇︎になっていますが、エラーが起きていた際は1⬇︎になっていました。その証拠に隣が1⬆︎になっています。
そうすることで再度、ターミナルで” git push heroku master”してあげるとうまく行きました。そこで、いろいろと思い返しました。
Pay.jpでjavascriptに環境変数を記載して、herokuにpushする際にわざとプログラムを変更して読み込ませるようにしました。変更を加えた際に、ブランチを作ったような気がしました。やはり気のせいではなくブランチを作ってありました。
- 投稿日:2020-09-07T21:54:30+09:00
[rails sエラー]md5.bundleとmysqlインストールエラー
目的地
作成済みアプリで問題なくrails s実行
現在
$ rails s 省略) /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': dlopen(/Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError) Referenced from: /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle Reason: image not found - /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle原因
pythonの環境構築したことでopensslのバージョンが変わってしまったこと?
やったこと
- rubyの再インストール
- bundlerのバージョン調整
- mysqlインストール
rubyの再インストール
rubyが参照していたバージョンのOpenSSLがなくなったことにより、エラー発生
どうやら再インストールするしかないらしい$ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]$ rbenv uninstall 2.5.1 $ rbenv install 2.5.1$ruby -v # ruby 2.5.1p0 ←のように表示されればOKbundle installしてみる
$ bundle install Traceback (most recent call last): 2: from /Users/<user名>/.rbenv/versions/2.5.3/bin/bundle:23:in `<main>' 1: from /Users/<user名>/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems.rb:308:in `activate_bin_path' /Users/<user名>/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems.rb:289:in `find_spec_for_exe': can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)
。。。
アプリディレクトリ下のbundleのバージョンとglobalのバージョンが違うらしい
bundlerのバージョン調整
アプリ内のgemfileを確認
gemfile.lockRUBY VERSION ruby 2.5.1p57 BUNDLED WITH 2.0.2現在のバージョン確認
bundler -v Bundler version 2.0.1合わせる
$ gem uninstall bundler -v 2.0.1 $ gem install bundler -v 2.0.2bundle installしてみる
$ bundle install (色々なgemのインストールのログが出てくる) . . . Installing ... Fetching mysql2 0.5.2 Installing mysql2 0.5.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 /Users/fukudatakumi/.rbenv/versions/2.5.1/bin/ruby -I /Users/fukudatakumi/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0 -r ./siteconf20190321-35638-onb5bd.rb extconf.rb --with-opt-lib\=/usr/local/opt/openssl/lib\ --with-opt-include\=-I/usr/local/opt/openssl/include checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/opt/mysql@5.7/bin/mysql_config ----- checking for mysql.h... yes checking for errmsg.h... yes checking for SSL_MODE_DISABLED in mysql.h... yes checking for SSL_MODE_PREFERRED in mysql.h... yes checking for SSL_MODE_REQUIRED in mysql.h... yes checking for SSL_MODE_VERIFY_CA in mysql.h... yes checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes checking for MYSQL.net.vio in mysql.h... yes checking for MYSQL.net.pvio in mysql.h... no checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes checking for my_bool in mysql.h... yes ----- Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/opt/mysql@5.7/lib ----- creating Makefile current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" clean current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" compiling client.c compiling infile.c compiling mysql2_ext.c compiling result.c compiling statement.c linking shared-object mysql2/mysql2.bundle ld: warning: directory not found for option '-L/usr/local/opt/openssl/lib --with-opt-include=-I/usr/local/opt/openssl/include' ld: library not found for -lssl clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2 for inspection. Results logged to /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2/gem_make.out An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.エラー変わったけど、、、
Make sure thatgem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'
succeeds before bundling.
らしいので
mysqlインストールするかぁmysqlインストール
指示されたコード打ってみる
$ gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/' Fetching mysql2 0.5.3 Installing mysql2 0.5.3 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 /Users/name/.rbenv/versions/2.5.3/bin/ruby -r ./siteconf20181128-2670-lgcxlu.rb extconf.rb checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/bin/mysql_config ----- checking for mysql.h... yes checking for errmsg.h... yes checking for SSL_MODE_DISABLED in mysql.h... yes checking for SSL_MODE_PREFERRED in mysql.h... yes checking for SSL_MODE_REQUIRED in mysql.h... yes checking for SSL_MODE_VERIFY_CA in mysql.h... yes checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes checking for MYSQL.net.vio in mysql.h... yes checking for MYSQL.net.pvio in mysql.h... no checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes checking for my_bool in mysql.h... no ----- Dont know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/Cellar/mysql/8.0.12/lib ----- creating Makefile current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 make "DESTDIR=" clean current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 make "DESTDIR=" compiling client.c compiling infile.c compiling mysql2_ext.c compiling result.c compiling statement.c linking shared-object mysql2/mysql2.bundle ld: library not found for -lssl clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3 for inspection. Results logged to /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.3/gem_make.out An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: mysql2どうやら、
ld: library not found for -lssl
がエラー起こしてるらしいhttps://qiita.com/HrsUed/items/ca2e0aee6a2402571cf6
を参考にさしてもらいterminal$ brew info openssl openssl@1.1: stable 1.1.1g (bottled) [keg-only] Cryptography and SSL/TLS Toolkit https://openssl.org/ /usr/local/Cellar/openssl@1.1/1.1.1g (8,059 files, 18MB) Poured from bottle on 2020-05-20 at 17:52:32 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/openssl@1.1.rb ==> Caveats A CA file has been bootstrapped using certificates from the system keychain. To add additional certificates, place .pem files in /usr/local/etc/openssl@1.1/certs and run /usr/local/opt/openssl@1.1/bin/c_rehash openssl@1.1 is keg-only, which means it was not symlinked into /usr/local, because macOS provides LibreSSL. If you need to have openssl@1.1 first in your PATH run: echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> /Users/kento/.bash_profile For compilers to find openssl@1.1 you may need to set: export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" For pkg-config to find openssl@1.1 you may need to set: export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig" ==> Analytics install: 578,162 (30 days), 1,761,588 (90 days), 7,253,878 (365 days) install-on-request: 61,776 (30 days), 207,766 (90 days), 910,622 (365 days) build-error: 0 (30 days)export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
このオプションの値を指定してインストールするgem install mysql2 -v '0.5.2' --source 'https://rubygems.org/' -- --with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/libbundle install してみる
rails s してみるおわり
- 投稿日:2020-09-07T21:54:30+09:00
[rails sエラー]md5.bundle
目的地
作成済みアプリで問題なくrails s実行
現在
$ rails s 省略) /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': dlopen(/Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError) Referenced from: /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle Reason: image not found - /Users/ユーザーの名前/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin18/digest/md5.bundle原因
pythonの環境構築したことでopensslのバージョンが変わってしまったこと?
やったこと
- rubyの再インストール
- bundlerのバージョン調整
- mysqlインストール
rubyの再インストール
rubyが参照していたバージョンのOpenSSLがなくなったことにより、エラー発生
どうやら再インストールするしかないらしい$ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]$ rbenv uninstall 2.5.1 $ rbenv install 2.5.1$ruby -v # ruby 2.5.1p0 ←のように表示されればOKbundle installしてみる
$ bundle install Traceback (most recent call last): 2: from /Users/<user名>/.rbenv/versions/2.5.3/bin/bundle:23:in `<main>' 1: from /Users/<user名>/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems.rb:308:in `activate_bin_path' /Users/<user名>/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems.rb:289:in `find_spec_for_exe': can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)
。。。
アプリディレクトリ下のbundleのバージョンとglobalのバージョンが違うらしい
bundlerのバージョン調整
アプリ内のgemfileを確認
gemfile.lockRUBY VERSION ruby 2.5.1p57 BUNDLED WITH 2.0.2現在のバージョン確認
bundler -v Bundler version 2.0.1合わせる
$ gem uninstall bundler -v 2.0.1 $ gem install bundler -v 2.0.2bundle installしてみる
$ bundle install (色々なgemのインストールのログが出てくる) . . . Installing ... Fetching mysql2 0.5.2 Installing mysql2 0.5.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 /Users/fukudatakumi/.rbenv/versions/2.5.1/bin/ruby -I /Users/fukudatakumi/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0 -r ./siteconf20190321-35638-onb5bd.rb extconf.rb --with-opt-lib\=/usr/local/opt/openssl/lib\ --with-opt-include\=-I/usr/local/opt/openssl/include checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/opt/mysql@5.7/bin/mysql_config ----- checking for mysql.h... yes checking for errmsg.h... yes checking for SSL_MODE_DISABLED in mysql.h... yes checking for SSL_MODE_PREFERRED in mysql.h... yes checking for SSL_MODE_REQUIRED in mysql.h... yes checking for SSL_MODE_VERIFY_CA in mysql.h... yes checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes checking for MYSQL.net.vio in mysql.h... yes checking for MYSQL.net.pvio in mysql.h... no checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes checking for my_bool in mysql.h... yes ----- Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/opt/mysql@5.7/lib ----- creating Makefile current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" clean current directory: /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" compiling client.c compiling infile.c compiling mysql2_ext.c compiling result.c compiling statement.c linking shared-object mysql2/mysql2.bundle ld: warning: directory not found for option '-L/usr/local/opt/openssl/lib --with-opt-include=-I/usr/local/opt/openssl/include' ld: library not found for -lssl clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2 for inspection. Results logged to /Users/fukudatakumi/tabelog/vendor/bundle/ruby/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2/gem_make.out An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.エラー変わったけど、、、
Make sure thatgem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'
succeeds before bundling.
らしいので
mysqlインストールするかぁmysqlインストール
指示されたコード打ってみる
$ gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/' Fetching mysql2 0.5.3 Installing mysql2 0.5.3 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 /Users/name/.rbenv/versions/2.5.3/bin/ruby -r ./siteconf20181128-2670-lgcxlu.rb extconf.rb checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/bin/mysql_config ----- checking for mysql.h... yes checking for errmsg.h... yes checking for SSL_MODE_DISABLED in mysql.h... yes checking for SSL_MODE_PREFERRED in mysql.h... yes checking for SSL_MODE_REQUIRED in mysql.h... yes checking for SSL_MODE_VERIFY_CA in mysql.h... yes checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes checking for MYSQL.net.vio in mysql.h... yes checking for MYSQL.net.pvio in mysql.h... no checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes checking for my_bool in mysql.h... no ----- Dont know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/Cellar/mysql/8.0.12/lib ----- creating Makefile current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 make "DESTDIR=" clean current directory: /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3/ext/mysql2 make "DESTDIR=" compiling client.c compiling infile.c compiling mysql2_ext.c compiling result.c compiling statement.c linking shared-object mysql2/mysql2.bundle ld: library not found for -lssl clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.3 for inspection. Results logged to /Users/name/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.3/gem_make.out An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: mysql2どうやら、
ld: library not found for -lssl
がエラー起こしてるらしいhttps://qiita.com/HrsUed/items/ca2e0aee6a2402571cf6
を参考にさしてもらいterminal$ brew info openssl openssl@1.1: stable 1.1.1g (bottled) [keg-only] Cryptography and SSL/TLS Toolkit https://openssl.org/ /usr/local/Cellar/openssl@1.1/1.1.1g (8,059 files, 18MB) Poured from bottle on 2020-05-20 at 17:52:32 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/openssl@1.1.rb ==> Caveats A CA file has been bootstrapped using certificates from the system keychain. To add additional certificates, place .pem files in /usr/local/etc/openssl@1.1/certs and run /usr/local/opt/openssl@1.1/bin/c_rehash openssl@1.1 is keg-only, which means it was not symlinked into /usr/local, because macOS provides LibreSSL. If you need to have openssl@1.1 first in your PATH run: echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> /Users/kento/.bash_profile For compilers to find openssl@1.1 you may need to set: export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" For pkg-config to find openssl@1.1 you may need to set: export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig" ==> Analytics install: 578,162 (30 days), 1,761,588 (90 days), 7,253,878 (365 days) install-on-request: 61,776 (30 days), 207,766 (90 days), 910,622 (365 days) build-error: 0 (30 days)export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
このオプションの値を指定してインストールするgem install mysql2 -v '0.5.2' --source 'https://rubygems.org/' -- --with-cppflags=-I/usr/local/opt/openssl@1.1/include --with-ldflags=-L/usr/local/opt/openssl@1.1/libbundle install してみる
rails s してみるおわり
- 投稿日:2020-09-07T21:11:35+09:00
Twitterでかっこよくソースコードを表示するCarbonを君は知っているか。
こんにちは、現在フリーのweb制作者として活動していますしょーごと申します。
さてみなさん、
ソースコードのハイライトは見ていて気持ちが良いですよね。
VSCodeのコードハイライトだと、class名が緑色になるのが好きだったりします。
これに慣れてしまうと、もう質素なメモ帳など使えなくなりますよね。
しかし、Twitterにはエディター機能はないので、ツイートしたくてもそのままソースコードを貼り付けると、すごく味気なくなります(文字数制限もきつい)
私はTwitterを初めて8年、エンジニアを初めて2年立ちますが、2020年からイカしたサービスを活用しています。
コードハイライト大好き教のあなた、今日からCarbonを使うのです。
Carbonとは
Twitterできれいにソースコードを共有できるサービス
です。スクショで貼るより綺麗です。
様々な言語、テーマに対応しているのが写真でわかるかと思います。
上記の写真でのテーマは
VSCode
ですが、私はseti
というテーマが好きなので、setiで表示していきます。Ruby
JavaScript(Vue)
Sass
PHP
簡単投稿、画像保存も可能
Twitterでサインインすればすぐツイートできますし、画像としてpngなどでエクスポートすることも可能です。
投稿時には
Created with @carbon_app
は消しても問題ありません。
pic.twitter.com以下があれば問題ありません。うーん、おしゃれ!!!
Twitterにソースコードを共有する心理としては、
「私のこのスマートなコードを見てくれ!これ便利でおすすめだぜ!!」
という心理かと思いますので(独断と偏見)
訴求力で見ても、とてもスマートなソースコードの共有方法だと思います。
- 投稿日:2020-09-07T20:02:27+09:00
Webアプリケーションにおけるセキュリティ
セキュリティ対策をしていないwebアプリケーションの開発は非常に危険です。
セキュリティとは何なのか。
セキュリティ対策をしていないと
・なぜ危険なのか
・どういった事が起こるのか
・どのように対策するのか
について学んだ内容をまとめました。(Rubyでの開発)前提 プログラミング初学者(1~2ヶ月)が学んだ内容です。 実際の現場で通用しないことや間違った内容が含まれている可能性があります。 間違っている部分や浅い部分については、追記やご指摘いただけると幸いです。セキュリティ対策していないとなぜ危険なのか
セキュリティ対策をしていないwebサービスはなぜ危険なのか、何が起こるのか。
結論
利用者は個人情報が漏れる。
管理者はwebページを勝手にいじられる。もう少し細かく見ると、
・個人情報を勝手に閲覧される
・webページの内容が改ざんされる
・webページ自体が利用不可能になる
その結果
・webサービス利用者へ大きな損害
・公開したwebページの社会的信用を失うwebサービスにおけるセキュリティとは何か
脆弱性があるwebサービスはセキュリティが低いと言えます。
脆弱性
脆弱性とはセキュリティホールとも呼ばれ、ソフトウェアの起こりうる欠陥や使用上の問題点のこと。
悪意のある人に攻撃を仕掛けられる際の弱点といえます。
この脆弱性があると開発者利用者どちらにも様々な被害が生じます。セキュリティ攻撃の種類
・JavaScriptによるセキュリティ攻撃
・セッションを用いた攻撃
・不正なリクエストを行う攻撃
・SQLによる攻撃
攻撃というのは個人情報を抜き取る行為と思って下さい。JavaScriptによる攻撃
JavaScriptはクライアントサイドで動くプログラミング言語です。
何らかの方法で悪意あるJavaScriptを埋め込めば、その埋め込んだページを表示した時にユーザーにそのプログラムを実行させることができます。
このような攻撃方法をXSS(クロスサイトスクリプティング)と呼びます。
スクリプトを埋め込んで実行させることをスクリプティングといいます。
その内容は個人情報を悪意ある人のサーバーへ送付するものが多いようです。JavaScriptによる攻撃
JavaScriptはクライアントサイドで動くプログラミング言語
何らかの方法で悪意のあるJavaScriptをユーザーがwebアプリケーションを表示したブラウザに埋め込めば、ユーザーにそのプログラムを実行させることができる。
このような攻撃をXSSというXSS(クロスサイトスクリプティング)
攻撃者が脆弱性のあるwebアプリケーション上に悪意のあるJavaScriptのプログラム(スクリプト)を埋め込み、そのサイトの利用者を攻撃する手法
悪意あるスクリプトをwebアプリケーションを表示した時に実行させることをゴールとした手法がXSS
スクリプトを埋め込んで実行させることを「スクリプティング」という。
内容は、ユーザーの個人情報などを悪意ある人のサーバーなどへ送付するスクリプトが多い。XSSの攻撃パターン
XSSの攻撃パターンには反射型XSSと格納型XSSの2タイプがあります。
反射型XSS
ユーザーが悪意のあるURLをクリックすると、脆弱性のあるwebアプリケーション上でスクリプトが実行されるようにする手法
手順
①ユーザーにURLをクリックさせる
攻撃者が、ユーザーに悪意のあるURL(脆弱性のあるwebアプリケーションへ遷移するURLに細工をしたもの)をクリックさせる。
→脆弱性のあるアプリケーションは攻撃者のもと?それとも全く関係ないサイト?
前者なら納得、後者なら後者のサイトはセキュリティが弱くて利用されているだけ?
②ユーザーがクリックすると、脆弱性のあるwebアプリケーション上でスクリプトが動く
悪意のあるURLでは脆弱性のあるwebアプリケーション上で発火するスクリプトが仕込まれている。そのため、脆弱性のあるwebアプリを開くとスクリプトが発火する。
③スクリプトが発火すると、攻撃者のサーバーへ個人情報が送られる
発火(発動)したスクリプトは個人情報を抜き取るようなものでした。
クリックしたユーザーの個人情報が攻撃者のサーバーへ記録されてしまいます。このようにURLをクリックしてレスポンスがあると即座にスクリプトが実行されることから反射型と呼ばれる。
別サイト(メールなども含む)から脆弱性のあるwebアプリケーションへ遷移した後にスクリプトが実行される。
よくチャットアプリなんかでURLが貼られると、そのページをクリックする前に
安全なサイトですか?
といった確認が出ると思います。
この反射型XSSを防ぐために、表示させるようにしているのだと思います。
これがクロスサイトスクリプティングのクロスサイト(webサイト間をまたぐ)を意味しています。格納型XSS
脆弱性のあるwebアプリケーションの投稿などに悪意のあるスクリプトを埋め込み、ユーザーがそのwebアプリケーションを訪れた時にスクリプトが発火するような攻撃手法
例えば、twitterの投稿で悪意のあるスクリプトを投稿します。
その投稿が見られるページに遷移した途端スクリプトが発火します。
その投稿をみようとしなくても、その投稿があるページを開いた瞬間攻撃されます。
手順
①攻撃者が、脆弱性のあるwebアプリケーションにスクリプト付きの投稿をする
フォームからコンテンツを投稿する際にスクリプトを埋め込んで投稿する。
②ユーザーがその投稿のあるページを訪れるとスクリプトが発火する。
スクリプトが埋め込まれた投稿ページを開くとそのスクリプトが発火する。
画像にマウスを合わせるとスクリプトが発火するような仕掛けになっていることもある。
③スクリプトが発火すると攻撃者のサーバーへ個人情報が送られる。
脆弱性のあるwebアプリケーションにスクリプトを格納し、ユーザーが訪れたタイミングで発火するようになっていることから格納型と呼ばれる。XSSの対処
XSSは現在でも多く事例が報告されている。
脆弱性をつく攻撃の被害はXSSに起因するものが最も多くの割合を占めている。対処方法
XSSが発生する主要因として、フォームから入力されたスクリプトタグ()などがスクリプトとしてそのままブラウザに反映されてしまっていることがあげられる。
XSSを防ぐためにHTMLにおいて意味を持つ"や<を何らかの別の文字列に変換する。この変換の際に使われる記法を文字参照という。文字参照
ブラウザ上で表示できない特殊文字を表記する際に用いられる記法。
変換前 変換後 < & It; > & gt; & & amp; " & quot; ' & #39; このようにプログラムを記述している時に使っている記号を特殊文字に変換すると、外部から埋め込まれたスクリプトが実行されにくくなります。
Ruby on Railsにおける対処法
ヘルパーメソッド<% %>でXSSの対策を行うことができる。
この中に書かれた記述は文字列として表示されるため、プログラムの記述にはならない。
このプログラムとしてではなく、文字列として特殊文字を表示することをエスケープ?というようです。まとめ
反射型
特定のURLにアクセスすることででスクリプトを発火させる。
格納型
投稿自体をみるとスクリプトが発火するので、普通のサイトで悪意のあるユーザーの投稿にスクリプトが埋め込まれていて、それがあるページにあくせすしてしまうと発火する。
Rubyの場合はRuby on Railsのヘルパーメソッドで回避できる。
- 投稿日:2020-09-07T19:37:55+09:00
Sinatra アプリを CSS で装飾
はじめに
前回の記事 - Qiitaで更に味を占めたので、
CSS
でチョットだけ色を付けてみました完成画面
前回の反省点
err.orapp.rb:2:in `require': cannot load such file -- sinatra/reloader (LoadError)単に、
sinatra-contrib
がgroup :development
になっているだけでした。CSS
ずらずらと並んでいるのはカッコ悪いので、社名のみを表示し、路線名はクリックして表示させることにしました。
style.css.btm { transition: 0.2s; height: 0; overflow: hidden; padding: 0 10px; } .container input:checked + .btm { height: auto; padding: 0 10px 10px 10px; background-color: lightsalmon; }
height
が0
になっているので隠れているんだと思います結果オーライまとめ
- 初アプリ修正
- CSS に詳しくなった
参照したサイト
【CSS】CSSだけでブロック要素の表示非表示
【初学者向け】Ruby 遅延鉄道路線名の入手方法 - Qiita
- 投稿日:2020-09-07T19:16:35+09:00
railsのハッシュタグ検索の実装
今回は、railsでハッシュタグ機能を実装しました。
https://glodia.jp/blog/3936/
のサイトを参考にさせていただきました。完成図
商品を出品する時にタグをつけると実装方法
1 商品テーブルitemsとタグテーブルtagsは中間テーブルで結びついている
2 ヘルパーに、タグ名をリンクにするための記述をするitems_helper.rbdef render_with_hashtags(tag_name, tag_id) tag_name.gsub(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/){|word| link_to word, "/item/hashtag/#{word.delete("#")}?tag_id=#{tag_id}"}.html_safe end第一引数でタグの名前、第二引数で中間テーブルに保存されているタグのidを渡してます。
gsubメソッドでurlに置換しhtml_safeメソッドをつけることでエスケープ処理を避け、ビューに「#名前」の形でリンクが踏めるようになります。
?tag_id=#{tag_id} の記述で、タグのidをリンクの中に仕込む3 ルーティングの実装
routes.rbget '/item/hashtag/:name', to: "items#hashtag"本来はitemコントローラーの中にネストするのがベストだと思います
4 コントローラーの実装
items_controller.rbdef hashtag @tag = Tag.find(params[:tag_id]) @items = @tag.items end2でリンクの中に仕込んだtag_idをparamsで渡し、該当するタグを探す
該当するタグを持つ商品を変数に入れる5 投稿詳細一覧を作る時と同様、eachメソッドを@itemsを使用してビューを実装
完成です!
- 投稿日:2020-09-07T18:53:17+09:00
Rails on Dockerの環境構築手順
環境
- MacOS Catalina 10.15.6
- Docker 2.3.0.3
- Ruby 2.7.1
- Rails 6.0.3.2
- Bundler 2.1.4
- Gem 3.1.2
- Yarn 1.22.5
手順
予めDockerをインストールしておいて下さい。
Rubyイメージの取得
$ docker pull ruby
Dockerコンテナを起動
<NAME>
と<DIRECTORY>
は適時変更して下さい。$ docker run -i -t --name <NAME> -p 3000:3000 -v "$PWD":<DIRECTORY> /bin/bashRailsの導入
作業ディレクトリへ移動します。
$ cd <DIRECTORY>次に、
Gemfile
の生成$ bundle init
生成されていることを確認。
$ ls Gemfile編集用に
vim
をインストール。
(ホストPCのディレクトリから直接編集してもOK)$ apt-get install vim-tiny編集します。
# gem "rails"
のコメントアウト#
を外します。$ vim.tiny Gemfile
編集後# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails"Gemをインストール。
$ bundle install新規Railsプロジェクトの作成。
$ bundle exec rails new .NodeJSをインストール。
$ apt-get install nodejsWebpackerをインストールしますが、その前に
Yarn
が必要なのでインストールします。
しかし、そのままapt-get install
すると0.32+git
というバージョンでインストールされてしまい、
webpack:install
した際に行われるyarn
のバージョンチェック時にエラーが出てしまうようです。
参考文献: 【Rails】ArgumentError: Malformed version number string 0.32+gitでwebpacker:installが実行できない場合の対処方法$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - $ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list $ apt-get update && apt-get install yarnWebpackerをインストール。
rails webpacker:installRails Server起動
起動できるはずです。
$ bundle exec rails server自分の環境の場合、うまくローカルで接続できなかったので明示的に指定すると無事接続できました。
$ bundle exec rails server -b 0.0.0.0=> Booting Puma => Rails 6.0.3.2 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 4.3.6 (ruby 2.7.1-p83), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop Started GET "/" for 172.17.0.1 at 2020-09-07 09:47:16 +0000 Cannot render console from 172.17.0.1! Allowed networks: 127.0.0.0/127.255.255.255, ::1 (1.5ms) SELECT sqlite_version(*) Processing by Rails::WelcomeController#index as HTML Rendering /usr/local/bundle/gems/railties-6.0.3.2/lib/rails/templates/rails/welcome/index.html.erb Rendered /usr/local/bundle/gems/railties-6.0.3.2/lib/rails/templates/rails/welcome/index.html.erb (Duration: 6.3ms | Allocations: 295) Completed 200 OK in 21ms (Views: 12.1ms | ActiveRecord: 0.0ms | Allocations: 1651)Yay! You're on Rails!
おわり
参考文献: 知識0から始めるRails on Docker
- 投稿日:2020-09-07T18:01:51+09:00
preventDefaultはなぜ必要なのか
動作環境
Ruby 2.6.5
Rails 6.0.3.2JavaScriptにおけるpreventDefaultがどういった働きをしているかをようやく理解することができたので、整理するために投稿してみました。
preventDefaultの意味
preventDefaultの必要性について話していく前に、そもそもpreventDefaultが何をしているのかを説明します。
default(デフォルト)の挙動をprevent(妨害)しています。
説明になっていないと思うかもしれませんが、厳密な説明をしようとすると、おそらくかなり長い行数が必要となってしまいますし、具体的な例を提示した方がわかりやすいと思い、端的に説明しました。早速、具体的な例を元に説明していきます。
preventDefaultの具体例
index.rb<%= form_with url: "/posts", method: :post do |form| %> <%= form.text_field :fuga %> <%= form.submit '投稿する' , id: "submit" %> <% end %>index.rbにて投稿するボタンをクリックすると、fugaに入力した内容が投稿されるとします。
このままだと、投稿するボタンをクリックすると、ページの読み込みが始まってしまうので、下記のJavaScriptを記載することで非同期通信にしたとします。function hoge() { const submit = document.getElementById("submit"); submit.addEventListener("click", (e) => { // 投稿するボタンをクリックした時と同じ挙動のコード(長くなってしまうので、省略) }); }; window.addEventListener("load", hoge);しかし、ここで1つ問題が生じてしまいます。それは、非同期通信にしたことによって同じ挙動が追加で行われてしまうので、1回の投稿で2回分投稿したことになってしまうということです。
具体的に説明すると、投稿するボタンをクリックすることで非同期通信が行われ、ページの読み込みなしで投稿が1つ増え、ページの再読み込みをすることで、本来の投稿するボタンをクリックした時の挙動が反映されて、投稿が1つ増えます。そのため、結果として同じ投稿が2回されるということが起きてしまいます。この問題を解決するためにprevent.Defaultを使います。以下のように1行追加するだけです。
function hoge() { const submit = document.getElementById("submit"); submit.addEventListener("click", (e) => { e.preventDefault(); // 投稿するボタンをクリックした時と同じ挙動のコード(長くなってしまうので、省略) }); }; window.addEventListener("load", hoge);これによって、デフォルトの挙動を妨害することができるので、1回の投稿で2回分投稿することがなくなりました。
しかし、ここで私は「そもそもデフォルトの挙動って何?」「なぜ都合よく非同期通信だけの挙動が妨害されていないの?」
といった疑問を抱いておりました。デフォルトの挙動とは?
基本的にRuby on Railsでのデフォルトの挙動は、ビューでの操作によって、ビューからコントローラーに情報が送られ、コントローラー内のいずれかのアクションが動くという認識で問題ないようです。
今回でいうと、投稿するボタンをクリックしたことでcreateアクションが動き、fugaを保存するということがデフォルトの挙動です。通常のRuby on Railsの流れですね。
そのため私は、preventDefaultを「通常のRuby on Railsの流れを妨害するもの」と捉えております。
- 投稿日:2020-09-07T16:37:16+09:00
rubyオブジェクトをJSON形式に変換
引数にハッシュ、配列等のrubyオブジェクトを入れJSON形式で返してくれます
JSON.generate
pry(main)> JSON.generate({"hoge"=>{"fuga"=>1, "fugafuga"=>2}}) => "{\"hoge\":{\"fuga\":1,\"fugafuga\":2}}"JSON.pretty_generate
pry(main)> JSON.pretty_generate({"hoge"=>{"fuga"=>1, "fugafuga"=>2}}) => "{\n \"hoge\": {\n \"fuga\": 1,\n \"fugafuga\": 2\n }\n}"JSON.generateに比べて見やすい文字列に返してくれます
人が読むものではない限りgenerateのほうが容量が軽いためgenerateを使用した方がいいとのことでした
- 投稿日:2020-09-07T15:46:10+09:00
Ruby カロリー計算 アウトプット
自分用のアウトプットです。
食べた食品のカロリー計算をするプログラムをしました。
M = 食品の品数
N = 人数
food = 1gあたりのカロリー
eat = 何g食べたか
carolie = トータルカロリーqiita.rbM,N = gets.chomp.split(" ").map{|i| i.to_i} food = [] i = 0 M.times do i = (gets.to_f / 100) food.push(i) end eat = [] N.times do i = gets.chomp.split(" ").map{|i| i.to_i} eat.push(i) end i = 0 f = 0 total = [] count = N count1 = M - 1 calorie = 0 while count > 0 do for s in 0..count1 do calorie += (food[i] * eat[f][s]).floor i = i + 1 end total.push(calorie) calorie = 0 i = 0 f = f + 1 count = count - 1 end puts totalあまりfor文使い慣れていないのでその点今回使えたのはよかったですかね。
おそらく今回2次元配列を使えばもっと凝縮できた感がありましたが、うまくいきませんでした。。。
- 投稿日:2020-09-07T15:13:30+09:00
RSpecとminitestのおおまかな違い
はじめに
railsで最もよく使われるテスティングフレームワークはRSpecという話をよく聞きますが、
ruby標準で使用できるminitestとの違いについてまとめてみました。RSpecについて
RSpecを使う理由は「最初からいろんな機能が全部入ってて便利だから」。
ちょっとテストコードのここだけを共通化したい、とか、モックで少し凝ったことをやりたい等、RSpecの標準機能でほとんど完結させる事ができる。minitestについて
簡単なRubyプログラムの動作確認をしたりするときに使う。
デフォルトでRubyにインストールされるので、すぐに使えて便利。
RSpec並みに凝ったことをやろうとすると、プラグインをたくさん入れたり、継承、モジュール等を駆使することになるため、業務レベルのテストコードではminitestはあまり使われていない。統合テスティング環境としての RSpec
実利的な観点から minitest よりも RSpec のほうが好ましい点がある。
minitestが 「テスティングフレームワーク」であるのに対して、Rspec が「統合テスティン グ環境」であることを目指しているという点。RSpec は、振舞定義用の DSL の提供に加えて、様々なテスト関連ライブラリや周辺ツールを統合したり、標準サポートしたりといった試みを積極的に続けている。以下にその代表的なものを記述する。
・RSpec 実行結果の色付け (レッドバー/ グリーンバー表示) の標準サポート
・モック や スタブ といったテスト技法の支援、関連ライブラリとの統合
・保留 (pending) のサポート
・Rake や RCov、Heckle、AutoTest (ZenTest) といった周辺ツールとの統合
・Ruby on Rails のサポート
・様々な形式による実行結果レポート (例:HTML 出力) 。
・TextMate との統合
・などなど※各項目について詳しくはRSpec 公式サイトの該当ページ参照
上記周辺ツールへの積極的な統合・サポートにより、RSpecの標準機能でできる事が多いため、広く使用されているのではないかと推測できる。
今後、RSpecを使用したテストについて学んで行きたい。
- 投稿日:2020-09-07T14:03:07+09:00
enumからセレクトボックスを作る際に、表示する文言を変えたいとき
あまり無いケースだとは思うが、enumからセレクトボックスを作成する際に、文言を変えたい場合の方法をメモしておく。
前提として、gemにenumerize
とreform
を使用している。product_form.rbextend Enumerize enumerize :fluit, in: { apple: 1, orange: 2, peach: 3, strawberry: 4, cherry: 5, }, predicates: { prefix: true } property :fluitja.ymlproduct: fluit: apple: りんご orange: オレンジ peach: もも strawberry: いちご cherry: さくらんぼ普通に書けば、これで良い。
new.slim= f.select :fluit, f.object.class.fluit.options, {prompt: '果物を選択'}しかし、「『りんご』と『さくらんぼ』は『(特別セール中)』という文言を入れたい」と言われたとする。
とはいえ、ja.ymlを変えたくはない。
f.object.class.fluit.options
を使わずに1つずつ書くのも、メンテナンス性が悪い。そこで、
f.object.class.fluit.options
が生成する Array を map で回して、特定の value の時のみ、文言を足して返すメソッドを作った。product_form.rbdef fruit_select_display self.class.fluit.options.map do |key, value| if value == 'apple' || value == 'cherry' [key + '(特別セール中)', value] else [key, value] end end endnew.slim= f.select :identification_document_type, f.object.fruit_select_display, {prompt: '果物を選択'}これでいったん用は足せた。
- 投稿日:2020-09-07T13:45:08+09:00
Rails link_toにパラメータを渡す
link_toを使ってgetsでコントローラにパラメータを受け渡したい
やりたいこと
view側からコントローラにリンクする際に、値を受け渡したい
結論
以下のようにパスの引数にハッシュの形で追加してやる
※例)top/indexからtop/link1へ値を渡す場合
top/index.html.erb<%= link_to "リンク1へ", top_link1_path(name: "piyo") %>パラメータを受け取る
top_controllerclass TopController < ApplicationController def link1 @params = params[:name] end end色々と調べてみましたが、備忘録として
- 投稿日:2020-09-07T11:40:11+09:00
Rails6で標準搭載されたwebpackerでハマる
発端
「ん?こっちで見ましょうか?」
から、なかなか気づかずに恥ずかしいハマり方してたので備忘録。
npmやらyarnなどのお話はたくさん情報あるのでそちらで。
対象システムのwebpackerでのbuild対象
application.html.erb<%= stylesheet_pack_tag 'application' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>としてるので、js,css 共にbuild対象。
ファイル構成(必要部分のみ)
app/ └ javascript/ └ packs/ | └ application.js └ stylesheets/ └ application.css └ custom.min.cssapplication.js~~ 省略 ~~ import "../stylesheets/application";application.css@import "~bootstrap/scss/bootstrap"; @import "./custom.min";ふむふむ。
$ bin/webpack ~~ 省略 ~~ ERROR in ./app/javascript/stylesheets/application.css Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/src/index.js): Error: Failed to find '~bootstrap/scss/bootstrap' ~~ 省略 ~~この辺含めてファイル構成だったり確認したけれど特に問題なし、と。
改めてエラーを確認したところ。。。
ERROR in ./app/javascript/stylesheets/application.cssapplication.css!!
$ mv app/javascript/stylesheets/application.css app/javascript/stylesheets/application.scss $ bin/webpack無事build成功。
トホホ。。結論
拡張子には気をつけよう。
- 投稿日:2020-09-07T11:02:37+09:00
Railsで現在いるページの判定をする
- 投稿日:2020-09-07T11:02:37+09:00
Ruby on Railsで現在いるページの判定をする
- 投稿日:2020-09-07T09:53:35+09:00
[Rails]モデルの単体テスト実装方法
前提条件
今回は新規ユーザー登録に関するモデルの単体テストを実装していきながら、方法をアウトプットします。ユーザー登録の仕様書は以下のとおり。
ニックネームが必須 メールアドレスは一意である メールアドレスは@とドメインを含む必要がある パスワードが必須 パスワードは7文字以上 パスワードは確認用を含めて2回入力する ユーザー本名が、名字と名前でそれぞれ必須 ユーザー本名は全角で入力させる ユーザー本名のフリガナが、名字と名前でそれぞれ必須 ユーザー本名のフリガナは全角で入力させる 生年月日が必須マイグレーションファイルは以下のとおり。
20200823050614_devise_create_users.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :nickname, null: false t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :family_name, null: false t.string :family_name_kana, null: false t.string :first_name, null: false t.string :first_name_kana, null: false t.date :birth_day, null: false ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end endモデルは以下のとおり。
user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable # バリデーションの設定(空の文字列を保存させない為と一意性制約) validates :nickname, presence: true validates :encrypted_password, presence: true validates :family_name, presence: true validates :family_name_kana, presence: true validates :first_name, presence: true validates :first_name_kana, presence: true validates :birth_day, presence: true # アソシエーション has_many :cards, dependent: :destroy has_many :shipping_infos, dependent: :destroy has_many :comments, dependent: :destroy has_many :items end実装手順
① RSpecの準備
② RSpecの設定
③ factory_botを導入
④ factory_botの実装
⑤ 正規表現の記述
⑥ テストコードの実装
⑦ テスコードの実行RSpecの準備
まずGemをインストールします。
Gemfile.rbgroup :development, :test do # 省略 gem 'rspec-rails' end group :development do gem 'web-console' end # web_console は既に記述がある場合は、記述場所を移動するだけでOK。追記してしまうと重複してしまう可能性があるため注意してください。Gemfileを編集したら、忘れずにbundle installを実行。
RSpecの設定
続いてRSpecの基本設定を行う。
まずはRSpec用の設定ファイルを作成する。ターミナル.$ rails g rspec:install # 以下のようにファイルが作成されれば成功 ▼ create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb次に、
.rspec
に以下を追加。rspec.--format documentation続いて、RSpec用ディレクトリを設定します。
RSpecによるテストコードが書かれたファイルのことを、specファイルと呼び、全てのspecファイルは、先程の
rails g rspec:install
コマンドで生成されたspecディレクトリの中に格納するので、ここで作成しておきましょう。モデルに関するテスト用ファイルであればspec/models/以下に、コントローラーに関するテスト用ファイルであればspec/controllers/以下に格納されます。appディレクトリ以下にあるテストの対象となるコードの在り処は全てこのディレクトリです。
specファイルは対応するクラスを持つファイル名spec.rbという名前になります。今回はまず「user.rb」に関するspecファイルを作成するので、その場合の名前は`「userspec.rb」`になります。
ディレクトリの作成が完了したら、この時点で一度RSpecが正常に利用できるかの確認を行いましょう。
ターミナル.$ bundle exec rspec # 以下のような結果になれば正常に動作しているのでOK No examples found. Finished in 0.00031 seconds (files took 0.19956 seconds to load) 0 examples, 0 failuresfactory_botを導入
続いてfactory_botを導入します。
Gemをインストール。Gemfile.rbgroup :development, :test do # 省略 gem 'rspec-rails' gem 'factory_bot_rails' endその後、bundle installを実行。
factory_botの実装
次に、specディレクトリ直下に
factories
というディレクトリを作成し,その中に、作成したインスタンスの複数形のファイル名でRubyのファイルを作成します。今回の場合は、users.rb
になります。
users.rb
を以下のように編集。users.rbFactoryBot.define do factory :user do nickname {"tarou"} email {"sample@gmail.com"} password {"1234567"} encrypted_password {"1234567"} family_name {"山田"} family_name_kana {"ヤマダ"} first_name {"太郎"} first_name_kana {"タロウ"} birth_day {"2000-01-01"} end endこの記述は、仕様書に沿った内容をダミーデーターとして作成しており、こうすると、specファイルの中で特定のメソッド(buildやcreate)により簡単にインスタンスを生成したり、DBに保存したりできるようになります。
正規表現記述
続いて、仕様書に沿って、バリデーションへ正規表現を設定していきます。
必要な正規表現は以下のとおり。パスワードは7文字以上 ユーザー本名は全角で入力させる ユーザー本名のフリガナは全角で入力させるこれらを踏まえてモデルへ記述すると以下のとおり。
user.rbclass User < ApplicationRecord # 省略 validates :nickname, presence: true validates :encrypted_password, presence: true, length: { minimum: 7 } # ここが文字数の正規表現 validates :family_name, presence: true, format: {with: /\A[ぁ-んァ-ン一-龥]/ } # ここがユーザー本名全角の正規表現 validates :family_name_kana, presence: true, format: {with: /\A[ァ-ヶー-]+\z/ } # ここがフリガナ全角の正規表現 validates :first_name, presence: true, format: {with: /\A[ぁ-んァ-ン一-龥]/ } # ここがユーザー本名全角の正規表現 validates :first_name_kana, presence: true, format: {with: /\A[ァ-ヶー-]+\z/ } # ここがフリガナ全角の正規表現 # 省略 endRubyの正規表現は下記サイトを参考にしてください。
https://gist.github.com/nashirox/38323d5b51063ede1d41テストコードの実装
それではいよいよテストコードの実装です!
テスコードを記述するときに心掛ける点は以下のとおり。①各exampleで期待する値は1つ ②期待する結果をはっきりわかりやすく記述 ③起きて欲しいことと起きてほしくないこと両方をテストする ④可読性を考えつつ、適度にDRYにするuser_spec.rbに以下のコードを記述。
user_spec.rbrequire 'rails_helper' describe User do describe '#create' do end end今回はUserモデルの単体テストなので
describe User do
となり、新規ユーザーを作成するのでdescribe '#create' do
としており、2行目のdescribの中にテストコードを記述します。まず、全ての項目の入力が存在すれば登録できることをテストします。
コードとその解説は以下の通り。user_spec.rbrequire 'rails_helper' describe User do describe '#create' do # 入力されている場合のテスト ▼ it "全ての項目の入力が存在すれば登録できること" do # テストしたいことの内容 user = build(:user) # 変数userにbuildメソッドを使用して、factory_botのダミーデータを代入 expect(user).to be_valid # 変数userの情報で登録がされるかどうかのテストを実行 end end end続いてテストすることは以下の通り。
nicknameがない場合は登録できないこと emailがない場合は登録できないこと passwordがない場合は登録できないこと encrypted_passwordがない場合は登録できないこと family_nameがない場合は登録できないこと family_name_kanaがない場合は登録できないこと first_nameがない場合は登録できないこと first_name_kanaがない場合は登録できないこと birth_dayがない場合は登録できないことこれらの条件は仕様書の必須項目(null:false, presence: true)をテストする為のものです。
それでは記述していきましょう。解説はnicknameがない場合は登録できないことのテスト箇所で行います。user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 入力されている場合のテスト ▼ it "全ての項目の入力が存在すれば登録できること" do user = build(:user) expect(user).to be_valid end # nul:false, presence: true のテスト ▼ it "nicknameがない場合は登録できないこと" do # テストしたいことの内容 user = build(:user, nickname: nil) # 変数userにbuildメソッドを使用して、factory_botのダミーデータを代入(今回の場合は意図的にnicknameの値をからに設定) user.valid? #バリデーションメソッドを使用して「バリデーションにより保存ができない状態であるか」をテスト expect(user.errors[:nickname]).to include("を入力してください") # errorsメソッドを使用して、「バリデーションにより保存ができない状態である場合なぜできないのか」を確認し、.to include("を入力してください")でエラー文を記述(今回のRailsを日本語化しているのでエラー文も日本語) end it "emailがない場合は登録できないこと" do user = build(:user, email: nil) user.valid? expect(user.errors[:email]).to include("を入力してください") end it "passwordがない場合は登録できないこと" do user = build(:user, password: nil) user.valid? expect(user.errors[:password]).to include("を入力してください") end it "encrypted_passwordがない場合は登録できないこと" do user = build(:user, encrypted_password: nil) user.valid? expect(user.errors[:encrypted_password]).to include("を入力してください") end it "family_nameがない場合は登録できないこと" do user = build(:user, family_name: nil) user.valid? expect(user.errors[:family_name]).to include("を入力してください") end it "family_name_kanaがない場合は登録できないこと" do user = build(:user, family_name_kana: nil) user.valid? expect(user.errors[:family_name_kana]).to include("を入力してください") end it "first_nameがない場合は登録できないこと" do user = build(:user, first_name: nil) user.valid? expect(user.errors[:first_name]).to include("を入力してください") end it "first_name_kanaがない場合は登録できないこと" do user = build(:user, first_name_kana: nil) user.valid? expect(user.errors[:first_name_kana]).to include("を入力してください") end it "birth_dayがない場合は登録できないこと" do user = build(:user, birth_day: nil) user.valid? expect(user.errors[:birth_day]).to include("を入力してください") end end end続いて、emailの一意性制約のテストを行います。
user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 省略 # email 一意性制約のテスト ▼ it "重複したemailが存在する場合登録できないこと" do user = create(:user) # createメソッドを使用して変数userとデータベースにfactory_botのダミーデータを保存 another_user = build(:user, email: user.email) # 2人目のanother_userを変数として作成し、buildメソッドを使用して、意図的にemailの内容を重複させる another_user.valid? # another_userの「バリデーションにより保存ができない状態であるか」をテスト expect(another_user.errors[:email]).to include("はすでに存在します") # errorsメソッドを使用して、emailの「バリデーションにより保存ができない状態である場合なぜできないのか」を確認し、その原因のエラー文を記述 end end end続いて、確認用パスワードがなければ登録できないテストを実行します。
user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 省略 # 確認用パスワードが必要であるテスト ▼ it "passwordが存在してもencrypted_passwordがない場合は登録できないこと" do user = build(:user, encrypted_password: "") # 意図的に確認用パスワードに値を空にする user.valid? expect(user.errors[:encrypted_password]).to include("を入力してください", "は7文字以上で入力してください") end end endここまでで、以下のテストは完了しました。
# 完了したテスト▼ ニックネームが必須 # 完了 メールアドレスは一意である # 完了 メールアドレスは@とドメインを含む必要がある # 完了 パスワードが必須 # 完了 パスワードは確認用を含めて2回入力する # 完了 ユーザー本名が、名字と名前でそれぞれ必須 # 完了 ユーザー本名のフリガナが、名字と名前でそれぞれ必須 # 完了 生年月日が必須 # 完了 # これから実装するテスト▼ パスワードは7文字以上 ユーザー本名は全角で入力させる ユーザー本名のフリガナは全角で入力させるそれでは、ここからは先ほど記述した正規表現のテストを行います。
まずパスワードは7文字以上のテストから。起きて欲しいことと起きてほしくないことの両方をテストします。
user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 省略 # パスワードの文字数テスト ▼ it "passwordが7文字以上であれば登録できること" do user = build(:user, password: "1234567", encrypted_password: "1234567") # buildメソッドを使用して7文字のパスワードを設定 expect(user).to be_valid end it "passwordが7文字以下であれば登録できないこと" do user = build(:user, password: "123456", encrypted_password: "123456") # 意図的に6文字のパスワードを設定してエラーが出るかをテスト user.valid? expect(user.errors[:encrypted_password]).to include("は7文字以上で入力してください") end end end最後に全角入力と全角カナ入力のテストを行います。
user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 省略 # 名前全角入力のテスト ▼ it 'family_nameが全角入力でなければ登録できないこと' do user = build(:user, family_name: "アイウエオ") # 意図的に半角入力を行いエラーを発生させる user.valid? expect(user.errors[:family_name]).to include("は不正な値です") end it 'first_nameが全角入力でなければ登録できないこと' do user = build(:user, first_name: "アイウエオ") # 意図的に半角入力を行いエラーを発生させる user.valid? expect(user.errors[:first_name]).to include("は不正な値です") end # カタカナ全角入力のテスト ▼ it 'family_name_kanaが全角カタカナでなければ登録できないこと' do user = build(:user, family_name_kana: "あいうえお") # 意図的にひらがな入力を行いエラーを発生させる user.valid? expect(user.errors[:family_name_kana]).to include("は不正な値です") end it 'first_name_kanaが全角カタカナでなければ登録できないこと' do user = build(:user, first_name_kana: "あいうえお") # 意図的にひらがな入力を行いエラーを発生させる user.valid? expect(user.errors[:first_name_kana]).to include("は不正な値です") end end endこれで仕様書に沿った機能のテストは以上です。
最終的には以下のようになります。user.spec.rbrequire 'rails_helper' describe User do describe '#create' do # 入力されている場合のテスト ▼ it "全ての項目の入力が存在すれば登録できること" do user = build(:user) expect(user).to be_valid end # nul:false, presence: true のテスト ▼ it "nicknameがない場合は登録できないこと" do user = build(:user, nickname: nil) user.valid? expect(user.errors[:nickname]).to include("を入力してください") end it "emailがない場合は登録できないこと" do user = build(:user, email: nil) user.valid? expect(user.errors[:email]).to include("を入力してください") end it "passwordがない場合は登録できないこと" do user = build(:user, password: nil) user.valid? expect(user.errors[:password]).to include("を入力してください") end it "encrypted_passwordがない場合は登録できないこと" do user = build(:user, encrypted_password: nil) user.valid? expect(user.errors[:encrypted_password]).to include("を入力してください") end it "family_nameがない場合は登録できないこと" do user = build(:user, family_name: nil) user.valid? expect(user.errors[:family_name]).to include("を入力してください") end it "family_name_kanaがない場合は登録できないこと" do user = build(:user, family_name_kana: nil) user.valid? expect(user.errors[:family_name_kana]).to include("を入力してください") end it "first_nameがない場合は登録できないこと" do user = build(:user, first_name: nil) user.valid? expect(user.errors[:first_name]).to include("を入力してください") end it "first_name_kanaがない場合は登録できないこと" do user = build(:user, first_name_kana: nil) user.valid? expect(user.errors[:first_name_kana]).to include("を入力してください") end it "birth_dayがない場合は登録できないこと" do user = build(:user, birth_day: nil) user.valid? expect(user.errors[:birth_day]).to include("を入力してください") end # パスワードの文字数テスト ▼ it "passwordが7文字以上であれば登録できること" do user = build(:user, password: "1234567", encrypted_password: "1234567") expect(user).to be_valid end it "passwordが7文字以下であれば登録できないこと" do user = build(:user, password: "123456", encrypted_password: "123456") user.valid? expect(user.errors[:encrypted_password]).to include("は7文字以上で入力してください") end # email 一意性制約のテスト ▼ it "重複したemailが存在する場合登録できないこと" do user = create(:user) another_user = build(:user, email: user.email) another_user.valid? expect(another_user.errors[:email]).to include("はすでに存在します") end # 確認用パスワードが必要であるテスト ▼ it "passwordが存在してもencrypted_passwordがない場合は登録できないこと" do user = build(:user, encrypted_password: "") user.valid? expect(user.errors[:encrypted_password]).to include("を入力してください", "は7文字以上で入力してください") end # 本人確認名前全角入力のテスト ▼ it 'family_nameが全角入力でなければ登録できないこと' do user = build(:user, family_name: "アイウエオ") user.valid? expect(user.errors[:family_name]).to include("は不正な値です") end it 'first_nameが全角入力でなければ登録できないこと' do user = build(:user, first_name: "アイウエオ") user.valid? expect(user.errors[:first_name]).to include("は不正な値です") end # 本人確認カタカナ全角入力のテスト ▼ it 'family_name_kanaが全角カタカナでなければ登録できないこと' do user = build(:user, family_name_kana: "あいうえお") user.valid? expect(user.errors[:family_name_kana]).to include("は不正な値です") end it 'first_name_kanaが全角カタカナでなければ登録できないこと' do user = build(:user, first_name_kana: "あいうえお") user.valid? expect(user.errors[:first_name_kana]).to include("は不正な値です") end end endテスコードの実行
テストを記述したアプリのディレクトリのターミナルにて下記コマンドを実行。
ターミナル.$ bundle exec rspecすると下記画像のように処理が行われればテストが成功しています。
最後に
モデルの単体テストは基本文法と、エラーを発生させる処理と発生させない処理を把握し、それぞれのメソッドを理解することができれば新たに機能が追加された場合でもコードを記述できると思います。
何か気になる点がございましたらコメント欄にてお申し付けください!
最後までご覧いただきありがとうございました!
- 投稿日:2020-09-07T09:39:05+09:00
byebugの導入から使い方まで
Railsの勉強の際にデバッグツールは使っていますか?
デバッグツールとは、プログラミングにつきもののデバッグ作業をサポートしてくれるツールのことで、ステップ実行といって一行ごとにプログラムを実行してその時に宣言されている変数の中身をみながら動作を確認する事が出来ます。それではRailsの開発に使っているbyebugについて紹介していきます。
まずはbyebugのgemをインストールして、デバックしたいコードに「byebug」というメソッドを仕込んでおくと、プログラムがそこを通過した時に止まり、デバッグモードが開始、対話形式でコマンドを打ち込んでおくと自由にメソッドを実行したり変数の値を確認したり出来ます。
インストール方法
インストールはGemfaileに
gem 'byebug'を追記するだけです。 (railsをインストールしている場合はデフォルトでインストールされています)
追記したら
bundle installでgemをインストールしてきます。
byebugの使い方
まずbyebugを開始するには、デバッグをしたいところにbyebugというメソッドを書いて上げます。
(今回の場所は例となります。)今回はstatic_pages/homeページの部分にbyebugを挿入してみます。
byebugを挟み込んだら、実際にメソッドを叩いてみます。
このように処理が止まり入力プロンプトが出てきます。
ここでnextを入力してEnterを押すと次の行に移動しました。ここでhelpメソッドを調べる為に入力してEnterを押すと
helpの中身を確認する事が出来ます。(変数の中身も見れます)
実際のデバッグ作業ではこのように変数の値やメソッドを実行してみて、期待通りの動きをしているかを確認していきます。よく使うコマンド一覧
next 一行進む continue 次のブレイクポイントに進む step メソッドの内部にステップインする list ソースコードを表示する up ソースコードの上を表示する down ソースコードの下を表示する他にも使ってみたいコマンドがあればhelpを入力すると表示されるので確認してみて下さい♪
ここまで覚えてしまえば、あとは実際に書いてみて慣れるのが一番早いと思います。
まとめ
byebugの紹介をしましたが、いかがでしたでしょうか?
byebugではそれぞれの変数の型も見れるのでブラックボックス化しがちなプログラミングの細かいところを見れるようになり、開発スピードの高速化と一石二鳥です。慣れればとても使えるツールだと思うのでぜひ使ってみてください♪
駆け出しエンジニアなので間違っている部分やわかりにくい点などあるかと思います。
その場合はコメントなど入れていただけるとこれからの成長につながりますのでよろしければお願いします。
【LGTM】を押していただけると飛び跳ねて喜びます。
Twitteの方でも呟いたりしておりますのでもしよろしければ遊びにきてください♪
- 投稿日:2020-09-07T09:23:05+09:00
Ruby始めました
こんにちは
今日から主にRubyに関して記事を書いていけたらなあと思います。
普段は検索して記事を見つけて勉強していましたが、メモ代わりに書き出していきたいと思います。
ruby.rbputs "hello Qiita!"うん、見やすい!
- 投稿日:2020-09-07T09:04:32+09:00
Rubyの基礎文法を簡単にまとめてみた
個人的に理解が浅い部分を抜粋してまとめています。
詳細はページ下部リンクからご覧ください。ハッシュ
#key:valueをひとかたまりに格納する fruits = {"a":"apple", "b":"grape", "c":"orange"} puts fruits puts fruits[:a] #キー値で取り出す #実行結果 {:a=>"apple", :b=>"grape", :c=>"orange"} apple条件分岐
if 条件A 条件に一致した場合の処理 elsif 条件B 条件Aと一致せず、条件Bに一致したの時の処理 else 条件A, Bのどちらにも一致しない時の処理 endインデント
rubyでは、tabキーでインデントはNG!
スペースキーでインデント作る!
繰り返し処理
for文
list = [1, 2, 3, 4, 5] for item in list puts item end #実行結果 1 2 3 4 5while文
a = 1 while a <= 10 do puts a a += 1 end #実行結果 1 2 3 4 5 6 7 8 9 10例外処理
begin
begin 実行するコード rescue 例外が発生したときだけ実行されるコード else 例外が発生しなかったときだけ実行されるコード endrescue
begin 実行するコード rescue 例外が発生したときだけ実行されるコード else 例外が発生しなかったときだけ実行されるコード ensure 例外の有無にかかわらず 最後に実行されるコード endraise
raise エラーの種類メソッド
#メソッド def drinkServer(fruit) drink = fruit + 'ジュース' return drink end puts drinkServer('りんご') #出力結果 りんごジュースクラス
メソッドなどの処理全体のひとかたまり
#円についての処理をするクラスを宣言 class Circle #クラス名の最初は大文字 def area_circle puts @radius * @radius * 3.14 end #関数などが連続するときは間に空行を1行入れること def circumference puts @radius * 2 * 3.14 end def radius=(radius) @radius = radius end end #インスタンスを生成 circle1 = Circle.new #半径を入力 circle1.radius = 3 #関数を呼び出す circle1.area_circle circle1.circumference継承クラス
class クラス名 < 継承したいクラス名 end参考記事
初心者のためのRuby入門徹底ガイド【基礎からわかりやすく解説】 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト
- 投稿日:2020-09-07T08:46:54+09:00
Rails 6で認証認可入り掲示板APIを構築する #2 gitとrubocop導入
Githubに上げる
←Rails 6で認証認可入り掲示板APIを構築する #1 環境構築
前回の続きから。
とりあえず動くところまでいったのでGithubにpushしましょう。New repositoryを選択。
その後適当な名前を付けて作成。
他の人からソースコードを見られたくなければPrivateに。問題なければPublicに。Cloud9はデフォルトでgitが入っているのでそのままgitコマンドが使えます。
$ git add -A $ git commit -m 'initial commit' $ git remote add origin https://github.com/{YOUR_ACCOUNT}/{YOUR_REPOSITORY}.git $ git branch -M master $ git push -u origin master上記コマンドのYOUR_部分は作ったばかりのリポジトリに書いてあるのでそこを参照してください。
キーペアを作成し、公開鍵をGithubに登録する
上記対応だと、pushするたびにGithubのユーザーIDとパスワードを聞かれます。
$ ssh-keygen -t rsaEnterキー連打でキーペアを作ります。
$ cat ~/.ssh/id_rsa.pubで表示される文字列が公開鍵なのでコピーします。
Githubに移動し、右上の自分のアイコンから『Settings』→『SSH and GPG keys』→『New SSH key』と遷移。
タイトルは分かりやすいものを付けて、keyに先程の公開鍵を貼り付けて保存。ただ、これでもpush時にまだIDパスを聞かれるはず。
$ git remote set-url origin git@github.com:{YOUR_ACCOUNT}/{YOUR_REPOSITORY}.gitとすればOK。
これで、次回以降pushやpull時にIDパスを都度聞かれなくなります。参考:GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~
testディレクトリを消す
今回はRSpecを使ってテスト実装していくので、minitest用であるtestディレクトリを消します。
$ git rm -r test/rubocopを入れる
まずは静的解析してくれるrubocopを入れましょう。
というのもコーディング規約をチェックしてくれるgemなのですが、後から入れるとコーディング規約に反する指摘が大量に出て手がつけられなくなるためです。Gemfile... + gem 'rubocop-rails' ...インストール$ bundlerubocop設定ファイルを作る
.rubocop.ymlAllCops: Exclude: - bin/* - db/schema.rb # 日本語コメント許可 AsciiComments: Enabled: false # ダブルクォーテーションに統一 StringLiterals: EnforcedStyle: double_quotesアプリケーションのrootディレクトリ(/home/ec2-user/environment/bbs)に配置してください。
ファイル名の先頭にドット付けるのを忘れずに。rubocop指摘箇所を直す
$ rubocop -a実行すると40個前後のエラーを吐きますが、ほぼ全て以下エラーのはず。
C: Style/FrozenStringLiteralComment: Missing frozen string literal comment.これは
各Rubyファイルの1行目に追記+ # frozen_string_literal: true +
これでOKです。
意味するところはRubyだと文字列がデフォルトでミュータブルだけど、意図しない不具合を生んだりするのでfreezeしてイミュータブルにするといいよね
Ruby3ではデフォルトでイミュータブルになることが決まっているよ、それに備えてこの記述を入れておけばファイル中の文字列がイミュータブルになるよ的な感じです。
数十ファイルを開いて編集保存して…をやるのが面倒であれば、
# Gemfileの先頭に # frozen_string_literal: trueを追記 $ sed -i '1s/^/# frozen_string_literal: true\n\n/' Gemfileのようにすればファイル先頭に追記ができます。
db/*のように指定するとディレクトリ一括もできます(ちょっと危険)。元も子もない話をすると、チュートリアルの範囲ならrubocopでこのチェック無効にしちゃってもいいです。
その場合は.rubocop.yml... + Style/FrozenStringLiteralComment: + Enabled: falseと追記してください。
ただし前述の通りRuby3からはデフォルトでイミュータブルになるので、今後新規アプリケーションを作り始めるのであれば入れておくべきでしょう。あとは以下エラーを潰すだけですね。
C: Style/Documentation: Missing top-level class documentation comment.app/mailers/application_mailer.rb
app/models/application_record.rb
config/application.rb
の3ファイルで発生しているはずですが、クラスのドキュメンテーションが無い時に出るエラーです。config/application.rbmodule Bbs + # + # 設定ファイル + # class Application < Rails::Application
のようにclass定義の前にコメントを追加しましょう。
全て修正し、
Inspecting 26 files .......................... 26 files inspected, no offenses detectedのようにエラーがなくなればOKです。
続きはまた明日
- 投稿日:2020-09-07T06:07:56+09:00
【RSpec】FactoryBotを使ってみよう【Rails】
Factory Botとは??
- テストのためのデータを簡単に作成できるライブラリ
Active Record
を使うFactory Botのあれこれ
factory_bot_rails
をインストールすると、下記のようなコマンドでfactory
を作成するためのファイルを作ることができます。bin/rails g factory_bot:model task少し解説します。
bin/rails g
までは大丈夫でしょう。factory_bot:model
でモデルに明示します。task
のように対象を指定してあげてください。このコマンドを実行すると、
spec/factories/tasks.rb
に以下のようなファイルが生成されると思います。spec/factories/tasks.rbFactoryBot.define do factory :task do end end雛形ができましたね。この中にデータを定義していきましょう。
spec/factories/tasks.rbFactoryBot.define do factory :task do name "お買い物" content "夕飯を買いに行く" end end少ないかもしれませんが、まあ大丈夫でしょう。 テストファイル内で
FactoryBot.create(:task)
と実行することで、spec/factories/tasks.rb
に記述した内容のデータを作成することができます。FactoryBotを少しだけ使いこなす。
オーバーライドさせる
例えば、
task
のname
がnil
だった時にエラーを出力させる異常系のテストを書きたい場合は、下記のように書けます。spec/models/task_spec.rb# nameがなければ、無効。 it "is invalid without a name" do task = FactoryBot.build(:task, name: nil) task.valid? expect(task.errors[:name]).to include("can't be blank") endプロパティを上書きして
nil
にすることで、期待通りの形にしています。ユニークな値を扱う。
例えばメアドは唯一無二であるはずだし、そのような仕様であり、そのようなテストを書くべきです。しかし、
FactoryBot
は常に同じ値を参照するので、そのような事象に対応できない場合があります。この問題をは下記のようにシーケンスを使うことで解決できます。
spec/factories/users.rbFactoryBot.define do factory :user do name "山田" sequence(:email) { |n| "test#{n}@example.com" } end endこのように定義することによって、
test1@example.com
、test2@example.com
のように設定されます。とても便利。