- 投稿日:2020-08-07T23:07:55+09:00
any?メソッドを使用してエラーメッセージの取得
エラーメッセージの表示の際に使用したメソッドをまとめたいと思います。
any?メソッドとは
any?メソッドはすべての要素が偽である場合に false を返します。真である要素があれば、ただちに true を返します。
書き方はこのような感じ
p [false, nil].any? # => false例えばエラーメッセージの記述を部分テンプレートに記載してオブジェクトにエラー情報がある場合のみ表示するように設定するとします。
app/controllers/items_controller.rbdef create @item = Item.new(item_params) if @item.save redirect_to root_path else render :new end endこの記述でバリデーション等で保存に失敗した際に
newアクションへ戻るように設定します。app/views/items/new.html.erb<%= form_with model: @item, local: true do |f| %> <%= render 'shared/error_messages', model: @item %>レンダー先にエラーの情報を持ったモデルオブジェクトを持っていきます。
app/views/shared/_error_messages.html.erb<% if model.errors.any? %> <div class="error-alert"> <ul> <% model.errors.full_messages.each do |message| %> <li class='error-message'><%= message %></li> <% end %> </ul> </div> <% end %>any?メソッドでerrorsの中身を確認して存在する場合はtrueとなりエラーの繰り返し処理が働きます。
またpresent?メソッドとかなり似ていますがany?メソッドは
上記例では繰り返し処理でエラーメッセージ を表示していますが
labelの場所ごとにエラーメッセージを表示したい場合はinclude?メソッドを使ってもいいなと思います。
- 投稿日:2020-08-07T22:27:59+09:00
継続渡しスタイル(CPS)チートシート
例によって,少なくとも約1名(自分自身)には役立ちそうだったので,各言語の継続渡しスタイル(Continuation-passing style,CPS)のサンプル記述を記事としてまとめた.
Python(Python 3):解説付き
対話モードで,
x
に10を代入してから,x + 20
を評価させてみる.>>> x = 10 >>> x + 20 30このプログラム記述をファイルにしてPythonインタプリタに実行させても,何も表示されない.対話モード(REPL)では,式として評価されたものはその結果を表示するのに対し,ファイル実行(スクリプト)では,そのような表示は行わないためである.
C:\Users\hoge>type sample.py x = 10 x + 20 C:\Users\hoge>python sample.py C:\Users\hoge>もし,ファイル実行で評価結果を表示させたい場合は,評価結果を得た後に,たとえば
C:\Users\hoge>type sample.py x = 10 print(x + 20) C:\Users\hoge>python sample.py 30 C:\Users\hoge>ここで,式として記述する場合は,評価結果を処理する関数を必ず指定しなければならない仕組みを考える.次は,
x + 20
を評価したら,その評価結果を関数f
に引数として渡して呼び出す関数cadd20
を定義し,f
にC:\Users\hoge>type sample.py def cadd20(x, f): f(x + 20) x = 10 cadd20(x, print) C:\Users\hoge>python sample.py 30 C:\Users\hoge\python>このように,結果を処理する手続きをあらかじめ指定する仕組みを想定したプログラミング手法を『継続渡しスタイル』(continuation-passing style,CPS)と呼ぶ.このスタイルは,そうとは意識されない形を含め,様々な実装に応用されている.
- コールバック関数(指定する手続き)とハンドラー(呼び出す関数)
- 例外処理の
try
(呼び出す手続き)とexcept
(指定する手続き)- CPSに自動変換して明確となった値受け渡しからの中間言語記述生成
なお,関数のCPSへの変換は容易であるが,変換した関数を使用するには工夫が必要である.ここでは,既存関数のCPSへの変換と利用例を示す(このチートシートの本体).
from operator import add, sub, mul # func(x, y) = (x + y) * (x - y) def func(x, y): return mul(add(x, y), sub(x, y)) print(func(10, 20)) # => -300 def cps(f): def cps(x, y, c): return c(f(x, y)) return cps cps(add)(10, 20, print) # => 30 def cfunc(x, y, c): return cps(add)(x, y, lambda c1: # x + y -> c1 cps(sub)(x, y, lambda c2: # x - y -> c2 cps(mul)(c1, c2, c))) # c1 * c2 -> c cfunc(10, 20, print) # => -300Scheme(Gauche,Guile)
; func(x, y) = (x + y) * (x - y) (define (func x y) (* (+ x y) (- x y))) (display (func 10 20)) ; => -300 (define (cps f) (lambda (x y c) (c (f x y)))) ((cps +) 10 20 display) ; => 30 (define (cfunc x y c) ((cps +) x y (lambda (c1) ; x + y -> c1 ((cps -) x y (lambda (c2) ; x - y -> c2 ((cps *) c1 c2 c)))))) ; c1 * c2 -> c (cfunc 10 20 display) ; => -300Ruby(CRuby)
# func(x, y) = (x + y) * (x - y) def func1(x,y) (x+y)*(x-y) end p func1(10,20) # => -300 add = -> x,y { x+y } sub = -> x,y { x-y } mul = -> x,y { x*y } prn = -> x { p x } cps = -> f { -> x,y,c { c.(f.(x,y)) } } cps[add][10,20,prn] # => 30 cfunc = -> x,y,c { cps.(add).(x, y, -> c1 { # x + y -> c1 cps.(sub).(x, y, -> c2 { # x - y -> c2 cps.(mul).(c1,c2,c) }) }) # c1 * c2 -> c } cfunc[10,20,prn] # => -300JavaScript(Node.js)
// func(x, y) = (x + y) * (x - y) function func1(x,y) { return (x+y)*(x-y) } console.log(func1(10,20)) // => -300 add = (x,y) => x+y sub = (x,y) => x-y mul = (x,y) => x*y cps = f => (x,y,c) => c(f(x,y)) cps(add)(10,20,console.log) // => 30 cfunc = function(x,y,c) { return cps(add)(x, y, c1 => // x + y -> c1 cps(sub)(x, y, c2 => // x - y -> c2 cps(mul)(c1,c2,c))) // x * y -> c } cfunc(10,20,console.log) // => -300備考
記事に関する補足
- そのうち『Iコンビネータ』に関する説明を追加するかもしれない(謎).
参考文献
- お気楽 OCaml プログラミング入門:継続渡しスタイル
変更履歴
- 2020-08-09:Schemeの
call/cc
利用例削除(Twitterコメントより)- 2020-08-07:参考文献欄を追加
- 2020-08-07:JavaScriptの例を追加
- 2020-08-07:初版公開(Python,Scheme,Ruby)
- 投稿日:2020-08-07T19:16:54+09:00
【Rails】form_withを完全に理解した
この記事の内容
- form_withメソッドの使い分け
- それに伴うストロングパラメータの取り扱い
- フォーム内容をHTTP通信させる方法
環境
$ rails -v Rails 6.0.3.1$ ruby -v ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]form_withとは
フォーム送信するためのUI部品をビルドするメソッドで、自動でサーバー側のコントローラアクションを切り替えてくれる特徴を持つ。
切り替える要因となるのは、オプションのmodelやurlに対する値によって変わり、以下のようになる。
オプション @userの中身 呼び出されるアクション 用途 model: @user User.new create ユーザー作成 model: @user User.find() update ユーザー編集 url: sessions_path create ユーザーログイン また、オプションの違いを比較すると、以下のようになる。
オプション 入力エリアのname属性 ストロングパラメータ model: @user name="user[email]" params.require(:user).permit(:email) url: users_path name="email" params.permit(:email) modelオプションを使った例
<%= form_with model: @user do |f| %> <%= f.label :name, "名前" %> <%= f.text_field :name, placeholder: "山田" %> <%= f.submit "登録する" %> <% end %>urlオプションを使った例
<%= form_with url: sessions_path do |f| %> <%= f.label :name, "名前" %> <%= f.text_field :name, placeholder: "山田" %> <%= f.submit "ログインする" %> <% end %>localオプション
実は、デフォルトで
remote: true
オプションが付与されており、いわゆるAjax通信をするようにあらかじめ設定されている。
そのため、特に何も設定しないと、renderメソッドが行われないことによるflashが表示されなかったりする。通常のHTTP通信を行うために、以下のような設定を行うことで、上記の問題を解決することができる。
<%= form_with model: @user, local: true do |form| %>まとめ
form_withは、自動でHTTPリクエストの種類を判別してくれるので、便利。
- 投稿日:2020-08-07T17:42:42+09:00
RailsでWebアプリ開発の流れをざっくり。
完璧自分用です。
rvmでrubyのバージョン変更
terminal.$ rvm install 2.5.1 $ rvm use 2.5.1バージョン指定でRailsでアプリ作成
terminal.$ gem install rails -v 5.2.1 -N #6系なら6.0.2.1とか適宜。 $ rails _5.2.1_ new < app name >必要なgemをインストールしておく
Gemfile.gem 'bootstrap', '~> 4.1.1' gem 'jquery-rails', '~> 4.3.1' gem 'bycript' #最初から用意されているので、コメントアウトを外すterminal.$ bundle installサーバー立てて、ブラウザで確認
terminal.$ rails s -p 任意のポート番号 #-p以下はなくてもok。特に指定しないと3000になるlocalhost:3000(もしくは指定したポート番号)にブラウザでアクセスして、以下のページが表示されればok
モデル作成
ログインシステムやユーザー認証機能用
terminal.$ rails generate model User name:string email:string password_digest:stringブログなどのコンテンツ用
terminal.$ rails generate model Articles title:string description:text後から足したい(user_idをArticlesモデルに足す場合を例に)
できたmigrateファイルに以下のように追記
class AddUserIdToArticles < ActiveRecord::Migration[5.1] def change add_column :articles, :user_id, :int end end最後に
terminal.$ rails db:migrateコントローラとビュー作成
terminal.$rails g controller Users index(ユーザー一覧作るなら) new edit $rails g controller Home index $rails g controller Sessions new #login用ビューに書きがちなrubyコードまとめ
hoge.html.erb#link_to <%= link_to “トップページ”, root_path %> <%= link_to “Yahooへ移動する”, “http://www.yahoo.co.jp/” %> <%= link_to “削除”, member_path(params[:id]), method: :delete %>
- 投稿日:2020-08-07T16:36:09+09:00
DockerでRailsチュートリアルのローカル開発環境構築 - WebpackでBootstrapとFont Awesomeを導入 -
はじめに
Dockerでローカル開発環境構築を行い、Railsチュートリアルを再走しております
- Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6
- Dockerを使用し、開発環境の再現が可能
- なるべくローカル環境にインストールしない
今回はRailsチュートリアルの5章に相当する部分です
3章, 4章の内容は特に問題になりませんが、
5章 5.1.2 BootstrapとカスタムCSS の部分でいよいよWebpackの沼に突入して行きます
具体的にはgemを利用せず, YarnとWebpackでBootstrapやFont Awesomeを導入、管理します
加えてテストを書くことが増えるのでその辺りをRSpecで置き換えて進めていきます
5章終了時のブランチはfilling-in-layoutです
https://github.com/dev-naokit/sample_app_on_docker/tree/filling-in-layout第一回
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita第二回
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ- - Qiita個人開発アプリ
mdClip <オンラインmarkdownエディタ>Dockerのコンテナ上で操作する場合はターミナルのコマンドを適宜
$ docker-compose run app ...もしくは
$ docker-compose exec app ...で置き換えてください。
BootstrapとFontawesomeの導入
Rails 6ではJavaScriptのモジュールバンドラとしてWebpackが導入されていますが、
画像やCSSに関しては従来のSprocketがアセットパイプラインとして使用され、
JavaScriptのみをWebpackでコンパイルするようになっていますapplication.html.erb
<head>
の内容を書き換えます
app/views/layouts/application.html.erb
<head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> # (下の行を追記)webpackがCSSを扱えるようにする <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> # JavaScriptはデフォルトでwebpacerが pack フォルダをコンパイルして出力している <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"> </script> <![endif]--> </head>YarnでBootstrapをインストール
jquery
とpopper
はBootstrapに必要なパッケージ
Font Awesomeもあとで必要になるのでインストールします
('@fortawesome'は誤字ではありません)yarn add bootstrap jquery popper.js @fortawesome/fontawesome-freeインストールされたモジュールは
package.json
で確認できますapplication.js
app/javascript/packs/application.js
以下を追記します
require("bootstrap"); require("@fortawesome/fontawesome-free");
require('jquery')
も併記するような情報もありましたが、
Bootstrapが自動的にrequire('jquery')
してくれるようでココには記述不要です私も色々不具合を検証している過程で
require('jquery')
がなくてもjqueryがロードされることに気づいたのですが
jqueryの多重起動はJavaScriptの動作不具合につながることもあるようで、
現状はこのまま進めます(下に参考記事を貼っておきます)
environment.js
jQueryをどこからでも呼び出せるようにする
config/webpack/environment.js
const { environment } = require('@rails/webpacker') var webpack = require('webpack'); environment.plugins.append( 'Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery', Popper: ['popper.js', 'default'] }) ) module.exports = environmentこうすることで毎回
import $ from 'jquery';
と書かなくて良くなるとのことですCSS
app/javascript/stylesheets/application.scss
(新規作成)以下追記
@import '@fortawesome/fontawesome-free/scss/fontawesome'; @import 'bootstrap/scss/bootstrap';application.js
app/javascript/packs/application.js
以下を追記します
import '@fortawesome/fontawesome-free/js/all'; import "../stylesheets/application.scss";参考
Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
CSSの扱いについて
JavaScriptだけでなく画像やCSS、全てをWebpackでコンパイルすることも可能なようです
現状はSprocketによるアセットコンパイルと、Webpackerが共存している状況に変わりはなく
app/javascript/stylesheets/...
をコンパイルした内容が<head>
内の<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>で出力され
app/assets/stylesheets/...
をコンパイルした内容が同じく<head>
内の<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>に出力されている状況です
つまりチュートリアル通り
assets
内のCSS, SCSSを編集しても、
packs
内のCSS, SCSSを編集してもビューに反映される状況が出来上がっていますBootstrapやFont Awesomeのstyleは後者によってimportされ、コンパイル、ビューに反映されています
今後チュートリアルをすすめる上でどちらのStylesheetを編集しても問題ないと思いますが
<head>
内での呼び出しの順序くらいは気に留めて置いたほうがいいかもしれませんちなみに、
packs
内でCSSを編集する場合、webpack-dev-server
のHot reloadの恩恵を受けられます
具体的には、変更保存した場合に自動的にブラウザがリロードされ、即座に(やや遅延あり...)変更内容を確認できますRailsチュートリアルの流れで
custom.scss
を作成する場合
app/javascript/packs/application.js
に以下を記述すれば大丈夫ですimport "../stylesheets/custom.scss";(私はこの仕様で進めてみます)
Troubleshoot
Bootstrapのスタイルがおかしい
おそらくヘッダー周りが上手く表示されないと思います
Bootstrapのバージョンの違いによるものでこちらの記事の通りインストールすると
Bootstrapの最新版ver. 4.5(2020.8.7現在)が導入されます
(Railsチュートリアルでは3.4.1)navbar-inverseというタグがBootstrap 4では使用できなくなっていますので
<header class="navbar navbar-expand-md bg-dark navbar-dark bg-dark">で置き換えるなど細かな修正が必要です
修正を加えたこの章終了時のBranchを公開する予定ですが
yarn add
の際にバージョンを指定するといった対策も可能ですテストRSpec関連
assert_...
をどう書き換えるか?そのまま使えます
「RSpecでも assert xxx って書いてテストしたい」=> すぐできます! - Qiita
ApplicationHelperをテストでも使えるように...
include ApplicationHelper
を個別の_spec.rb
ファイルに記述もしくは、
spec/rails_helper.rb
に記述
各_spec.rb
でrequireされているので、個々に記述する必要はないはずですおわりに
この部分はRails 6環境で個人アプリ開発にあたり、最も苦労しました
身の丈に合わない内容で誤りを含むかもしれませんが
Railsチュートリアルの環境構築だけでなく、Rails 6環境でアプリ開発を行う方の一助になれば幸いです
- 投稿日:2020-08-07T11:53:29+09:00
編集、削除の権限を投稿者だけにしたい
バージョン
・ruby 2.5.7
・Rails 5.2.4.3編集、削除の権限を投稿者だけにしたい
CRUD処理は出来た!
けど、このままだと全ての投稿を編集や削除が出来てしまう状態。
編集、削除の権限を投稿者だけの機能にしたい。
ユーザーの投稿を守る為に下記のメソッドを使う
unlessはもし〜でなかったらと言う意味。下記でいうと、
もし受け取ったユーザーのIDが、ログインしているユーザー(current_user)のIDと一致しなければ、処理を実行せずリダイレクトで戻しますよっていう意味です。
before_actionでメソッドを呼び出して、完成!!!
before_actionはコントローラーの全てのアクションが実行される前に実行されるものです。
今回は編集と削除のみの場合で行いたいので、editとupdateとdestroyのみにしています。
- 投稿日:2020-08-07T11:40:11+09:00
Ruby 例外処理について
例外処理とは
例外処理を行うことで、エラー原因やエラー箇所の特定や、発生したエラーに対する適切な処理を行うことができます。
本記事では、以下について紹介していきます。
- rescue
- ensure
- 例外処理の戻り値
- return
- rescue修飾子
- 特殊変数
$!
$@
- メソッド全体に例外処理を設ける(begin/endの省略)
- raise
- カスタム例外を作成
rescue
以下のようにbeginの下に、通常実行したいプログラムを記述します。
そのプログラムの実行中に例外が発生した場合に、呼び出したいコードをrescueの下に記述します。begin p "実行するコード" rescue p "例外が発生した場合に実行されるコード" end
結果
"実行するコード"else
rescueに、elseを付け加えることによって
例外が発生しなかった場合に呼び出したいコードを追加できます。begin p "実行するコード" rescue p "例外が発生した場合に実行されるコード" else p "例外が発生しなかった場合に実行されるコード" end
結果
"実行するコード" "例外が発生しなかった場合に実行されるコード"
rescueの使用例
例外が発生したら、「エラーが発生しました!」というメッセージを表示するブログラムを作成します。
文字列を""(ダブルクォーテーション)で囲っていないので例外となり、rescueの下にあるコードが実行されます。
begin p 文字列 rescue p "例外が発生しました" end
結果
"例外が発生しました"ensure
例外処理にensureを使用することで、例外の有無に関わらず実行される処理を記述することができます。
begin p "実行するコード" rescue p "例外が発生した場合に実行されるコード" else p "例外が発生しなかった場合に実行されるコード" ensure p "例外の有無にかかわらず 最後に実行されるコード" end
結果
"実行するコード" "例外が発生しなかった場合に実行されるコード" "例外の有無にかかわらず 最後に実行されるコード"使用用途としては、何らかの処理を行っている時にエラーが発生した場合でも、確実に実行したい処理がある場合に使います。
(例)ファイルを開いて作業するプログラムの場合、「実行中の例外発生に関わらず、最後に必ずファイルを閉じておく」といったことができます。例外処理の戻り値
- 例外発生せず正常に処理が終了した場合、beginの最後の式が戻り値となります。
- 例外が発生した場合、rescueの最後の式が戻り値となります。
(例) 処理が正常に終了した場合
class Return def test(n) begin 1 / n "Begin" ensure "Ensure" end end end obj = Return.new p obj.test(1)"Begin"(例) 例外処理が発生した場合
class Return def test(n) begin 1 / n "Begin" rescue 'Rescue' ensure "Ensure" end end end obj = Return.new p obj.test(0)"Rescue"return
ensure内にreturn文を記述すると、
- 例外発生が取り消され、正常終了してしまう
- 例外発生の有無に関わらず、ensureの値がメソッドの戻り値となってしまう
このことから、本来期待した処理が実行されません。
例外発生が取り消され、正常終了してしまう
本来は下記のようにrescueをなくし、ensureのみ記述した場合は、例外処理が発生すると異常終了となります。
class Return def test(n) begin 1 / n "Begin" ensure "Ensure" end end end obj = Return.new p obj.test(1) p obj.test(0)
結果
(ZeroDivisionError)しかし、ensure内にreturn文を記述すると、下記のように正常終了してしまいます。
class Return def test(n) begin 1 / n "Begin" ensure "Ensure" return "return ensure" end end end obj = Return.new p obj.test(1) p obj.test(0)
結果
"return ensure" "return ensure"例外発生の有無に関わらず、ensureの値がメソッドの戻り値となってしまう
class Return def test(n) begin 1 / n "Begin" rescue 'Rescue' ensure "Ensure" return "return ensure" end end end obj = Return.new p obj.test(1) # 本来は"Begin"が返ってくる p obj.test(0) # 本来は"Rescue"が返ってくる
結果
"return ensure" "return ensure"rescue修飾子
rescueは修飾子のように使うこともできます。
以下のように、普通に記述すると5行は書かないといけない処理がrescue修飾子を使うと1行でスッキリと記述することができます。class Return def test begin 文字列 rescue "error!!!" end end end obj = Return.new p obj.test
rescue修飾子を使用すると1行で書けます!
class Return def test 文字列 rescue "error!!!" end end obj = Return.new p obj.test
結果
"error!!!"特殊変数
特殊変数とは、rubyに用意された特別な意味を持つ変数のことです。
rescueで例外オブジェクトを代入する変数は、指定の有無に関わらず値が代入されます。特殊変数$!
例外が起こった時にその例外オブジェクト(Exception)が代入されます。もしも複数の例外があった場合は一番最後の例外オブジェクトが代入されることになります。例外が発生しなかった場合にアクセスすると nil が得られます。
特殊変数$@
例外が起こったバックトレースを配列にして代入してくれます。バックトレースとは、例外を発生させたプログラム全体の流れを追って、原因となったコードの情報を示すものです。
使用例
コンソール(irbやpry)で例外が発生しても、バックトレースが表示されないことにより、原因がわからない場合があります。
コンソールで例外時のバックトレースを表示するには、特殊変数$@を使用します。irb(main):002:0> puts $@メソッド全体に例外処理を設ける(begin/endの省略)
メソッド全体に例外処理を設ける場合は、begin/endを省略することができます。
begin/endを記述した例
def hoge begin p 1/0 rescue p "エラー!!!" end end
begin/endを省略した例
def hoge p 1/0 rescue p "エラー!!!" endraise
raiseメソッドは意図的に例外を引き起こすためのメソッドです。
下記のように記述すると、raiseメソッドにより例外が引き起こされ、rescueメソッドが実行され、「エラー!!!」と出力されます。
begin raise rescue p "エラー!!!" end"エラー!!!"このメソッドはrescue内でも使用することができます。
使用用途としては、例外発生時にプログラムを異常終了させることに加えて、例外情報をログに記録したり、メール送信したい場合に使うことができます。class Return def test(n) begin 1 / n "Begin" rescue p "エラー!!!(log)" raise end end end obj = Return.new obj.test(0)"エラー!!!(log)" Traceback (most recent call last): 2: from ruby.rb:14:in `<main>' 1: from ruby.rb:4:in `test' ruby.rb:4:in `/': divided by 0 (ZeroDivisionError)カスタム例外を作成
例外クラスはRubyのクラスと同様です。
StandardErrorを継承する独自の例外クラスを作成します。(例)
class Error < StandardError end全てのrubyの例外オブジェクトはmessage属性を持っています。
以下のように独自の例外にデフォルトのメッセージを定義してみます。class Error < StandardError def initialize(msg="Error Message") super end end raise Error #=> Error Message独自のデータを例外に付け加えることができます。
class Error < StandardError attr_reader :attr def initialize(msg="default Error message", attr="value") @attr = attr super(msg) end end begin raise Error.new("Error message", "value") rescue => e puts e.attr #=> value endこれで、独自の例外を作成できました。
参考記事
https://qiita.com/k-penguin-sato/items/3d8ce4e71520da2d68c4
- 投稿日:2020-08-07T11:13:40+09:00
[頭の体操] 逆ポーランド記法の列挙とその計算
列挙
[1, 2, 3, 4]
を与えられた時に四則演算ですべてのパターンを列挙するrequire "set" NUMBERS = [1, 2, 3, 4] SIGNS = %i[+ - / *] results = NUMBERS.permutation(4).uniq.each.with_object(Set.new) do |numbers, results| (SIGNS * 3).permutation(3).uniq.each do |signs| a, b, c, d = numbers x, y, z = signs [c, d, x, y].permutation(4).uniq.each do |combination| next if combination.join.match(/\A([^\d]{2})/) results << ([a, b, *combination, z]).join(" ") end end end # results.size => 7680その計算
1 2 3 4 + - /
を与えられた場合、-0.2を返すrequire 'active_support/core_ext/object/blank' class Rpn SIGNS = %i[+ - / *] class << self def calc(rpn_text) rpn = new(rpn_text) rpn.calc end end def initialize(rpn_text) @stack = notation_to_a(rpn_text) end def calc(this_stack = stack) return this_stack.first if this_stack.size == 1 operator_at = this_stack.index{|x| SIGNS.include? x } operator = this_stack[operator_at] value = this_stack[operator_at - 2].send(operator, this_stack[operator_at - 1]) this_stack[(operator_at - 2)..operator_at] = value return calc(this_stack) end private attr_reader :stack def notation_to_a(rpn_text) rpn_text.chars.select(&:present?).collect do |x| SIGNS.include?(x.to_sym) ? x.to_sym : x.to_f end end end Rpn.calc("1 2 3 4 + - /") # => -0.2
- 投稿日:2020-08-07T07:38:10+09:00
Ruby on Railsのシード機能についてのメモ
はじめに
初心者です。
RubyとRuby on Railsを使ってアプリケーションを作っています。
備忘録も兼ねておりますので、間違いなどあればご指摘ください。シード機能とは
データベース作成後に、初期データを簡単に流し込むことができる機能。
どのファイルを使うのか
db/seeds.rb
に初期データとして流し込みたいコードを記述して、
ターミナルでrails db:seed
すればOK。
実行してもターミナルに何か表示されるわけではないが、データに問題なければ流し込まれているはず。ファイルにはどう記述するのか
例)productsテーブルのnameカラムとdescriptionカラムにデータを5つ流し込む
5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") endtimesメソッドを使っているが、1行ずつ書いていっても問題なし。
まとめ
- シード機能はデータベース作成後に初期データを流し込むことができる機能
db/seeds.rb
に流し込みたいデータを記述- ターミナルで
rails db:seed
すれば流し込める参考
Railsガイドv6.0
https://railsguides.jp/active_record_migrations.html
- 投稿日:2020-08-07T03:52:51+09:00
[ruby]特定条件のみに呼応するプログラムの作成
内容
今日の曜日を表示するコードをDateクラスを使用して記述してください。
ただし、金曜日だった場合だけ以下のように表示の内容を変えてください。(出力内容)
「今日は月曜日」
「今日は金曜日だ !!!」実装
解説
今回はRubyで日付を扱うため、ライブラリであるDateクラスを使用します。
1行目でライブラリからDateクラスをよびだします。
3行目でwdayメソッドを使用し、0(日曜日)〜6(土曜日)の整数にした時の今日の値を取得することができます。
※値なので取得できるのはあくまでも整数です。
なので、4行目でdaysに配列で曜日を記入します。
そして、6~10行目のif文で今日の日付が5(金曜日)だったら
「今日は金曜日だ!!!」と出力される式、違った場合は
「今日は○曜日」と出力される
- 投稿日:2020-08-07T00:22:04+09:00
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ-
はじめに
前回の記事
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita個人開発アプリ
mdClip <オンラインmarkdownエディタ>前回の記事に続いて、Railsチュートリアルのローカル開発環境構築を行っていきます。
Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6
Dockerを使用し、開発環境の再現が可能
なるべくローカル環境にインストールしない
Docker環境で操作する場合はターミナルのコマンドを適宜
$ docker-compose run app ...もしくは
$ docker-compose exec app ...で置き換えてください。
Rspec導入
minitestでも問題ないです
後述のCircleCIでもminitestを走らせる事もできました。Gemfile
必要に応じて以下のgemを追加
(不要ならminitest関連のgemを削除する)
Gemfile
# Test enviroment: Rspec gem 'rspec-rails' gem 'spring-commands-rspec' gem 'guard' gem 'guard-rspec', require: false # Test enviroment: Fake date generator gem 'factory_bot_rails' gem 'faker' gem 'forgery_ja'bundle install
Gemfileを編集したので
docker-compose build
が必要です$ docker-compose build初期ファイル生成
$ rails g rspec:installレポートフォーマット
.rspec
--require spec_helper --format documentationGuard初期化
$ bundle exec guard initspring boot対応
$ bundle exec spring binstub --allGuardの自動テスト時にもspringが有効になるように
Guardfile
$ guard :rspec, cmd: "bundle exec spring rspec" doCircleCI設定
事前準備
ここでは説明しませんが事前に以下の手順が必要だと思います
- GitHub & CircleCI & Herokuのアカウント登録
- SSH接続設定(GitHub - CircleCI)
- CircleCIへのproject登録および環境変数定義(Heroku APIキー, app名)
設定概要
git push
-> 自動test (RSpec) -> 自動デプロイ(Heroku)- Orbを使うと
config.yml
の内容を簡略化できる(キャッシュ利用のための記述が不要)- Orbを使うために
version: 2.1
指定- Docker imageのRuby versionはRailsチュートリアルに合わせて2.6.3
- Node.jsが必要なので-nodeのついたimageを指定
メモ: Node.js バリアントの Docker イメージ (
-node
で終わるタグ) に対しては、Node.js の LTS リリースがプリインストールされています。 独自に特定のバージョンの Node.js/NPM を使用する場合は、.circleci/config.yml
内のrun
ステップで設定できます。 Ruby イメージと共に特定のバージョンの Node.js をインストールする例については、以下を参照してください。公式サンプルを踏襲しています
公式do - Ruby
Language Guide: Ruby - CircleCI公式doc - Heroku Deploy
デプロイの構成 - CircleCI現時点で最新のHeroku-orbは1.2.0ですがバグがあるようで
pull request
されています
deploy-via-git bash script error · Issue #13 · CircleCI-Public/heroku-orbconfig.yml
.circleci/config.yml
version: 2.1 orbs: ruby: circleci/ruby@1.0 node: circleci/node@2 heroku: circleci/heroku@1.1.0 # setupでまとめる commands: setup: steps: - checkout - ruby/install-deps - node/install-packages: pkg-manager: yarn cache-key: "yarn.lock" jobs: build: docker: - image: circleci/ruby:2.6.3-node steps: - setup test: docker: - image: circleci/ruby:2.6.3-node - image: circleci/postgres:11.6-alpine environment: POSTGRES_USER: postgres POSTGRES_DB: myapp_test POSTGRES_PASSWORD: "" environment: BUNDLE_JOBS: "4" BUNDLE_RETRY: "3" PGHOST: 127.0.0.1 PGUSER: postgres PGPASSWORD: "" RAILS_ENV: test steps: - setup - run: name: Wait for DB command: dockerize -wait tcp://localhost:5432 -timeout 1m - run: name: Database setup command: bundle exec rails db:schema:load --trace - run: name: Rspec command: bundle exec rspec deploy: executor: heroku/default steps: - checkout - heroku/install - heroku/deploy-via-git: maintenance-mode: true - run: name: DB migrate command: heroku run rails db:migrate --app $HEROKU_APP_NAME workflows: version: 2 test_and_deploy: jobs: - build - test: requires: - build - deploy: requires: - build - test filters: branches: only: master動作確認
HTMLを書き換える
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base def hello render html: "Bye, world!" end end変更をgit pushして、CircleCIのpipelineがsuccessに変われば
ブラウザから見た内容が上記を反映するはずです簡単なテスト
仮のrequest_specを作成
rails g rspec:request test
spec/requests/tests_spec.rb
require 'rails_helper' RSpec.describe "Tests", type: :request do describe "GET /" do it "Bye, world!が表示されること" do get root_path expect(response.body).to include "Bye, world!" end end endCircleCI上でも上記テストがpassするはずです
Troubleshoot
CircleCIのtestが以下のエラーで失敗する
rails aborted! PG::ConnectionBad: could not translate host name "db" to address: Name or service not known
database.yml
の記述が原因ですtest環境ではdefaultを引き継いで
host: db
が適応されているはずです
config/database.yml
以下のように書き換えて環境変数がある場合はそちらを優先するようにしました
(ymlのなかでもerbが使えるという学びでした)test: <<: *default host: <%= ENV['PGHOST'] || 'db' %> database: myapp_testERROR IN CONFIG FILE:
インデント、フォーマットの間違いが多いと思います
最後に
- 意地でローカル環境をきれいに保つことに注力した結果、デプロイやdb:migrateを自動化することで、Heroku CLIすらインストールすることを回避しましたが、素直にHeroku CLIくらいは入れておいた方が今後のエラー解決に役立つ気もします。
- 難易度は上がりますが、ローカル環境でDocker, CICDを取り入れてのRailsチュートリアル、学べることも多いと思いますので腰を据えて取り組むことのできる方はぜひトライしてみてください。
- 今後も未知のエラーに遭遇することが予想されますが、おおよそココまでが大変なところかとおもっていますので、この記事がお役に立てれば幸いです。