- 投稿日:2020-02-20T23:22:28+09:00
まとめ: 『オブジェクト指向設計実践ガイド-Rubyでわかる進化し続ける柔軟なアプリケーションの育て方-』(第1章-第5章)
『オブジェクト指向設計実践ガイド Rubyでわかる進化し続ける柔軟なアプリケーションの育て方』(第5章まで)要約
前置き
今回のscopeは第1章から第5章までとします。
第6章以降で扱う、継承・モジュール・コンポジション・テストは、別にまとめる方が、一つの記事としてまとまりがあると考えるためです。気になった方は、他の記事や、原著を購入して読まれてください
ここは間違ってるんじゃない?こう理解した方がいいんじゃない?ということがありましたらご指摘お願いします
要約
第1章
オブジェクト指向とはメッセージの伝達に着目する考え。
オブジェクト指向設計とは、オブジェクト同士の依存関係を管理し、疎結合にする設計。第2章
クラスもメソッドも単一責任にする第3章
依存を認識する。基本的には、抽象化され、安定した、自分より変更されないものに依存する第4章
publicメソッド: クラスの主要な責務を明らかにする
privateメソッド: 変化しやすく他のクラスのオブジェクトが依存するのが危ない第5章
ダックタイピングとは、振る舞いによって、オブジェクトの型を定義するテクニック。本題
第1章
オブジェクト指向設計の理解の前提として、
オブジェクト、オブジェクト指向の用語の理解と、設計は何故するのかを理解してからの方が
話は理解しやすいと考えました。なのでそこに軸足をおいてこの章を説明します。
- オブジェクトとは?
- データとメソッドにより定義される振る舞い(処理・手続き)をもつ
- オブジェクト指向とは?
- オブジェクト間のメッセージの伝達に着目する視点のことをいう。
- 補足
- 以前Kyoto.rbで、オブジェクト指向とは何か?という題材で、教えてもらった見方がわかりやすかったので載せときます。
- 世間一般でオブジェクト指向っていう言葉がでた時の2つの視点
- 構成単位に着目する見方(今では割と当たり前な見方)
- レシーバパッシブな、メッセージに着目する見方 <-本書はここ
- 設計がなぜ必要か?
- 必ず行われる変更(新機能の追加etc)の際に、変更のコストを削減するために、設計は大事。
- 現実世界の問題に当てはめると、アプリケーションが成功(ヒット)した時、設計が貧弱だと、単純であるべき変更がアプリケーション内部を伝達し、コードを破壊するから
- オブジェクト指向設計とは?
- オブジェクト同士の依存関係を管理し、互いを知りすぎない、疎結合にする設計
- その結果、オブジェクトが変更を許容できるような形で依存関係を構成するための、コーディングテクニック
まとめると、
オブジェクトとは、データと振る舞いをもつもの オブジェクト指向は、メッセージの伝達に着目する 設計は、変更をよりやりやすくするために必要 オブジェクト指向設計とは、オブジェクト同士の依存関係を管理し、疎結合にする設計のこと第2章
オブジェクト指向はメッセージに着目するとはいえ、目立ってわかりやすいのはクラスです。
そのため、本書ではクラスの設計から説明を始めています。
- クラスとは?
- 似たようなオブジェクトに関する構造の設計図のこと
- 振る舞いを定義したメソッドと、変数を定義した属性をもつ
- 単一責任のクラスをつくる
- 単一責任のクラスから構成されるアプリケーションは変更が簡単。
- 反対に多くの責務をもつクラスの場合、内部がからまり、必要な振る舞いだけを取り出すことができない。
- そう入ったクラスに依存すると、そのクラスに依存する全てのクラスを破壊する可能性がある。
- だから単一責任のクラスで、着脱可能なユニットであることを維持する。
- クラスが単一責任かを見分けるための2つの方法
- クラスがもつメソッドを質問に言い換えた時、意味をなす質問になっているかどうか
- Gearクラスさん、あなたの比を教えてくれませんか OK
- Gearクラスさん、あなたのタイヤは何ですか ...???? NG ※ gear: 歯車。特に自転車の歯車式の変速装置
- 一文で、クラスを説明する
- それと / またはが入ると、そのクラスは2つ以上の責任を負っています
- (余談ですが、個人的にこれはすごくわかりやすくて、クラスを書く際に、コメントで、クラスの責務を一文で書くのを習慣にしてます!)
- クラスがすることが全て、そのクラスの中心的な目的に関連していれば、そのクラスは 凝集度が高い* = 単一責任である!
- あらゆる箇所を単一責任にする
- メソッドも単一責任
- 役割が何であるかを質問し、1分で責任を説明できるようにする
- メソッドを単一責任にして、見えてきた物のうち、責任がありすぎて混沌としているクラスがあれば、それらの責任は別のクラスに分ける
まとめると、
あとからの変更を簡単にするためにも、単一責任のクラスを作る クラスが単一かを見極めるには、「メソッドを質問に言い換える」「一文でクラスを説明する」 メソッドも単一責任にし、混沌とするクラスがあればその責務を新しいクラスに切り分ける第3章
この章では、「依存関係を管理する」手法について説明されます。
ここでいう「依存関係の管理」とは、単一責任をもつオブジェクトが、振る舞いが実装された他のオブジェクトと、共同作業をする適切な方法のことを指します。
- 「依存関係がある」とは、次のことをオブジェクトが知ってるとき
- ほかのクラスの名前
- self以外に送るメッセージの名前
- メッセージが要求する引数
- それら引数の順番 -> ハッシュ の利用
- 一般的に避けた方がいい「依存」の問題
- メッセージチェーン
- 出発と目的地の間の、途中のオブジェクトに依存関係を作り出す
- コードに対する依存関係
- 依存を減らすために
- 依存オブジェクトの注入
- 依存を隔離
- 引数の順番への依存を取り除く
- 初期化の際に引数にハッシュ を使う
- デフォルト値を指定(
||
orfetch
)抽象化された、安定した性質をもつものへ依存することで、変更への直面を低減させる
- 「自分より変更されないものに依存する」
まとめると、
依存関係を認識する、それぞれに依存を減らす対策をする 基本的には、抽象化され、安定した、自分より変更されないものに依存する第4章
この章からクラスからメッセージへと話の重点が移ります。
メッセージとは、メソッドで呼び出し(call)して、オブジェクトへ伝達するもののことです。
またインターフェースとは、クラスの主要な責務を明らかにする、public(公開情報)メソッドのことです。
- オブジェクト指向アプリケーションは、クラスから成り立つが、メッセージにより定義される
- ここでいうインターフェースとは、クラス内にある、外部に晒されているメソッド(パブリックメソッド)のこと
クラス内部で、
public
(公開情報)であるメソッドと、private
(非公開情報)であるメソッドとを分ける
- publicメソッド
- 安全に依存でき、クラスの主要な責任を明らかにする
- privateメソッド
- 変化しうる部分で、他のクラスのオブジェクトが依存するのは危険。テストで言及されないことも。
- (余談ですが、第9章で、privateメソッドをテストしない理由を、不安定で、他のオブジェクトによる利用を避けるためと説明があり、ハッとしました!!!!)
メッセージに基づく設計へ視点を変更し、このメッセージを送る必要があるけど、誰が応答すべきかと思考を変える
- シーケンス図を書くことにより、パブリックインターフェースとして公開すべきメソッドを顕にし、メッセージを明らかにすることができる
publicインターフェースでは、「何を」に着目し、依頼先のクラスの責務として「どのように」(方法)を任せる
- 「私は自分が何を望んでいるか知っているし、あなたがあなたの担当部分をやってくれると信じているよ」が理想
まとめると、
オブジェクト指向アプリケーションはメッセージにより定義される クラス内部で、クラスの主要な責務を明らかにするpublicメソッドと変化しやすく他のクラスのオブジェクトが依存するのが危ないprivateメソッドを分ける 「どのように」については、依頼先クラスを信頼し、そのクラスの責務として任せる第5章
はじめに
ダックタイピングの背景には、
メッセージを設計の中心におく、パブリックインターフェースを構築するという2つの考えがあります
- ダックタイピングとは
- オブジェクトを、クラスではなく、メッセージ(振る舞い)によって定義するテクニック
- オブジェクトを特定のクラスから切り離し、
何を「する」
かで、オブジェクトの仮想の型
を定義する- ポリモーフィズムとは
- 相手がどのクラスのオブジェクトかを意識せずに、メッセージを送れる仕組み
- 同じ名前のメソッドを複数のクラスで使用できるようにし、そのメソッドを通して、暗黙的に複数のインスタンスの動作を切り替えれるようにすること
- ダックタイピングを認識する3つの
- クラスで分岐するcase文
- kind_of?とis_a?
- responds_to?
- ダックタイピングという言葉に囚われすぎずに、これらが出てきた時に、ダックタイピングができないかどうか考えてみるくらいの温度感からまず、接してみるといいのかも。
まとめると、
ダックタイピングとは、振る舞いによって、オブジェクトの型を定義するテクニック。 ダックタイプを見極める3条件を見つけると、まず疑ってみる。読後感想
オブジェクト指向設計の考えが深まった。
ただ、第5章のダックタイピングの章が、何を目的として、独立した章を用意しているのかが僕の理解では追いつきませんでした
Rubyでは、型≠クラスで、振る舞いによって型が規定される
ことを示すため??
時間を置いて、読み返してみよう。
- 投稿日:2020-02-20T23:03:40+09:00
【rails】bundle install したときに vender/bundle にインストールされるのをデフォルトに戻す
はじめに
Railsで開発している時、エラーを解決しようとガチャガチャやった後、
bundle install
したらなぜかプロジェクト下の vender/bundle に gem がインストールされるようになってしまいました。とりあえず前の状態に戻したいと思い、原因と解決法を探りました。bundle install --path vender/bundle
調べてみると、むしろ
bundle install --path vender/bundle
を推奨する記事が散見されましたが、下記の記事のようにこの慣習に疑問を呈している記事もありました。bundle install時に--path vendor/bundleを付ける必要性は本当にあるのか、もう一度よく考えてみよう
デフォルトに戻す
ググると以下のような方法をすぐに見つけました。
Bundlerがどこからgemを探すかは、プロジェクトルートの下の.bundle/configに設定ファイルがあります。これを消すことで、新たな場所にbundle installできるようになります。
https://teratail.com/questions/16066
しかし、私の場合この方法では症状解決しませんでした。
そこで、もう一度bundle install
しプロジェクト下に作成された .bundle/config ファイルを確認しました。--- BUNDLE_WITHOUT: "production"…特に
path
オプションに関連するものはありませんでした。そこで
bundler config
でどのようなオプションが設定されているかを確認しました。$ bundler config Settings are listed in order of priority. The top value will be used. without Settings are listed in order of priority. The top value will be used. path Set for the current user (/Users/punkshiraishi/.bundle/config): "vendor/bundle"これで path オプションが /Users/[ユーザ名]/.bundle/config で設定されていることが分かったので開いてみると
/Users/[ユーザ名]/.bundle/config--- BUNDLE_WITHOUT: "production" BUNDLE_PATH: vendor/bundleありました!
このBUNDLE_PATH: vendor/bundle
を削除し、bundle install
することで、使用中の Ruby 直下に gem がインストールされるようになりました!更に調べてみると bundler のオプションは
- Railsプロジェクト下の .bundle/config
- 環境変数
- ユーザのホームディレクトリ下の .bundle/config
の3つにあるということが分かりました。プロジェクト直下の .bundle/config を削除しても設定が戻らないという方は上記も調べてみると良いかもしれません。
参考
- 投稿日:2020-02-20T21:33:24+09:00
複数テーブルに存在するカラムのi18n定義を共通化する
複数テーブルに共通して存在するカラム(ex.
created_at
,updated_at
)を各テーブルで定義するのは冗長でめんどくさい。config/locales/translation_ja.ymlja: activerecord: attributes: user: name: ユーザ名 created_at: 登録日時 updated_at: 更新日時 event: name: イベント名 created_at: 登録日時 updated_at: 更新日時こんな風に書かなくても、
attributes
直下で定義すれば使い回すことができる。config/locales/translation_ja.ymlja: attributes: created_at: 登録日時 updated_at: 更新日時<%= l(User.created_at) %> => 登録日時
- 投稿日:2020-02-20T20:07:03+09:00
Railsで投稿した内容をGoogleMap上にmarkerで表示させる方法
はじめに
世界中の絶景を投稿できるアプリが作れます。
マップの表示方法はGoogleMapsAPIを使いました。
投稿した内容から自動的に軽度と緯度を取得してGoogleMapsAPIのマップ上に表示させます。
完成形はこんな感じ
環境
- Ruby 2.5.1
- Rails 5.2.3
- MySQL 5.6
目次
- GoogleMapsAPIのKEYを取得
- 簡単なアプリを作成しとりあえずGoogleMapsをアプリ上に表示させる
- 投稿機能を作り軽度、緯度取得し、マップ上に表示
GoogleMapsのKEYを取得
(グーグルアカウントにログインしてから始めてください)
まずGoogle Map PlatformからKEYを取得します
全て選択し続行。
プロジェクト名はなんでもいいですが今回はMyProjectを選択
支払い方法を入力します。
topページに移動しますので下の方のMaps Platfomを選択
Maps JavaScript APIを選択し有効を押します
画面上にあるAPI とサービスの認証情報
認証情報を作成を選択しAPIを作成。
画面にでてくるのがAPIキーになるので保存しといてください。(必要な場合はキーの制限をしてください)簡単なアプリを作成しgooglemapをアプリ上に表示させる
アプリ名はここではgmapにします
ここの部分は自分のアプリ名にしてください。
まずアプリの雛形とデータベース設計しますターミナル上で
rails _5.2.3_ new gmap -d mysql cd gmap rails g controller maps rails db:create rails db:migrateerbになっているのでhamlに変換します。
ここは任意で大丈夫です。
※erbをhamlに簡単に変えてくれるサイトですGemfilegem "haml-rails", ">= 1.0", '<= 2.0.1'bundel install rails haml:erb2haml
マップを表示させます
rails5.2以上なので今回はcredentialsを使いますroutes.rbRails.application.routes.draw do root to: "maps#index" endviews/maps/index.html.haml%div{:style => "width: 100%;"} #map{:style => "width: 100%; height: 100vh;"} :javascript function initMap(){ let map = new google.maps.Map(document.getElementById('map'), { center: {lat: -34.397, lng: 150.644}, zoom: 8 }); } %script{:src => "https://maps.googleapis.com/maps/api/js?key=#{Rails.application.credentials[:GOOGLE_MAP_KEY]}&callback=initMap"}先ほどのAPIキーをcredentialsで隠しておきます
ターミナル上でEDITOR="vi" bin/rails credentials:editGOOGLE_MAP_KEY: MyAPIKeyMyAPIKeyの部分は先ほど取得したkeyを入力してください
これで一応マップ表示ができたと思います!
投稿機能を作り軽度、緯度取得
まずは投稿機能を作るためにpostsのviewとcontroller,modelを作ります。
rails g scaffold posts name:string description:string latitude:float longitude:float rake db:migrate表示をgmaps4railsのgemを使って表示する方法に変えます。
Gemfilegem 'gmaps4rails'underscore、gmaps/googleをapplicaton.jsに追加します。
//= require underscore //追加 //= require gmaps/google //追加 //= require_tree .app/assets/javascripts/underscore.jsを作り
こちらの中身を全部コピペviews/maps/index.html.haml%div{:style => "width: 100%;"} #map{:style => "width: 100%; height: 100vh;"} :javascript handler = Gmaps.build('Google'); handler.buildMap({ provider: {mapTypeId: 'hybrid'}, internal: {id: 'map'} }, function(){ markers = handler.addMarkers(#{raw @hash.to_json}) handler.bounds.extendWith(markers); handler.fitMapToBounds(); handler.getMap().setCenter(new google.maps.LatLng(35.681298, 139.7640582)); handler.getMap().setZoom(4); });provider: {mapTypeId: 'hybrid'}の部分でマップのタイプを変えることができます。
何もなければ最初のタイプです。
他のタイプは下記を参照してください。ROADMAP 道路や建物などが表示される地図です
SATELLITE 衛星写真を使った地図です
HYBRID ROADMAPとSATELLITEの複合した地図です
TERRAIN 地形情報を使った地図ですapplicationにkeyを移してどこでも使えるようにします。
application.html.haml!!! %html %head %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/ %title Gmap = csrf_meta_tags = csp_meta_tag = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %script{:src => "//maps.google.com/maps/api/js?key=#{Rails.application.credentials[:GOOGLE_MAP_KEY]}"} %script{:src => "//cdn.rawgit.com/mahnunchik/markerclustererplus/master/dist/markerclusterer.min.js"} = yieldコントローラーに投稿した場所にmarkerが立つようにします。
maps_controller.rbclass MapsController < ApplicationController def index @posts = Post.all @hash = Gmaps4rails.build_markers(@post) do |post, marker| marker.lat post.latitude marker.lng post.longitude marker.infowindow post.description end end endmarker.infowindow post.descriptionのところに表示させたいカラムを変えれば表示内容を変えれます。
今回はdescriptionにします。これでマーカーが立つようになりました。
あとは新規投稿で軽度、緯度を取得できるようにしますgem 'geocoder'post.rbclass Post < ApplicationRecord geocoded_by :name after_validation :geocode end名前のカラム名で軽度と緯度が取得できるようになったので
あとは送信する時に余計なカラムを消しておきます。posts/_form.html.haml.field = f.label :name = f.text_field :name .field = f.label :description = f.text_field :description .field = f.label :latitude = f.text_field :latitude .field = f.label :longitude = f.text_field :longitude .actions = f.submit 'Save'のlatitudeとlongitudeの項目を消します。
これで完成です!最後に
間違っているところがあったら教えてください…
- 投稿日:2020-02-20T20:03:59+09:00
RailsアプリをDockerで作ってCircleCIで自動テストしてHerokuにデプロイした話
はじめに
どうも、Pirikaraです。
久しぶりの投稿となりました。今回は、Docker環境でRailsアプリケーションを開発し、
CircleCIで自動テスト、Herokuにデプロイするところまでやっていきたいと思います。
個人開発でやってみましたが、このエラーの山々......
一つ一つエラーを解決して設定ファイルを修正してを繰り返し繰り返し......
やっとまともに動くようになりました。
初めてやるよって方は僕の屍を踏み越えていってください。
ちなみに間違ってるよーとか改善点とかご指摘いただけると幸いです。環境
・Mac OS
・Ruby 2.5.3
・Rails 5.2.2
・MySQL 5.7また、Dockerがインストールされていることを前提としています(Dockerコマンドが使用できる状態)。
インストールしていない場合は、公式サイトからアカウントを作ってログインし、DockerHubからダウンロード・インストールします。
DockerhubHerokuについても登録していない場合は登録の必要があります。
公式サイトから登録が可能です。
Herokuアプリの構成
開発環境からDockerを導入し、RailsとMySQLのimageでコンテナを作りました。苦労していた環境構築がすぐに出来て感動。
GithubにpushするとCircleCIによる自動テストが行われて、テストをパスするとHerokuに自動でデプロイされる仕様です。
また、Herokuでは有料であればMySQLが使用できるみたいですが、僕はお金がないので本番環境のみPostgreSQLを使用します。では、
1. Docker開発環境の構築
2. CircleCIの導入と自動テスト
3. Herokuに自動デプロイ
の順番でやっていきましょう。1.Docker開発環境の構築
まず、アプリケーションのディレクトリを作成します。
ここではsample_appとします。sample_appディレクトリを作成 $ mkdir sample_app sample_appディレクトリに移動 $ cd sample_appディレクトリ内に「Dockerfile」「docker-compose.yml」「Gemfile」「Gemfile.lock」の4ファイルを作成します。
$ touch Dockerfile $ touch docker-compose.yml $ touch Gemfile $ touch Gemfile.lockでは、それぞれ中身を書いていきましょう。(Gemfile.lockは空のままです)
DockerfileFROM ruby:2.5.3 #必要なパッケージのインストール RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs #作業ディレクトリの作成 RUN mkdir /bbs_app #作業ディレクトリをAPP_ROOTに割り当てる ENV APP_ROOT /bbs_app WORKDIR $APP_ROOT #ローカルのGemfileを追加 ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock #Gemfileのbundle installを実行 RUN bundle install ADD . $APP_ROOTdocker-compose.ymlversion: '3' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root ports: - "4306:3306" web: build: . command: rails s -p 3000 -b '0.0.0.0' environment: RAILS_ENV: development volumes: - .:/bbs_app ports: - "3000:3000" links: - dbGemfilesource 'https://rubygems.org' gem 'rails', '5.2.2'ところどころ違いますが、
設定の内容についてはこちらの記事が詳しくて参考になったので、任せます。
DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】ここまで書けたら、dockerコマンドでrails newします。
$ docker-compose run web rails new . --force --database=mysql --skip-bundleあとでimageを構築する際にDockerfileにしたがってbundle installが実行されるので、ここではスキップします。
作成されたconfig/database.ymlを編集します。
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # docker-compose.ymlのMYSQL_ROOT_PASSWORD host: db # docker-compose.ymlのservice名dockerを起動します。
imageを構築(コンテナは作成しない) $ docker-compose build コンテナを構築・起動 $ docker-compose upデータベースを作成します。
$ docker-compose run --rm web rails db:create--rmオプションをつけることで、コンテナが実行されたあと削除されます。
「rails g controller ~」や「rails console」など、docker-composeから始まるコマンドで実行していくことになりますが、
--rmをつけていないと実行するたびにコンテナが増えていってしまうので、都度削除しています。僕は。ここまでできると、localhost:3000へアクセスしてサーバーの起動を確認することができます。おめでとう。
2.CircleCIの導入と自動テスト
こちらのブログをパク・・・参考にしました。
導入まで大変わかりやすく、参考になりました。こちらを参考に導入してみてください。「.circleci」というディレクトリを作成し、これ以下に「config.yml」というファイルを作成します。
また、configディレクトリ以下に「database.yml.ci」というファイルを作成します。では、作成したファイルの中身を書いていきましょう。
config.ymlversion: 2 jobs: build: docker: - image: circleci/ruby:2.5.3-node-browsers environment: - BUNDLER_VERSION: 2.0.2 - RAILS_ENV: 'test' - image: circleci/mysql:5.7 environment: - MYSQL_ALLOW_EMPTY_PASSWORD: 'true' - MYSQL_ROOT_HOST: '127.0.0.1' working_directory: ~/bbs_app steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "Gemfile.lock" }} - v1-dependencies- - run: name: install dependencies command: | gem install bundler -v 2.0.2 bundle install --jobs=4 --retry=3 --path vendor/bundle - save_cache: paths: - ./vendor/bundle key: v1-dependencies-{{ checksum "Gemfile.lock" }} # Database setup - run: mv ./config/database.yml.ci ./config/database.yml # Database setup - run: name: Databasesetup command: | bundle exec rake db:create bundle exec rake db:schema:load # run tests! - run: name: Run rspec command: | mkdir /tmp/test-results TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \ circleci tests split --split-by=timings)" bundle exec rspec \ --format progress \ --format RspecJunitFormatter \ --out /tmp/test-results/rspec.xml \ --format progress \ $TEST_FILES # collect reports - store_test_results: path: /tmp/test-results - store_artifacts: path: /tmp/test-results destination: test-resultsdatabase.yml.citest: adapter: mysql2 encoding: utf8 pool: 5 username: 'root' port: 3306 host: '127.0.0.1' database: app_test #database.ymlのテスト環境のデータベース名を参照これでGithubへpushすると、自動でテストが実行されるようになります。
プルリクエストを作ってmasterブランチへmergeしていくと思うのですが、テストに失敗するとmergeすることができません。
ほらね。テストをパスすると、Mergeボタンがアクティブになります。
※ seeds.rbを読み込みたい場合
.circleci/config.ymlでseeds.rbの読み込み設定をしたところ、うまくいかなかったのでspec_helperにseeds.rbを読み込む設定をしました。
「database_cleaner」というgemを導入し、spec_helperへ処理を書いていきます。
これで、Rspec実行の際にデータベースがリフレッシュされ、seeds.fileが読み込まれます。Githubへpushした際に実行された場合は大丈夫なのですが、ローカルでdocker-composeコマンドからrspecを実行した場合にデータベースがリセットされてしまうので注意してください。
Gemfilegroup :development, :test do # rspec実行時にDBをリセットする gem 'database_cleaner' endspec_helper.rb# テスト実行時にDatabaseをリセットし、seeds.rbを読み込む RSpec.configure do |config| config.before(:suite) do DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation) Rails.application.load_seed end end3.Herokuに自動デプロイ
Herokuにデプロイするため、ファイルを修正・追加します。
まずはGemfile。
開発環境ではMySQL、本番環境ではPostgeSQLを使用するので、「pg」のgemをインストールします。Gemfile# 変更前 gem 'mysql2', '>= 0.4.4', '< 0.6.0' # 変更後 gem 'mysql2', '>= 0.4.4', '< 0.6.0', groups: %w(test development), require: false gem 'pg', '~> 0.19.0', group: :production, require: false次に、database.ymlを編集していきます。
本番環境でPostgreSQLを使う設定をします。database.ymlproduction: <<: *default adapter: postgresql encoding: unicode pool: 5そして、「heroku.yml」というファイルを新たに作成します。
作成場所はアプリ直下です。(GemfileとかDockerfileと一緒)
今回はDockerコンテナを使用して開発をしているので、コンテナごとHerokuのサーバーに持っていきます。
そのための設定ファイルです。知らんけど。DockerコンテナをHerokuにアップする方法は公式サイトを参考にしました。
heroku.ymlbuild: docker: web: Dockerfile run: web: bundle exec puma -C config/puma.rbアプリケーション側の設定はこれで完了です。
ではHeroku側の設定をしてデプロイしていきましょう。
ターミナルから、Herokuにログインします。$ heroku login # ログインするかどうか確認されます。 # クリックするとブラウザが立ち上がり、Herokuのログイン画面になります。ログインしてください。 heroku: Press any key to open up the browser to login or q to exit: # ログインが完了すると、ターミナルに「ログインしたよー」って表示されます。 Opening browser to https://cli-auth.heroku.com/auth/browser/************** Logging in... done Logged in as *******@email.com次に、Herokuにアプリケーションを作成します。
# アプリケーション名のところには好きな名前を入れてください。それでURLが作成されます。 $ heroku create アプリケーション名 Creating app... done, ⬢ ******* https://******.herokuapp.com/ | https://git.heroku.com/*******.gitちなみにこの時、Herokuのリポジトリが作成されています。
もしアプリケーションの名前を変更したいときは、Herokuの管理画面から名前を変更することに加えて、リポジトリを削除する必要があります。$ git remote rm herokuこのコマンドで消せます。
消さないとアプリ名とリポジトリ名が異なるためにデプロイできなくなります。そして、Heroku側でPostgreSQLを使用する設定をします。
$ heroku addons:create heroku-postgresql:hobby-dev # PostgreSQLのデータベース作ったよーって通知がきます。 Creating heroku-postgresql:hobby-dev on ⬢ ******... free Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Created postgresql-transparent-70433 as DATABASE_URL Use heroku addons:docs heroku-postgresql to view documentation今回DockerコンテナをHerokuにのせるので、Heroku側でコンテナにアプリのStackをセットします。
$ heroku stack:set containerこの辺の話は「heroku.yml」の設定の時に出てきた公式サイトに全部載ってます。
Dockerを使用したデプロイこれでデプロイするための設定は完了しました。
masterブランチにアプリをpushしたのち、$ git push heroku masterこのコマンドでHerokuのリポジトリにpushすることでデプロイが完了します。エラーが起こらなければ。
さて、ついに自動デプロイです。
circleciを通してHerokuにデプロイしていくので、config.ymlファイルにdeployの処理を追加します。config.yml# 省略 - deploy: name: Deploy Master to Heroku command: | if [ "${CIRCLE_BRANCH}" == "master" ]; then git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP_NAME.git master fi「HEROKU_API_KEY」と「HEROKU_APP_NAME」については、CircleCIに設定した環境変数が読まれるため、
こちらを設定していきます。どちらもHerokuの管理画面から取得できます。
アカウント設定からHEROKU_API_KEYに当たるAPI KEYを......
アプリケーションの設定からHEROKU_APP_NAMEを......
それぞれ取得します。CircleCIのアプリケーション管理画面から、右上の「Project Setting」をクリックします。
Environment Variablesから「Add Variables」をクリックして、先ほど取得した値を環境変数として設定します。
これがconfig.ymlで使用されます。
設定は以上です。
これで、Githubへpush → CircleCiが自動でテスト → パスすればHerokuに自動でデプロイ
という風に動きます。良かったね。
終わりに
DockerとCircleCIを利用したのは初めてでしたが、
環境構築もテスト・デプロイも簡潔になったので、非常に便利でした。特にテストコマンドやデプロイコマンドについては「コマンド打つだけやしなぁ......」と自動化の恩恵を甘く見ていましたが、
チリも積もればなんとやらです。
いちいちコマンドを打つ煩わしさから解放され、アプリの開発スピードも段違いだったように感じます。参考にしていただけたら幸いです。
またね。
- 投稿日:2020-02-20T19:53:02+09:00
【初心者向け】form_withでundefined method `form_with' forというエラーが出た際の対応方法について
Railsでform_withを使用した際、undefined method `form_with' for やDid you mean? form_tagと表示されてしまって詰まった話
Railsでアプリケーションを作成中、投稿フォームの実装時、form_withを使用したところ、永遠とエラーが出てしまって解決に時間がかかってしまったため、備忘録として残す。
結論、form_withはRailsのバージョンが5.1 以上じゃないと動かないようです。
Railsガイド様いつも参考にしています
https://railsguides.jp/5_1_release_notes.htmlWebcamp様にも記載ございました
https://web-camp.io/magazine/archives/17665何をすればいいのか?
Gemfileの中にあるRailsのgemのバージョンをアップグレードする
Railsバージョンアップデートの手順
- gemファイルのrailsを5.1以上で指定する(ここでは5.2.4を指定しています)
gem 'rails', '~> 5.2.4'
- bundle updateする(※注意:bundle installではない!!!!)
bundle updateRailsをバージョンアップした際にRails sで立ち上がらない問題が発生
undefined method `halt_callback_chains_on_return_false=' for ActiveSupport:Module (NoMethodError)これが表示されたら、configファイルの中身の以下
config/initializers/new_framework_defaults.rb以下をコメントアウト
ActiveSupport.halt_callback_chains_on_return_false = false と Rails.application.config.action_controller.raise_on_unfiltered_parameters = true上記をコメントアウトし、これで通常通りRails sで起動した。
(よかった・・・・でも勉強になった)ちなみに、ActiveSupport.halt_callback_chains_on_return_falseの意味はよくわかりません・・・。
https://techracho.bpsinc.jp/hachi8833/2017_02_21/35843参考記事
https://qiita.com/luglio22/items/0dd520f3748935bada81もし
ここは違う、ここはこうした方が良い等々ございましたらご指摘いただけますと幸いです。
最後までみていただき、ありがとうございます。
- 投稿日:2020-02-20T19:34:28+09:00
rails s 起動しない 解決方法の1つ
チーム開発においてエラーが発生!
※ 初心者向けに何か助けになればと思い記述しております。
※ アウトプットの練習も兼ねております。開発環境 rails 5.2.4.1
ruby 2.5.1
クラウドサービスはAWSを使用
現状自動デプロイまで完了5名でフリマアプリの作成
githubアプリより最新のタスクデータを取得のため
masterブランチにブランチを切り替えpullを実行rails sでサーバーを立ち上げた際に起動しない
..... => Rails 5.2.4.1 application starting in development => Run `rails server -h` for more startup options Exiting Traceback (most recent call last): 85: from bin/rails:3:in `<main> .....試した事
PC再起動
bunde linstall
rails db:migrate
rails db:rollback
rails db:drop
rails db:migration:reset
rake db:migrate:reset 等...いずれもエラー表示冷静にエラーの記述を見るとrails sの起動時に下記の内容が
config/initializers/carrierwave.rb:10:in `block in <top (required)>'
指定のファイルconfig/initialize/carriewave.rbの記述に注目
provider: 'AWS', aws_access_key_id: Rails.application.credentials[:aws] [:access_key_id], aws_secret_access_key: Rails.application.credentials[:aws] [:secret_access_key], region: 'ap-northeast-1'
結果awsのマスターkeyをpullでは取得できていないためであったと思われる。
configファイルの参加にmaster.keyのファイルを作成しマスターよりkeyを一旦取得し記述するとエラーは解決。しかしこのままではセキュリティに問題がある為、別の方法を模索中です。
- 投稿日:2020-02-20T19:13:49+09:00
処理速度が早いrender
renderは使い方を間違えると表示に読み込みが遅くなってしまう。
今回はパフォーマンスを意識して学習した。NG:each doで部分テンプレート読み込み
each doは繰り返し処理なので、部分テンプレートもなんども読み込みする。
悪い例# eachを使う処理はNG <% @products.each do |product| %> // 3つの書き方を記述しているが、each doを利用しているのでだめ <%= render product %> <%= render 'products/product', product: product %> <%= render partial: 'products/product', locals: { product: product } %> <% end %>@productsが1000個の場合、1000回部分テンプレートを読み込む事になる。
処理が早い書き方
正解= render partial: 'product', collection: @products, as: "product" # partial: 'product' > _product.html.erbを読み込む # collection: @products > 複数あるproductを1つずつ処理する。 > each doの代わりになる。 # as: "product" > @products の単体の変数 、部分テンプレートで利用する変数はproductになる。これだと一度しか部分テンプレートが読み込まれないから、処理速度が早まる。
- 投稿日:2020-02-20T18:21:30+09:00
Jenkins Pipelineのpipeline {...}の"pipeline"と"{...}"は何か(Groovy初心者向け、他言語経験者向け)
背景
お仕事でJenkins Pipelineを書くことになりました。早速サンプルをコピーし、Hello Worldが表示されてうれしい一方、こんな疑問が。
この、
pipeline
と{...}
とは何なのか?どういう文法規則なのか?Jenkinsfilepipeline { agent any stages { stage('Build') { steps { sh 'echo "Hello World"' } } } }Jenkinsfile自体は単なるデータ構造(JSONやYAMLの仲間)に見えます。ということは何か規則があるはずです。しかしそれが書かれているページが見つからない。
職場のつよつよエンジニアに聞いたところ、JenkinsfileはGroovyのプログラムということが分かりました。その後自分で調べたことと、他の言語との対比を書いておきます。
"pipeline"と"{...}"は何かの答え
pipeline
はメソッド名
{...}
はクロージャ
pipeline {...}
は、pipeline
メソッドに、{...}
というクロージャを引数として渡す、という構文です。
pipeline
はメソッドなので、Jenkinsfileの実行時にdef pipeline(Closure c) { // 前処理 // クロージャを呼び出す c(); // 後処理 }のように定義されたメソッドが(どこかから)読み込まれています。
もっと詳しく
groovyのメソッド呼び出し
上記の
pipeline
の呼び出しを冗長に書くと、pipeline({ -> // 処理 })です。
groovyのクロージャは{x, y -> x + y}
のように、{引数 -> 処理}
のように書きます。引数がない場合は、引数 ->
の部分は省略可能です1。引数を省略すると、pipeline({ // 処理 })の形になります。
また、メソッド呼び出しのカッコは、引数がある場合は省略可能なので、pipeline { // 処理 }になります。Jenkinsfileと同じ形になりました。
クロージャ
クロージャとは、メソッドの呼び出し側で動いているような振る舞いをする無名関数です。
こちらの説明が分かりやすいです。
クロージャ - Apache Groovyチュートリアル他の言語で書いてみると
Groovyのクロージャを他の言語と対比します。(ここに書ききれない言語につきましてはコメントで補足お願いします)
Ruby
Groovyの
pipeline { // 処理 }という記法は、Rubyの
pipeline { # 処理 }という記法と対応します。見た目は同じですね。GroovyはRubyに強い影響を受けていることがわかります。
Rubyのブロックを、Groovyではクロージャと言います。ブロックとクロージャの違いは、こちらのページが分かりやすいです。
Rubyist のための他言語探訪 【第 5 回】 GroovyJavaScript
Groovyの
pipeline { // 処理 }という記法は、JavaScriptの
pipeline(() => { // 処理 })という記法に対応します。JavaScriptではメソッド呼び出しのカッコは省略できず、引数がない場合も引数を囲むカッコを省略できないですが、Groovyでは省略が可能です。
Java
Groovyの
pipeline { // 処理 }という記法は、Javaの
pipeline(() -> { // 処理 })に対応します。JavaScriptと同様Javaでもメソッド呼び出しのカッコと、引数がない場合は引数を囲むカッコを省略できません。Groovyではこの2つは省略可能です。
Python
Groovyの
pipeline { // 処理 }という記法は、Pythonで対応する記法がないのですが、あえて書くとしたら
pipeline(lambda: 処理)です。Pythonの場合、lambda式は複数行にまたがることができませんが、Groovyでは可能です。
参考資料
あとがき
Jenkinsfileを作成している最中、「コピペで動いてはいる、ただ、なんで動いているのか分からない」という状態でしたが、Groovyのプログラムということを理解し、実態がつかめました。
Jenkins Pipelineの記事がまだまだ少ないので、分かったことを今後も書けたらと思います。
正確に言うと、
{-> 処理}
と{ 処理 }
では挙動が変わります。 ↩
- 投稿日:2020-02-20T16:51:40+09:00
RubyOnRails消化のコツ
はじめに
TECH::EXPERTというプログラミング教室に通っている添野です。
今日はRails苦戦中の方におすすめの記事です。Railsはプログラミング初心者が一見すると難解ですよね。
今回は、Rails初心者だった私が理解をするために用いたコツを紹介します。Rails消化のコツ
結論をいいます。
Railsのコードを「決まっているもの」と、「自分で決めていい/または決めたもの」に分類してください。これだけです。逆に言うと、これ以外に「理解する方法」はありません。理由は「理解=分類」だからです。「例え話が分かりやすい理由」とかも「理解=分類=比較=例え話」だからですね。少し話がそれましたが、以下、消化のコツを解説していきます。
例
次のコードは、Railsコントローラの記述の一部です。
@tweet = Tweet.new決まっているもの
「.new」は決まっているものです。
「決まっているもの」とは、Railsというカレールーに予め入っているスパイスです。スパイスはもうとっくの昔にカレールーの中に溶け込んでおり、それを後からスパイスだけ取り出して変えるということですので、錬金術師以外にはできません。語尾に草を追加して「.neww」とか書くと、エラーになります。自分で決めていい/または決めたもの
「Tweet」は決めたもの、「@ tweet」は決めていいものです。
「Tweet」はテーブルの名前で、データベース作りをするときにあなたが既に決めています。もう決めたものなので、1文字でも打ち間違えるとエラーです。もう皿に盛ってしまったライスを一旦捨てて、別のライスを盛るというのは、超美食家パーソナルコンピューター様は決して許しません。エラーという名の罵詈雑言を浴びせられ、基本的には食べてくれません。
@ tweetというのは、これからカレーに入れる具材の名前です。この時点で決めることができます。ここだけ唯一「@ tweet」以外で書いてもエラーにはなりません。
以上、こんな感じでひたすら分類を繰り返してください。まとめ
とにかく、上記の2つを分類することを意識しつつコーディングを進めると良いかな、と私は思います。美食家をうならせるようなカレー作りを、明日もがんばっていきましょう!
おすすめ記事
「TECH::EXPERTはカレーづくり教室だった話」
- 投稿日:2020-02-20T16:10:32+09:00
#Stripe API checkout / Web form input credit card / setup mode / #Ruby example
- publish checkout session by API
- use checkout session id in client e.g html + js and redirect to Stripe webform
- After checkout you can retrieve payment method by API
https://stripe.com/docs/payments/checkout/collecting
# Docs # https://stripe.com/docs/payments/checkout/collecting # Code require 'stripe' Stripe::api_key = ENV['STRIPE_SECRET_KEY'] checkout_session = Stripe::Checkout::Session.create( payment_method_types: ["card"], mode: "setup", # customer_email: "", # client_reference_id: "", success_url: "http://example.com", cancel_url: "http://example.com", ) # customer = Stripe::Customer.create # # checkout_session = Stripe::Checkout::Session.create( # payment_method_types: ["card"], # mode: "setup", # customer: customer.id # success_url: "http://example.com", # cancel_url: "http://example.com", # ) # Exception: Stripe::InvalidRequestError: You can not pass a `customer` in setup mode. puts checkout_session # e.g # # { # "id": "cs_test_nSeAmaYPHYg3uYoJr0AGc8KDPWLX2SnW5ESdiSiNpIwkwb7QjoLBdcUZ", # "object": "checkout.session", # "billing_address_collection": null, # "cancel_url": "http://example.com", # "client_reference_id": null, # "customer": null, # "customer_email": null, # "display_items": [ # ], # "livemode": false, # "locale": null, # "metadata": { # }, # "mode": "setup", # "payment_intent": null, # "payment_method_types": [ # "card" # ], # "setup_intent": "seti_1GDl7YCmti5jpytU0I0ByfjD", # "submit_type": null, # "subscription": null, # "success_url": "http://example.com" # } puts <<~HTML <script src="https://js.stripe.com/v3/"></script> <script> var stripe = Stripe('#{ENV['STRIPE_PUBLIC_KEY']}'); stripe.redirectToCheckout({ // Make the id field from the Checkout Session creation API response // available to this file, so you can provide it as parameter here // instead of the placeholder. sessionId: '#{checkout_session.id}' }).then(function (result) { // If `redirectToCheckout` fails due to a browser or network // error, display the localized error message to your customer // using `result.error.message`. }); </script> HTML # e.g # # Save this html file in your machine and access # # <script src="https://js.stripe.com/v3/"></script> # # <script> # # var stripe = Stripe('pk_test_wxxxxxxxxxxxxxxxxxxxxxx'); # # stripe.redirectToCheckout({ # // Make the id field from the Checkout Session creation API response # // available to this file, so you can provide it as parameter here # // instead of the placeholder. # sessionId: 'cs_test_nSeAmaYPHYg3uYoJr0AGc8KDPWLX2SnW5ESdiSiNpIwkwb7QjoLBdcUZ' # }).then(function (result) { # // If `redirectToCheckout` fails due to a browser or network # // error, display the localized error message to your customer # // using `result.error.message`. # }); # # </script> # Redirect to URL example # https://checkout.stripe.com/pay/cs_test_fRmOtv2TQjhfo1WmVXCxw68tlckFz6KiIUi2EwvHTACynBckPrfu98L1#fidkdWxOYHwnPyd1blpxYHZxWnJhVDRvd1B3bHRzY2xWSF9ycUJAUVFfZzU1dU9tNkJRTTMnKSd3YGNgd3dgd0p3bGJsayc%2Fa3BpaSknaGxhdic%2FfidicGxhJz8nS0QnKSdocGxhJz8nYzRhMWNnPDQoMGc1NygxPWNmKGc0PDUoNGRjMGFnPTQwMWQwJykndmxhJz8nNTNnMTcxZDMoNzE2MCgxMzwwKDwzY2coYTZgYzM0MjM1ZDU1J3gpJ2dgcWR2Jz9eWHgl # After checkout Stripe::Checkout::Session.retrieve(id: checkout_session.id, expand: ["setup_intent", "setup_intent.payment_method"]).setup_intent # There is payment method # => #<Stripe::SetupIntent:0x3fc716e16f00 id=seti_1GDlGfCmti5jpytUDumoV2O4> JSON: { # "id": "seti_1GDlGfCmti5jpytUDumoV2O4", # "object": "setup_intent", # "application": null, # "cancellation_reason": null, # "client_secret": "seti_xxxxxxxxxxxxxxxxxxxxxxxxxx", # "created": 1582090721, # "customer": null, # "description": null, # "last_setup_error": null, # "livemode": false, # "mandate": null, # "metadata": {}, # "next_action": null, # "on_behalf_of": null, # "payment_method": {"id":"pm_1GDlLxCmti5jpytUaLbokfjU","object":"payment_method","billing_details":{"address":{"city":null,"country":"JP","line1":null,"line2":null,"postal_code":null,"state":null},"email":"example@gmail.com","name":"yuma inaura","phone":null},"card":{"brand":"visa","checks":{"address_line1_check":null,"address_postal_code_check":null,"cvc_check":"pass"},"country":"US","exp_month":11,"exp_year":2030,"fingerprint":"3Dnj9E30BUfyFTcl","funding":"credit","generated_from":null,"last4":"4242","three_d_secure_usage":{"supported":true},"wallet":null},"created":1582091050,"customer":null,"livemode":false,"metadata":{},"type":"card"}, # "payment_method_options": {"card":{"request_three_d_secure":"automatic"}}, # "payment_method_types": [ # "card" # ], # "single_use_mandate": null, # "status": "succeeded", # "usage": "off_session" # }succeeded and redirect to
JP
Stripe API API で WebFormで決済情報・カード情報を登録するためのセッションを発行する
Original by Github issue
- 投稿日:2020-02-20T16:01:57+09:00
bundle install 実行 エラー
bundle install を実行後次のエラーが発生
※初心者向けです
アウトプットの練習の為、記述しています。開発環境
ruby 2.5.1
rails 5.2.4gemに追記したいファイル
gem 'carrierwave' gem 'mini_magick'Gemファイルに追記後下記のエラーがターミナルで発生
There was an error parsing `Gemfile`: unterminated string meets end of file - gem 'mini_magick ^. Bundler cannot continue. from /Users/yasumasaikeda/Desktop/projects/mini_listing/Gemfile:64 gem 'carrierwave' gem 'mini_magick
上記のエラーメッセージは記述によるミスでgemファイルの( ' )が最後抜けてました。
かなり初歩的なミスですがエラーの内容をしっかり見て、指定のファイルを辿れば解決できました。正しいgemファイルの記述
gem 'mini_magick'
以上、です
- 投稿日:2020-02-20T14:41:06+09:00
【ruby2.5】今日の日付を取得する方法
Dateクラスを初めて知ったので、備忘録用にまとめました。
年/月/日/曜日の取得方法
require "date" puts Date.today #出力結果 2020-02-20 puts Date.today.year # 2020 puts Date.today.month # 2 puts Date.today.day # 20 puts Date.today.wday # 4todayメソッドを用いて、
dateクラスから今日の日付情報を含んだインスタンスを作成する→Date.todayDate.todayにそれぞれyear、month、day、wdayメソッドを用いて情報を取得する
曜日の取得方法
曜日に関しては、曜日情報を含んだ引数が取得されるので、
言葉に変換する場合は例えば下記のように取得できます。require "date" date = Date.today.wday days = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"] puts days[date] #出力結果 木曜日以上です。
- 投稿日:2020-02-20T14:25:54+09:00
【binarysearch.io】Codewars と併用すると良いかもしれないオンラインプログラミング学習サイト
Twitter でのつぶやきで知ったオンラインのプログラミング学習サイトです。
#朝ダイジェスト
— Alyson //东京黑客/แฮกเกอร์โตเกียว (@Alyson__T) January 28, 2020
競技プログラミングとかリートコードよりもまずはcodewarsやこういうのでまったりやってからだよな。
Binary Search | Master algorithms togetherhttps://t.co/jvb7UhSdym
- Java, Ruby, Python, C++, JavaScript に対応しています (2020/02/20現在)。
- チャットしながら複数人で解答を作っていくという醍醐味があるみたいですが、今回は一人で(他人のチャットに邪魔されずに)学習する方法をお教えします。
- Codewars よりも問題の質が安定しているという印象を受けました。(公式が作成した問題のみ)
- 競技プログラミングではないので、プログラミング学習のドリルとして使う、プログラミングのレベルアップに使う等の用途に向いていると思います。
1. https://binarysearch.io/ にアクセスし「Get Started」をクリックしてサインアップを行います。
2. 「Full Name」「Username」「Email」「Password」を入力して「Sign up for Binary Search」をクリックします。
3. 2で登録した「Email」に登録確認用メールが送信された旨が表示されるので、メールアプリを開いて確認用のリンクをクリックします。
4. メールアドレスの確認が完了したら「Start」ボタンをクリックします。
5. https://binarysearch.io/ のログイン後の画面が表示されます。問題を解くには「Create room」ボタンを押します。
6. Difficulty で問題の難易度を選びます。外国人の方からチャットで話かかけられたりしないように Capacity を「1 player」にしておく(または Private にしておく)と良いかもしれません。
7. room を作成したら「Start Room」ボタンを押して問題を開始します。(今回は Easy で作成しました)
8. 「引数として与えられた配列の長さが1かどうかを返す」よう関数を完成させなさい、という問題です(注記:こんな簡単すぎる問題ばかりではありません)。解答言語としてJavaScriptを 選択しました。
9. 解答を作成したら「Run▶」ボタンをクリックします。「Correct!」と表示されたら「Submit code」ボタンをクリックします。
10. 問題によっては、「Solution」というタブに解法・解説が提示されることがあります。(この問題は簡単すぎなので解説がないんだと思います)
11. 別の問題を解くには「Start Room」ボタンを再度押して次の問題を開始します。部屋を抜けるには画面右上の×ボタンをクリックします。
最後に
公式の問題ばかりなので(?)問題の質が安定している(均一)なのが良いですね。気になったのは同じレベルで学習を続けていると同じ問題が出てくることがあることですが、そのまま解いちゃえば良いので大きな問題ではないと思います。
- 投稿日:2020-02-20T14:25:54+09:00
【binarysearch.io】Codewars と併用すると良いかもしれないオンラインプログラミング学習サイト (Master algorithms together)
Twitter でのつぶやきで知ったオンラインのプログラミング学習サイトです。
#朝ダイジェスト
— Alyson //东京黑客/แฮกเกอร์โตเกียว (@Alyson__T) January 28, 2020
競技プログラミングとかリートコードよりもまずはcodewarsやこういうのでまったりやってからだよな。
Binary Search | Master algorithms together https://binarysearch.io/
- Java, Ruby, Python, C++, JavaScript に対応しています (2020/02/20現在)。
- チャットしながら複数人で解答を作っていくという醍醐味があるみたいですが、今回は一人で(他人のチャットに邪魔されずに)学習する方法をお教えします。
- Codewars よりも問題の質が安定しているという印象を受けました。(公式が作成した問題のみ)
- 競技プログラミングではないので、プログラミング学習のドリルとして使う、プログラミングのレベルアップに使う等の用途に向いていると思います。
1. https://binarysearch.io/ にアクセスし「Get Started」をクリックしてサインアップを行います。
2. 「Full Name」「Username」「Email」「Password」を入力して「Sign up for Binary Search」をクリックします。
3. 2で登録した「Email」に登録確認用メールが送信された旨が表示されるので、メールアプリを開いて確認用のリンクをクリックします。
4. メールアドレスの確認が完了したら「Start」ボタンをクリックします。
5. https://binarysearch.io/ のログイン後の画面が表示されます。問題を解くには「Create room」ボタンを押します。
6. Difficulty で問題の難易度を選びます。外国人の方からチャットで話かかけられたりしないように Capacity を「1 player」にしておく(または Open to public を Private にしておく)と良いかもしれません。
7. room を作成したら「Start Room」ボタンを押して問題を開始します。(今回は Easy で作成しました)
8. 「引数として与えられた配列の長さが1かどうかを返す」よう関数を完成させなさい、という問題です(注記:こんな簡単すぎる問題ばかりではありません)。解答言語としてJavaScriptを 選択しました。
9. 解答を作成したら「Run▶」ボタンをクリックします。「Correct!」と表示されたら「Submit code」ボタンをクリックします。
10. 問題によっては、「Solution」というタブに解法・解説が提示されることがあります。(この問題は簡単すぎなので解説がないんだと思います)
11. 別の問題を解くには「Start Room」ボタンを再度押して次の問題を開始します。部屋を抜けるには画面右上の×ボタンをクリックしてから「Leave」を選択します。
最後に
公式の問題ばかりなので(?)問題の質が安定している(均一)なのが良いですね。気になったのは同じレベルで学習を続けていると同じ問題が出てくることがあることですが、そのまま解いちゃえば良いので大きな問題ではないと思います。
- 投稿日:2020-02-20T13:51:15+09:00
[読書] オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
なんとなくオブジェクト指向を導入し、妙に DRY にこだわった結果、相互依存が増えて見通しの悪い巨大なオブジェクトの中に手続き的なコード分岐が大量に存在するコードに直面することは、比較的 Rails で開発しているとあることかもしれない。オブジェクト指向は教条主義的になりがちだが、現実正解にある巨大なゴチャゴチャコードからどうやって分離するかという観点では実践的なガイドとなる。実質的にはリファクタリングをオブジェクト指向を用いてどうすすめるかという観点で良い助けになるだろう。とくにオブジェクト間の処理の流れをシーケンス図にして整理するセクションについては、とてもわかりやすい。積極的にシーケンス図を活用すべきである。
しかし、いくつかネックとなるポイントも存在する。1/5 のボリュームはオブジェクトをどうテストするかという観点でやや薄まった内容で記載さてれているし、翻訳も少し不自然さはあるかもしれない。また、適応されているデザインパターンもごく一部で網羅しているわけではなく、思ったよりボリュームが足りないというのが率直な感想。最後に、本書は自転車のメカニズムの構造に興味がない人は合わないかもしれないという点も補足しておく。★★★★☆ 4/5
- 投稿日:2020-02-20T11:05:30+09:00
[Ruby] irb や pry で例外時のバックトレースを表示する
TL;DR
irb や pry で例外時のバックトレースを表示するには
バージョン情報
$ ruby -v ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18] $ bin/rails -v Rails 6.0.1実例
以下のモデルを作成した。
app/models/hunter.rbclass Hunter < ApplicationRecord validates name, presence: true end早速
bin/rails c
で動作を確認してみると謎のエラーが発生した。irb(main):008:0> Hunter.create!(name: 'クラピカ') Traceback (most recent call last): 1: from (irb):8 NoMethodError (undefined method `Hunter' for #<Hunter:0x00007f8a322f52d8>)Hunter#Hunter というメソッドがないって言われる……。なんだこの HUNTER×HUNTER みたいなへんちくりんなエラーは ?
それにしても、他に情報が何も出力されないのでエラーの原因がさっぱりわからない。こういうときはメソッドの呼び出し状況であるバックトレースを出力する。Ruby では $@ という特殊変数にバックトレースを参照することができる。
irb(main):002:0> puts $@ /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!' (irb):8:in `irb_binding' # 略 -e:1:in `<main>' => nilバックトレースに
validate
というキーワードがあったのでバリデーション周りを疑ってみる。すると本来シンボルであるはずの validates の引数がシンボルになっていなかったのが原因だと判明した!app/models/hunter.rbclass Hunter < ApplicationRecord # name が self.name すなわち Hunter.name と解釈されて "Hunter" を返していた。 # name を :name に修正した。 validates :name, presence: true endしかしこの方法はちょっと不便だ。もう一度
$@
を参照しようとすると空になってしまう。irb(main):002:0> puts $@ /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!' (irb):8:in `irb_binding' # 略 -e:1:in `<main>' => nil irb(main):003:0> puts $@ => nilそこで irb をより強力にしたツールである pry を使う。Gemfile に
pry-rails
を追加して bundle install しておく。Gemfilegroup :development, :test do gem 'pry-rails' end
bin/rails c
で動作を確認してみる。[1] pry(main)> Hunter.create!(name: 'クラピカ') NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> from /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
wtf
と入力すると、例外のバックトレースが表示される。すべてではなく先頭から数行が表示される。[2] pry(main)> wtf Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' 4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda'もう一度入力してもバックトレースが表示される。おもしろいことに
wtf!
やwtf!!?
のようにwtf
の後に!
や?
をつけると、つけた量に比例して表示されるバックトレースの行数が増える。[3] pry(main)> wtf! Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' 4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda' 5: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:201:in `block (2 levels) in halting' 6: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:607:in `block (2 levels) in default_terminator' 7: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `catch' 8: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `block in default_terminator' 9: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:202:in `block in halting'バックトレースを最後まで表示したい場合は
wtf -v
と入力する。[4] pry(main)> wtf -v Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 73: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 74: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 75: -e:1:in `<main>'参考
- 投稿日:2020-02-20T11:05:30+09:00
[Ruby][初心者向け] コンソールで例外が発生したときは、バックトレースを表示して原因を調べよう
typo など特に凡ミス対策に有効です ?
TL;DR
- コンソール (irb や pry) で例外が発生しても、バックトレースが表示されないので原因がわからないことがある。
- コンソールで例外時のバックトレースを表示するには
バージョン情報
$ ruby -v ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18] $ bin/rails -v Rails 6.0.1実例
以下のモデルを作成した。
app/models/hunter.rbclass Hunter < ApplicationRecord validates name, presence: true end早速
bin/rails c
(irb) で動作を確認してみると謎のエラーが発生した。irb(main):008:0> Hunter.create!(name: 'クラピカ') Traceback (most recent call last): 1: from (irb):8 NoMethodError (undefined method `Hunter' for #<Hunter:0x00007f8a322f52d8>)Hunter#Hunter というメソッドがないって言われる……。なんだこの HUNTER×HUNTER みたいなへんちくりんなエラーは ?
それにしても、他に情報が何も出力されないのでエラーの原因がさっぱりわからない。こういうときはメソッドの呼び出し状況であるバックトレースを出力する。Ruby では $@ という特殊変数でバックトレースを参照することができる。
irb(main):002:0> puts $@ /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!' (irb):8:in `irb_binding' # 略 -e:1:in `<main>' => nilバックトレースに
validate
というキーワードがあったのでバリデーション周りを疑ってみる。すると本来シンボルであるはずの validates の引数がシンボルになっていなかったのが原因だと判明した!app/models/hunter.rbclass Hunter < ApplicationRecord # name が self.name すなわち Hunter.name と解釈されて "Hunter" を返していた。 # name を :name に修正した。 validates :name, presence: true endしかしこの方法はちょっと不便だ。もう一度
$@
を参照しようとすると空になってしまう。irb(main):002:0> puts $@ /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!' (irb):8:in `irb_binding' # 略 -e:1:in `<main>' => nil irb(main):003:0> puts $@ => nilそこで irb をより強力にしたツールである pry を使う。Gemfile に
pry-rails
を追加して bundle install しておく。Gemfilegroup :development, :test do gem 'pry-rails' end
bin/rails c
で動作を確認してみる。[1] pry(main)> Hunter.create!(name: 'クラピカ') NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> from /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
wtf
と入力すると、例外のバックトレースが表示される。すべてではなく先頭から数行が表示される。[2] pry(main)> wtf Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' 4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda'もう一度入力してもバックトレースが表示される。おもしろいことに
wtf!
やwtf!!?
のようにwtf
の後に!
や?
をつけると、つけた量に比例して表示されるバックトレースの行数が増える。[3] pry(main)> wtf! Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' 4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda' 5: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:201:in `block (2 levels) in halting' 6: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:607:in `block (2 levels) in default_terminator' 7: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `catch' 8: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `block in default_terminator' 9: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:202:in `block in halting'バックトレースを最後まで表示したい場合は
wtf -v
と入力する。[4] pry(main)> wtf -v Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088> -- 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing' 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate' 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each' 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate' # 略 73: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 74: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 75: -e:1:in `<main>'参考
- 投稿日:2020-02-20T11:02:09+09:00
ActiveAdminのTips
最近ActiveAdminを使用しているのですが
便利な反面, 仕様がわかりづらく, バグでは?と思うことが多いです.
私が躓いたところをいろいろ追加して行こうと思います.前提環境
activeadmin (1.4.3)詳細画面
if文の挙動
特定のカラムに値があったら, 表示する.
なければ表示しない. という単純な仕様shops.rbActiveAdmin.register Shop do show do panel "求人(Job)情報" do attributes_table_for shop.job do #① idがあれば表示 if resource.job.job_img1_id.present? row :job_img1_id end #② idがなければ表示 if resource.job.job_img2_id.nil? row :job_img2_id end #③ idがあれば表示 (ここ挙動がおかしい!!バグ!!) if :job_img3_id.present? row :job_img3_id end #④ idがなければ表示 (ここ挙動がおかしい!!バグ!!) if :job_img4_id.nil? row :job_img4_id end end end end end今 job_img[1-4]_id は値がないnull(nil)です.
つまり、写真2と写真4だけが表示されているのが正しい挙動です.実際の画面を見ると
写真1 写真4 => 非表示
写真2 写真3 => 表示
(上下のメイン写真コメントと写真5はここでは無関係)ここで
写真3は写真1同様に非表示とならなければなりません.同様に
写真4は写真2同様に表示とならなければなりません.
ここでバグがありました.結論
:シンボル使用した時と, resouceから呼び出した時で, 挙動が正反対になっています.
正しい挙動はresouceを使用した時です.
ifの引数にシンボリックの使用は推奨されません.
- 投稿日:2020-02-20T11:02:09+09:00
ActiveAdminのTips& Bugs
最近ActiveAdminを使用しているのですが
便利な反面, 仕様がわかりづらく, バグでは?と思うことが多いです.
私が躓いたところをいろいろ追加して行こうと思います.
日本語の記事が見つからなかったので, 書きました.前提環境
activeadmin (1.4.3)一覧画面(Index)
カスタムフィルター(子テーブルの要素をFilter対象とする)
前提
親(Shop) : 子(Job) = 1 : N 関係の時,
親要素に子要素をJOINして, DBのビューのような使い方をしている.実現したいこと
子(Job)の特定のカラム(ここでは:published)の値でフィルター機能を作りたい
ソースコード
app/models/shop.rbclass Shop < ActiveRecord::Base has_many :jobs, dependent: :destroy # ActiveAdmin用のscope scope :join_jobs, -> { joins(:jobs)} scope :active_admin_custom_filter, -> (filter) { # gem ransackerのバグのため、ここで数値へ変換 # filter = filter == "掲載中" ? 1 :0 self.where('jobs.published = ? ',filter) } # 別にprivateでなくても良いが private # ActiveAdmin用のfilterカスタマイズ def self.ransackable_scopes(auth_object = nil) [:active_admin_custom_filter] endapp/admin/shops.rbActiveAdmin.register Shop do # gemのransackerにバグがあり, 自作scopeに数値を渡せない. initilizarの要修正 filter :active_admin_custom_filter, label: "掲載(求)", as: :select, collection: proc{ [%(掲載中 1), %w(掲載停止 0)] } # initilizarを修正していない時はこっち # filter :active_admin_custom_filter, label: "掲載(求)", as: :select, collection: proc{ [%(掲載中 掲載中), %w(掲載停止 掲載停止)] } # カスタムフィルターだと, as: を指定する必要がある. よって, 下では表示すらされない # filter :active_admin_custom_filter, label: "掲載(求) # override controller do def scoped_collection end_of_association_chain.join_jobs end end endgem ranscakerの不具合はこちらの記事を参照させていただきました.
画面とまとめ
これで親(Shop)にはない,子(Job)の要素(publishedカラム)でfilterができました.
詳細画面(Show)
if文の挙動
特定のカラムに値があったら, 表示する.
なければ表示しない. という単純な仕様app/admin/shops.rbActiveAdmin.register Shop do show do panel "求人(Job)情報" do attributes_table_for shop.job do #① idがあれば表示 if resource.job.job_img1_id.present? row :job_img1_id end #② idがなければ表示 if resource.job.job_img2_id.nil? row :job_img2_id end #③ idがあれば表示 (ここ挙動がおかしい!!バグ!!) if :job_img3_id.present? row :job_img3_id end #④ idがなければ表示 (ここ挙動がおかしい!!バグ!!) if :job_img4_id.nil? row :job_img4_id end end end end end今 job_img[1-4]_id は値がないnull(nil)です.
つまり、写真2と写真4だけが表示されているのが正しい挙動です.実際の画面を見ると
写真1 写真4 => 非表示
写真2 写真3 => 表示
(上下のメイン写真コメントと写真5はここでは無関係)ここで
写真3は写真1同様に非表示とならなければなりません.同様に
写真4は写真2同様に表示とならなければなりません.
ここでバグがありました.結論
:シンボル使用した時と, resouceから呼び出した時で, 挙動が正反対になっています.
正しい挙動はresouceを使用した時です.
ifの引数にシンボリックの使用は推奨されません.
- 投稿日:2020-02-20T10:41:24+09:00
Rubyで配列の要素を検索置換する方法
WEB企業の研修中に学んだ事のアウトプットです。
配列の要素を検索し、その要素を別のオブジェクトで置換する方法です。一般的な方法
array = ["foo","bar","baz"] # arrayから"bar"を検索して"hoge"で置換します。 array.map!{|x| x=="bar" ? "hoge" : x} puts array #=> ["foo","hoge","baz"]微妙な方法
※この方法でも検索置換できますが、検索ワードが配列に存在しない場合エラーになります。
array = ["foo","bar","baz"] # arrayから"bar"を検索して"hoge"で置換します。 array[array.index("bar")] = "hoge" puts array #=> ["foo","hoge","baz"]
- 投稿日:2020-02-20T08:14:50+09:00
RailsアプリをHerokuにデプロイしたらクラッシュしてたときの対処法
開発環境では問題なく動いていたアプリが、満を持してデプロイしたときにクラッシュしてたら精神的に結構きますよね
正直、辛い。
今回は、Rails5のアプリをHerokuにデプロイした際にクラッシュを起こしていたので、そのとき取った行動をメモとして残しておきます。
エラー画面
We're sorry, but something went wrong.
If you are the application owner check the logs for more information.日本語でおk(死語)
このエラー文自体を検索し、色んなエラー時対応の記事を読み込んでいくと、
何にしろログを見なっせ
(書いてある)ということなので、
$ heroku logs
を叩きました。こちらの記事はとても参考になりました。
Qiita/[Ruby on Rails Tutorial]Herokuにデプロイ後Application error[H10 (App crashed)]が発生した時の対処法
$ heroku logs 2020-02-19T13:24:10.854459+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/runner.rb:138:in `load_and_bind' 2020-02-19T13:24:10.854460+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/single.rb:87:in `run' 2020-02-19T13:24:10.854460+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/launcher.rb:174:in `run' 2020-02-19T13:24:10.854461+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/cli.rb:77:in `run' 2020-02-19T13:24:10.854461+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/bin/puma:10:in `<top (required)>' 2020-02-19T13:24:10.854462+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/bin/puma:23:in `load' 2020-02-19T13:24:10.854462+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/bin/puma:23:in `<top (required)>' 2020-02-19T13:24:10.941495+00:00 heroku[web.1]: State changed from starting to crashed 2020-02-19T13:24:10.946163+00:00 heroku[web.1]: State changed from crashed to starting 2020-02-19T13:24:10.919655+00:00 heroku[web.1]: Process exited with status 1 2020-02-19T13:24:14.912178+00:00 heroku[web.1]: Starting process with command `bundle exec puma -C config/puma.rb` 2020-02-19T13:24:17.577966+00:00 app[web.1]: Puma starting in single mode... 2020-02-19T13:24:17.587312+00:00 app[web.1]: * Version 3.9.1 (ruby 2.5.7-p206), codename: Private Caller 2020-02-19T13:24:17.587332+00:00 app[web.1]: * Min threads: 5, max threads: 5 2020-02-19T13:24:17.587335+00:00 app[web.1]: * Environment: production 2020-02-19T13:24:19.870761+00:00 app[web.1]: ! Unable to load application: LoadError: No such file to load -- URI.rb 2020-02-19T13:24:19.870872+00:00 app[web.1]: bundler: failed to load command: puma (/app/vendor/bundle/ruby/2.5.0/bin/puma) 2020-02-19T13:24:19.870924+00:00 app[web.1]: LoadError: No such file to load -- URI.rb 2020-02-19T13:24:19.870926+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `require' 2020-02-19T13:24:19.870926+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `block in require' 2020-02-19T13:24:19.870927+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:in `load_dependency' 2020-02-19T13:24:19.870927+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `require' 2020-02-19T13:24:19.870928+00:00 app[web.1]: /app/app/controllers/application_controller.rb:5:in `<class:ApplicationController>' 2020-02-19T13:24:19.870928+00:00 app[web.1]: /app/app/controllers/application_controller.rb:1:in `<top (required)>' 2020-02-19T13:24:19.870929+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `require' 2020-02-19T13:24:19.870929+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `block in require' 2020-02-19T13:24:19.870930+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:in `load_dependency' 2020-02-19T13:24:19.870930+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in `require' 2020-02-19T13:24:19.870930+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:379:in `block in require_or_load' 2020-02-19T13:24:19.870931+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:36:in `block in load_interlock' 2020-02-19T13:24:19.870931+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies/interlock.rb:12:in `block in loading' 2020-02-19T13:24:19.870932+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/concurrency/share_lock.rb:149:in `exclusive' 2020-02-19T13:24:19.870932+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies/interlock.rb:11:in `loading' 2020-02-19T13:24:19.870933+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:36:in `load_interlock' 2020-02-19T13:24:19.870933+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:357:in `require_or_load' 2020-02-19T13:24:19.870934+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:335:in `depend_on' 2020-02-19T13:24:19.870934+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:251:in `require_dependency' 2020-02-19T13:24:19.870934+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:476:in `block (2 levels) in eager_load!' 2020-02-19T13:24:19.870935+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:475:in `each' 2020-02-19T13:24:19.870935+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:475:in `block in eager_load!' 2020-02-19T13:24:19.870935+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:473:in `each' 2020-02-19T13:24:19.870936+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:473:in `eager_load!' 2020-02-19T13:24:19.870936+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/engine.rb:354:in `eager_load!' 2020-02-19T13:24:19.870937+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/application/finisher.rb:67:in `each' 2020-02-19T13:24:19.870937+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/application/finisher.rb:67:in `block in <module:Finisher>' 2020-02-19T13:24:19.870937+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/initializable.rb:30:in `instance_exec' 2020-02-19T13:24:19.870938+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/initializable.rb:30:in `run' 2020-02-19T13:24:19.870938+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/initializable.rb:59:in `block in run_initializers' 2020-02-19T13:24:19.870939+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:228:in `block in tsort_each' 2020-02-19T13:24:19.870939+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component' 2020-02-19T13:24:19.870939+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:431:in `each_strongly_connected_component_from' 2020-02-19T13:24:19.870940+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:349:in `block in each_strongly_connected_component' 2020-02-19T13:24:19.870940+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:347:in `each' 2020-02-19T13:24:19.870941+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:347:in `call' 2020-02-19T13:24:19.870941+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:347:in `each_strongly_connected_component' 2020-02-19T13:24:19.870942+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:226:in `tsort_each' 2020-02-19T13:24:19.870942+00:00 app[web.1]: /app/vendor/ruby-2.5.7/lib/ruby/2.5.0/tsort.rb:205:in `tsort_each' 2020-02-19T13:24:19.870947+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/initializable.rb:58:in `run_initializers' 2020-02-19T13:24:19.870947+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/railties-5.1.6/lib/rails/application.rb:353:in `initialize!' 2020-02-19T13:24:19.870948+00:00 app[web.1]: /app/config/environment.rb:5:in `<top (required)>' 2020-02-19T13:24:19.870948+00:00 app[web.1]: config.ru:3:in `require_relative' 2020-02-19T13:24:19.870948+00:00 app[web.1]: config.ru:3:in `block in <main>' 2020-02-19T13:24:19.870949+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:116:in `eval' 2020-02-19T13:24:19.870949+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:116:in `new_from_string' 2020-02-19T13:24:19.870950+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:105:in `load_file' 2020-02-19T13:24:19.870950+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:66:in `parse_file' 2020-02-19T13:24:19.870951+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/configuration.rb:313:in `load_rackup' 2020-02-19T13:24:19.870951+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/configuration.rb:242:in `app' 2020-02-19T13:24:19.870951+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/runner.rb:138:in `load_and_bind' 2020-02-19T13:24:19.870952+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/single.rb:87:in `run' 2020-02-19T13:24:19.870952+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/launcher.rb:174:in `run' 2020-02-19T13:24:19.870952+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/lib/puma/cli.rb:77:in `run' 2020-02-19T13:24:19.870952+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/gems/puma-3.9.1/bin/puma:10:in `<top (required)>' 2020-02-19T13:24:19.870953+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/bin/puma:23:in `load' 2020-02-19T13:24:19.870953+00:00 app[web.1]: /app/vendor/bundle/ruby/2.5.0/bin/puma:23:in `<top (required)>' 2020-02-19T13:24:20.204439+00:00 heroku[web.1]: State changed from starting to crashed 2020-02-19T13:24:20.185683+00:00 heroku[web.1]: Process exited with status 1 2020-02-19T13:24:21.120419+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=example.herokuapp.com request_id=eb4b6551-949a-4693-9f76-2b0bcd0e92dd fwd="219.100.188.52" dyno= connect= service= status=503 bytes= protocol=https心折れそう
折れてました。
辛かったので、エラー文の一番最後にあった
heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/"
を、エラーコード記載されてるし後はグーグル先生がどうにかしてくれるだろうと脳死で検索しました。結果的に分かったのは、
エラー文見ろ
厳しい!!!
目から溢れる汁で滲む画面を読み進めたところ、次の部分に目が留まる(とはいっても序盤の方)。
2020-02-19T13:24:19.870761+00:00 app[web.1]: ! Unable to load application: LoadError: No such file to load -- URI.rb 2020-02-19T13:24:19.870872+00:00 app[web.1]: bundler: failed to load command: puma (/app/vendor/bundle/ruby/2.5.0/bin/puma) 2020-02-19T13:24:19.870924+00:00 app[web.1]: LoadError: No such file to load -- URI.rbご丁寧に
!
までつけてある。ここでピーンと来て、そういえばネットから次のコードをコピペしたときに、
example_controller.rbrequire 'net/https' require 'uri' # 'URI'と記載していたで実行したところ、
uriなんてねえよバーカ!
と怒られたので、
'uri'
=>'URI'
と訂正したことを思い出しました。お ま え か。
その後、正しく
require 'uri'
と訂正すると無事動いてくれました。エラー文を読もう(結論)
心折れかかったら息抜きも忘れないでください。
- 投稿日:2020-02-20T00:58:47+09:00
Ruby on Rails アソシエーションの応用 class_name 【一つのモデルを複数に分岐する】
忘れているかもしれないので、
まずは基本から復習していきましょう!!基本(1対多)
userが複数の商品(products)を保持している関係だとしたら、
user.rbclass User < ApplicationRecord has_many :products endproductsはuserに保持されているので、
product.rbclass Product < ApplicationRecord belongs_to :user enduserというフォルダに、複数のproductファイルがある感覚と同じ。
だからuserは単数形、productは複数形
productは親フォルダのuserに入っているから、belongs_to :user
userフォルダはたくさんのproductを持っているから、 has_many :products応用(1対多): class_name
じゃあ、productsを保持するuserが、販売者(seller)・購入者(buyer)に分ける場合はどうしましょうか?
seller・buyerにそれぞれモデルは必要ありません。userモデルを分けてあげれば大丈夫です。じゃないとIDが変わって逆に大変ですから。userはproductsを複数保有しているので同じです。
(次にやります。)user.rbclass User < ApplicationRecord has_many :products endproductsに紐づくuserを"seller"と"buyer"に分けたいので、下記ようにします。
product.rbclass Product < ApplicationRecord belongs_to :seller, class_name: "User", foreign_key: "seller_id" belongs_to :buyer, class_name: "User", foreign_key: "buyer_id" end「なんじゃこりゃ!!」、となったと思います。要点を抑えたら簡単です。
では解説していきます。STEP1 モデル名は変えられる。
基礎だと下記のように、ProductはUserに紐づいていました。
product.rbclass Product < ApplicationRecord belongs_to :user endbelongs_to :userと記述されていますが、この"user"という名前を変えられます。
「userじゃなくて、ownerに変えたいなあ??」
このように名前を変えたい場合にclass_nameを使います。product.rbclass Product < ApplicationRecord belongs_to :owner, class_name: "User" # belongs_to :userと同じです。 # 元はUserモデルだけど(class_name: "User")、ownerって表示に変えますわ(belongs_to :owner) endSTEP2: Userモデルを分ける
1つだとSTEP1だけで変えられます(まあ、変える必要ないんだけど)。
では、userをsellerとbuyerと2つに分けたい場合、どうすればいいのでしょうか?まずはproductsテーブルをみてください。
productレコードのカラムに"buyer_id(user_id)"と"seller_id(user_id)"があります
このカラムに入れるidを元にuserをsellerとbuyerに分けています。product.rbclass Product < ApplicationRecord belongs_to :seller, class_name: "User", foreign_key: "seller_id" # belongs_to :seller, class_name: "User" = (Productに紐づく) Userモデルをsellerと定義するわ。 # foreign_key: "seller_id" = user_idはProductレコードの『seller_idカラム』のid番号を使うわ belongs_to :buyer, class_name: "User", foreign_key: "buyer_id" # belongs_to :buyer, class_name: "User" = (Productに紐づく) Userモデルをbuyerと定義するわ。 # foreign_key: "seller_id" = user_idはProductレコードの『buyer_idカラム』のid番号を使うわ endこれで二つに分けられました。
カラムに紐づくid番号で分けたあげた分けです。STEP3: Productを複数に分ける
販売中、売却済み、購入した商品に分けます。
user.rbclass User < ApplicationRecord # 全部取得 has_many :products # 販売中 has_many :selling_products, class_name: "Product", foreign_key: "seller_id", -> { where("buyer_id is NULL") } # Productモデル名を selling_productsに定義するわ = has_many :selling_products, class_name: "Product" # productレコードの”seller_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "seller_id" ( userはhas_many: productsだから ) # でも、buyer_idが入っていないproductだけにする = -> { where("buyer_id is NULL") } # 買った商品 has_many :bought_products, class_name: "Product", foreign_key: "buyer_id" # Productモデル名を bought_productsに定義するわ = has_many :bought_products, class_name: "Product" # productレコードの”buyer_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "buyer_id" ( userはhas_many: productsだから ) # 売却済み商品 has_many :sold_products, class_name: "Product", foreign_key: "seller_id", -> { where("buyer_id is not NULL") } # Productモデル名を sold_productsに定義するわ = has_many :selling_products, class_name: "Product" # productレコードの”seller_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "seller_id" ( userはhas_many: productsだから ) # でも、buyer_idが入ってるproductだけにする = -> { where("buyer_id is not NULL") } endまとめ
class_nameでモデルを分ける際は、
まとめhas_many :〜側のモデルのカラムを使って分ける。 # 今回だと has_many :products # productにuser_idを紐づけるので、これを使って分ける。 # 親元のuserのカラムにproduct_idは入れないので、userのカラムを使って分けることはできない。 まとめ: 1対多なら、 『多』のカラムを使って分けよう ( foreign_key: )参考リンク
- 投稿日:2020-02-20T00:47:39+09:00
Railsでブログアプリケーションの作成時に、postを作成するだけでからのコメントが表示されるのを解消する。
発生した問題
タイトルにもある通り、railsで定番のブログのようなアプリを作っているときに、投稿を作成しそれの詳細をクリックしたらみられるようにshow.html.erbに記述。comment機能も追加した。しかし、投稿を作成するだけで、空のコメントが表示され、削除しようとするとRouting errorになる。
解決策
投稿詳細ページ(筆者はshow.html.erb)で、以下のように表示していた。
show.html.erb<div class="p-comment__list mx-auto"> <div class="p-comment__listTitle">コメント</div> <%= render @post.comments %> </div>それを、
show.html.erb<div class="p-comment__list mx-auto"> <div class="p-comment__listTitle">コメント</div> <%= render @post.comments.select(&:persisted?) %> </div>と変更した。
違いに気づいていただけただろうか。@post.commentsを@post.comments.select(&:persisted?)に変更した。直った!!!!!!!
参考URL
https://stackoverflow.com/questions/36680890/rails-empty-comment-on-every-new-post
- 投稿日:2020-02-20T00:09:46+09:00
Rubyの例外について無知だったのでざっくりとまとめた
Rubyで例外処理を行うときにわからないことが多すぎたので調べた。
シンプルに
シンプルに
begin
とrescue
を使うパターン。raise
を使うと意図的に例外を出すことができる。
raise
で以下のように例外を出した場合は、例外の種類はRuntimeError
となる。begin raise "例外を発生させたい" rescue => exception puts exception.class puts exception.message puts exception.backtrace end実行結果
RuntimeError 例外を発生させたい test.rb:2:in `<main>'
raise
でRuntimeError
以外のエラーを出したいときには以下のように記述する。同時にメッセージを登録することができる。begin raise StandardError.new('例外を発生させたい') rescue => exception puts exception.class puts exception.message puts exception.backtrace end実行結果
StandardError 例外を発生させたい test.rb:2:in `<main>'関数内での例外処理
関数内で例外処理を行いたい場合は以下のように記述する。関数内の場合は、
begin
のブロックを利用する必要がない。def test raise StandardError.new('例外を発生させたい') rescue => exception puts exception.class puts exception.message puts exception.backtrace end test()実行結果
StandardError 例外を発生させたい test.rb:2:in `test' test.rb:9:in `<main>'関数内の関数で例外が発生した場合には外側の関数で捕捉される。
def exception raise "関数内での例外" end def test exception() rescue => exception puts exception.class puts exception.message end test()実行結果
RuntimeError 関数内での例外複数の例外
エラーの種類により処理を分けることができる。以下の例では
StandardError
とRangeError
の時は上のrescue
、それ以外の場合は下のrescue
で捕捉される。begin raise StandardError rescue StandardError, RangeError => exception puts exception.class rescue => exception puts exception.class end実行結果
StandardError
ZeroDivisionError
を発生させるbegin 1/ 0 rescue StandardError, RangeError => exception puts exception.class rescue => exception puts exception.class end実行結果
ZeroDivisionError独自のエラー
StandardError
を継承し、独自のエラークラスを作成することができる。class MyError < StandardError def initialize(msg="Error Message") super end end begin raise MyError.new("エラーです") rescue => exception puts exception.class puts exception.message endMyError エラーですまとめ
ざっくりとまとめた。雰囲気は掴めた気がする。