- 投稿日:2020-06-02T23:42:01+09:00
Rubyの『クラス』関係の問題を集めてみて解いてみた。
Rubyのクラスが分からない
チェリー本を読んでいざアウトプットしていこうと思ったものの、自分でプログラムを作るとなると中々解けずに難しい。。。
そんな僕と同じ悩みを抱えている方のために基礎問題を集めてみました。
基礎問題と言えど正直、曖昧な知識のままこの問題を解いていくと分からないことがあります。
出来れば答えを見ずに進めていくのが良いと思いますが、考えてもどうしても分からない場合は記事の下の方に回答を書いておきますので参考にして下さい。
そして、回答を読んでも分からないと言うことが僕自身ありましたので、分からなかった点まで記載していきます。
問題(3問)
①クラス変数とクラスメソッドについて
sample.rbclass Car def self.run @@count += 1 end def count @@count end end car1 = Car.new car1.run car2 = Car.new car2.run car1.run puts Car.countこちらの記事の問題を参照しました。
●<問題>
上のプログラムは実行するとエラーが出ます。
ある箇所を修正して期待通りの出力ができる様にソースを変更してください。(期待出力)
・インスタンスメソッドrun
を呼ぶとクラスの共有カウンタが1ずつ増加する。
・クラスメソッドcount
を呼ぶと現在のカウンタの値が返される。3と表示されればオッケーです。
●<ヒント>
以下の記事が、この問題を解く上で非常に参考になりました。
https://qiita.com/mogulla3/items/cd4d6e188c34c6819709②特異メソッド
この記事を引用させていただきました。
food.rbclass Food def eat puts "I like." end end natto = Food.new() wasabi = Food.new() karaage = Food.new() natto.eat #=>I like. wasabi.eat #=>I don't like. karaage.eat #=>I love.●<問題>
コメントアウト通りの出力になる様にコードを変えてください。③Musicクラスを継承したRapクラスを定義する
こちらの記事を参照しました。
●<問題>
Rapクラスへ記述するコードを下記の出力結果から予測してください。sample.rbclass Music def mc puts "This is #{@genre} of #{self.class.to_s}" end def initialize(genre) @genre = genre end end Rap.new("mc-battle").mc(出力例)
This is mc-battle of Rap Yo, mic check 1, 2.ー※※※※※※※※※※※解答※※※※※※※※※※※ー
①クラス変数とクラスメソッドについて
クラス変数とクラスメソッドの使い方を理解していないと解けないですね。
●<クラス変数>
- クラスとそのインスタンスがスコープになる
- 定数と似ているがクラス変数は何度でも値を変更できる点で異なる
- クラスメソッド、インスタンスメソッド、クラス定義式内でアクセス可能
以下の記事が参考で、この問題を解く上で非常に参考になりました。
https://qiita.com/mogulla3/items/cd4d6e188c34c6819709まず、見るべき点は2、6行目です。
sample.rbclass Car def self.run #2行目 @@count += 1 end def count #6行目 @@count end end car1 = Car.new car1.run car2 = Car.new car2.run car1.run puts Car.count気づくことはなかったでしょうか?
最後の行を見てください。
puts Car.count
これは、Carクラスcountメソッドをそび出しているみたいですが、おかしくありませんか?
クラスをそのまま呼び出す際は、クラスメソッド出なければいけません。
修正すると、
sample.rbclass Car def self.run #2行目 @@count += 1 end def self.count #6行目 @@count end end #-中略- puts Car.count #最後の行そして、2行目もおかしいですね。
こちらはインスタンスメソッドにしなければいけません。
sample.rbclass Car def run #2行目/def self.runから変更 @@count += 1 end end car1 = Car.new car1.runなぜなら、classのそとでは
car1
とインスタンスを作成しているからそのインスタンスを呼び出すためのメソッドとして、インスタンスメソッドにしなければいけません。しかしこれで終わりではありません。
クラス変数
@@count
が定義されていません。sample.rbclass Car @@count = 0 #クラス変数の定義 def run #クラスメソッド @@count += 1 #@@countはクラス変数 end def self.count #インスタンスメソッド @@count end end car1 = Car.new car1.run car2 = Car.new car2.run car1.run puts Car.count # => $ ruby sample.rb # => 3これでオッケーです。
②特異メソッド
そもそも、特異メソッドとは?
1つのインスタンス固有のメソッドのことを指します。特異メソッドは、
def オブジェクト名.メソッド名
で定義できます。
https://qiita.com/k-penguin-sato/items/d637dced7af32e4ec7c0よって、
food.rbclass Food def eat puts "I like." end end natto = Food.new() wasabi = Food.new() karaage = Food.new() #--追加--↓ def wasabi.eat puts "I don't like." end def karaage.eat puts "I love." end #--追加--↑ natto.eat wasabi.eat karaage.eat同じクラスのインスタンスであるオブジェクトに、同じ名前の動作が異なるメソッドを定義します。
これが特異メソッドで、これはクラスに対してではなくクラスからできたインスタンスに対してのメソッドになります。
よってそれぞれのメソッドからの出力ができます。
(結果)
I like. I don't like. I love.③Musicクラスを継承したRapクラスを定義する
sample.rbclass Music def mc puts "This is #{@genre} of #{self.class.to_s}" end def initialize(genre) @genre = genre end end Rap.new("mc-battle").mc・
self.class.to_s
:Rap.new
の様に作られたインスタンス自体のクラス名を文字列に変換する。では、
Rapクラス
と、を作っていきます。sample.rb#--中略-- class Rap < Music end出力文字を見てください。
Yo, mic check 1, 2.
Musicクラスでは定義されていない出力ですので、Rapクラスで出力していきます。
最後の行の
Rap.new("mc-battle").mc
を見てみると、メソッドはmc
が使われていますので、記載していきます。sample.rb#--中略-- class Rap < Music def mc end end
Musicクラス
を継承しているので必要な部分を記載するとsample.rb#--中略-- class Rap < Music def mc puts "Yo, mic check 1, 2." end endしかしこれで終わりではないです。
まだ、現時点ではMusicクラスの呼び出しができていません。
どうすればいいでしょうか?
「super」メソッドを実行します。
superメソッドは、スーパークラスの中でその呼び出されたメソッドと同じメソッド名を持つメソッドを探して実行します。
それでは、書き換えると
sample.rbclass Music def mc puts "This is #{@genre} of #{self.class.to_s}" end def initialize(genre) @genre = genre end end class Rap < Music def mc super #追加コード puts "Yo, mic check 1, 2." end end Rap.new("mc-battle").mc完成です。
- 投稿日:2020-06-02T22:57:33+09:00
[rails]Haml 投稿フォームについて
- 投稿日:2020-06-02T22:55:07+09:00
[rails]hamlでアイコンを表示させたい!
haml%i.fa.fa-trash下記、アイコンについて参考になる便利サイトです。
▼回転させたり、他の機能も使いたい!
【Rails】font-awesome-railsの使い方を徹底解説!▼アイコンを選びたい
Font Awesome▼色を指定したい
fontawesomeの色指定!
- 投稿日:2020-06-02T22:01:57+09:00
database.ymlファイルの主な役割を2つ述べてください
使い方はわかるけど、言葉で説明する際に
整理しておくシリーズ。・rake db:createのコマンドを実行した時に作成されるデータベースの名称を指定する。
・RailsアプリケーションがSQLサーバーにアクセスするときのソケットファイルの位置を指定する
- 投稿日:2020-06-02T21:56:35+09:00
【Rails】gemのgoogle-cloud-visionでv1.0が出たので対応してみた
以前に書いた記事でコードを書き換える必要があったので対応してみました。
gem
google-cloud-vision
をv0.x系からv1.0.0にアップデートしたら要注意です。基本的に
Migrating to google-cloud-vision 1.0
https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-vision/MIGRATING.mdに書いてあるとおりなのですが
#safe_search_detection
についてはこちらのほうがわかりやすかったです。require "google/cloud/vision" image_annotator = Google::Cloud::Vision::ImageAnnotator.newを
require "google/cloud/vision/v1" image_annotator = Google::Cloud::Vision::V1::ImageAnnotator::Client.newに書き換えました。
Google Cloud Visionについては以前にも破壊的なバージョンアップがあったような...
- 投稿日:2020-06-02T20:58:52+09:00
質問の仕方について
基礎的な事だが、せっかくスクールであった
質問の型なので、メモ書きしておきます。■解決したいこと
エラー文や、今起こっているトラブルを端的に書く■自力で調べた内容
検索エンジンを用いた際の検索ワードについてや読んだ記事のリンクを書く■仮説と検証作業の結果
検索して得た情報から立てた仮説と、その検証作業による結果を書く
- 投稿日:2020-06-02T20:36:52+09:00
【Error】編集後に画面遷移しない事象の解消法
概要
タスクの編集画面を実装し、確認のため編集を行い、ボタンを押下したのですが画面が変わらず。。。。
結果としては、「redirect_to」していなかったということでしたが、エラー解決するまでの経緯を備忘録として残します!
確認方法
【前提】
編集画面で登録ボタンを押した後は、ボタンは押下できない状況にあった。
画面遷移もされない。
①MySQLに編集データが保存されているかを確認
→
変更されている②エラー画面が出ていないのであれば、ターミナルにエラー情報が記入されているのではないかを確認
terminalNo template found for TasksController#update, rendering head :no_content Completed 204 No Content in 139ms (ActiveRecord: 3.4ms)あった
No templateって記載されてた!!③コントローラーを確認
→redirect_toが記載なし修正箇所
修正前
tasks_controller.rbdef update @task.update(task_params) if @task.valid? @task.save else flash.now[:alert] = 'タスク名を入力してください' render :index end end修正後
tasks_controller.rbdef update @task.update(task_params) if @task.valid? @task.save redirect_to group_tasks_path(@group), notice: 'タスクが変更されました' else flash.now[:alert] = 'タスク名を入力してください' render :index end end皆さま、お気をつけください
参考
エラー204に関するURLです。
https://developer.mozilla.org/ja/docs/Web/HTTP/Status/204
- 投稿日:2020-06-02T20:35:23+09:00
form_with scope
form_withのscopeについて
こんなフォームがあったけどscopeってどんな意味だってなった
ruby.rb<%= form_with scope: :session, url: sessions_path do |f| %> <%= f.text_field :name %> <%= f.submit %> <% end %>とりあえず検証ツールを見てみる
なるほどこんな働きなわけね。<form action="/sessions" method="post" data-remote="true"> <input type="text" name="session[name]"> </form>つまりscopeオプションはどんなはたらき?
spopeオブジェクトに私た値がname値のプレフィックス(接頭語)になっている
name = "session[name]"
という形でパラメータが送信されている。ってこと
どうやって受け取る?
パラメータのプレフィックスにsessionがついただけなので難しく考えることはないです
controller.rbdef create #スコープを用いて送信された値をsession[:user_id]に代入 session[:user_name] = session_params[:name] endこんな働きをしているってことですね。大したことはなかった。
本日はここまで。
form_withひとつとっても色々ありますね。一人前のエンジニアになるまであと87日
- 投稿日:2020-06-02T19:46:21+09:00
ターミナルでよく使うコマンド集(ファイル操作編)
ターミナル# カレントディレクトリのパスを表示する $ pwd 表示例→/Users/ユーザ名/Desktop/sample →print working directoryの略 # 今いるディレクトリの直下にあるファイルやフォルダの名前の一覧を表示します $ ls →listの略 #ファイルのパーミッションの確認 $ ls -l #移動したい時に使う $ cd ファイル名 change directoryの略。 #ホームディレクトリに移動する $ cd ~/ #一つ上の階層のファイルに移動する $ cd ..<移動の注意点>
ターミナル#相対パス $ cd projects #絶対パス $ cd ~/projects相対パスはフォルダ名(ファイル名)から初めて良い
絶対パスは/から始めます
- 投稿日:2020-06-02T19:30:03+09:00
[Rails] 可読性を上げるための第1歩~変数宣言の注意点~
概要
この記事は、
- プログラムのソースコードを書く際に、読みやすくするための方法を
- 特に「変数」宣言の仕方に絞って取り上げた
ものです。
動機
私もやっと3年仕事でプログラミングの経験を積んだ、というところですが、開発したり本を読んだりする中で、「読みやすいコードと読みにくいコード」を分けるポイントに、段々気付くことができるようになってきました。
「こういったポイントを早く知ってもらえば、読みにくいコードが減っていき、私も周囲の人もスムーズに気分よく開発できるようになる!」という思いでこの記事を書きました。
Why?
なぜ読みやすいソースコードを書くか
- プログラミングにおいて、ソースコードの読みやすさはとても大事
- プログラムは、書く時間よりも読まれる時間の方が圧倒的に多いとされている
- 使い捨てが確定しているソースならいいのですが、そうではないソースコードが読みにくいと、修正が大変
- 特に、他人の書いたソースコードが読みにくい場合、「やってらんないわ、もう書いた奴に直させよう...」と感じてしまう
⇒ 読みやすく書いておくことで、後々の効率化に繋げよう!
本題
項目一覧
※「4.」以外は、他のプログラミング言語についても当てはまると思います。
「そんなん知ってるよ。」という方は、是非私に色々教えてください(>_<)
1. 変数名は詳しく
変数名には、なるべく詳しい情報を盛り込みましょう!
# bad a = 1 b = 'ラプタ' c = 'きみをのせて' # good number = 1 title = 'ラプタ' song = 'きみをのせて'理由
一目で中身が分かるようにするためです。
a, b, c ... だと、代入した瞬間は中身がわかりますが、30行先でb
という変数があるとき、中身を思い出すのは一苦労です。
もう1回値を代入したところを見直さないと思い出せないかもしれません。なので、中身がはっきりわかるような名前にしましょう。
もうひと手間
より詳しい情報が変数名から読み取れるように工夫してみましょう。
# good number = 1 title = 'ラプタ' song = 'きみをのせて' # very good rank = 1 movie_title = 'ラプタ' ending_theme_song = 'きみをのせて'何に使われているのかわからない変数は、いつの間にか生まれてしまいます。
「ソースコードを書いた翌日、その変数の役割をもう思い出せない」ということは普通に起こります。なので、役割を思い出す手掛かりになる情報をなるべく盛り込みましょう。
(変数に使用する単語数は、おおむね4個くらいまでが適切とされています。)2. 使う直前に宣言する
変数は、なるべく呼び出す直前の行で宣言するようにしましょう!
# bad def play_movie main_theme_song = 'なんだっけ....(知らない)' ending_theme_song = 'きみをのせて' play_music(main_theme_song) # - - - - - - - - - - - - - - - - - # # 処理 # ending_theme_song は使われない # 20 行 # - - - - - - - - - - - - - - - - - play_music(ending_theme_song) end # good def play_movie main_theme_song = 'なんだっけ....' play_music(main_theme_song) # - - - - - - - - - - - - - - - - - # # 処理 # ending_theme_song は使われない # 20 行 # - - - - - - - - - - - - - - - - - ending_theme_song = 'きみをのせて' play_music(ending_theme_song) end理由
- 中身がわからなくなる
「1.」と似たような理由ですが、変数に入っていた値が一体何だったのか、行数が空けば空くほどわからなくなってしまいます。
近くに書いておけばすぐに確認できます。- 途中の処理で使われていないか不安になる
今回のサンプルでは、間に20行処理が挟まれています。
開発の途中でこのending_theme_song
という変数の中身を変えたり、変数を削除したり、または変数名を変えたくなる時が来たとします。
そのとき、途中の20行でこの変数が使われているかどうかを確認する必要が発生します。
もし途中で使われているのに変更を加えてしまったら、バグが発生するかもしれませんので。この2つの問題は、使用される直前で変数を宣言することで回避できます。
3. 1つの変数を複数の目的で使わない
ある変数の役割が途中から変わる....そんな実装はやめましょう!
これをされてしまうと、最悪の場合、そのソースを書いた人に聞かないと以降の修正ができないという事態にもなりかねません。# bad def play_movie theme_song = 'なんだっけ....' play_music(theme_song) theme_song = 'きみをのせて' play_music(theme_song) end # good def play_movie main_theme_song = 'なんだっけ....' play_music(main_theme_song) ending_theme_song = 'きみをのせて' play_music(ending_theme_song) endこの例では些細な問題に見えると思います。
どっちでもいいだろうと。
ですが...。理由
- どこから役割が変わったのかわからない
変数の役割が途中で変わると困るのは、処理が長いときや複雑な場合です。
入り組んだ複雑な処理の途中で変数の役割が変わってしまうと、その処理を全て読み解かないと、どこで役割が変わったのかがわかりません。
つまり、たった一つの変数に変更を加えたいだけなのに、同じ変数名が使われている処理全てを把握しなければならなくなります。- そもそも役割が変わったことに気づけない
悪夢のような状況です。
変数は通常一つの役割で使われるものなので、途中で役割が変わるなどとは想像されません。
仮に2つの用途があるとして、「片方の用途に合わせて変数の中身を変え、もう一方の用途のことは放置される」ということは十分起こり得ます。
「確認せずに修正する方が悪い」と言っても構いませんが、恨まれるでしょう。4. インスタンス変数の乱用は危険
Ruby on Rails
では、変数名の前に@
をつけて、インスタンス変数を宣言することができます。
インスタンス変数は、そのクラス(controllerなど)内であれば自由にどこからでも呼び出すことができるという便利さがあるのですが、使いすぎに注意しましょう!
基本的には、
- viewファイルで呼び出す必要のある変数だけをインスタンス変数にする
ことによってかなりマシになります。
# ---------------------------------------- # # Bad example # ---------------------------------------- # # controllers/samples_controller before_action :set_music, only: [:show] def show # 画面を開くたびに、1年以上前のmusicを削除 @old_date_range = Date.new(1900, 1, 1)..Date.today.prev_year @musics = Music.where(created_at: @old_date_range) @musics.delete_all end private def set_music() @music = Music.find_by(id: params[:id]) end # views/samples/playmusic.html.erb <div> <%= @music.title %> </div># ---------------------------------------- # # Good example # ---------------------------------------- # # controllers/samples_controller before_action :set_music, only: [:show] def show # 画面を開くたびに、1年以上前のmusicを削除 # viewファイルで使わない変数には@をつけない old_date_range = Date.new(1900, 1, 1)..Date.today.prev_year musics = Music.where(created_at: old_date_range) musics.delete_all end private def set_music() @music = Music.find_by(id: params[:id]) end # views/samples/playmusic.html.erb <div> <%= @music.title %> </div>理由
- インスタンス変数の危険なところ
- 「宣言」箇所がパッと見分からなくなりやすい
- 「使用」箇所がパッと見分からなくなりやすい
- 影響範囲が大きくなりやすい
インスタンス変数は、controller内で1度宣言されれば、そのcontroller内のどこからでも呼び出すことができます。
それはメリットではあるのですが、そのせいで、どこで宣言された変数なのか、どこで使用されている変数なのか、わからなくなることが往々にしてあります。このことを、「影響範囲が大きすぎる」などと呼んだりもします。
その結果、その変数をソースから削除したり変更する際に、影響範囲を調べるのが困難になります。
使う必要がないところでインスタンス変数を使うと、後々自分も他人も困ることになります。最後に
〇実感する前に取り組む
おそらくですが、後ろのものほど実感がわきにくいと思います。
ただ、「実感したときには時すでに遅し」です。そのときはもう、読みにくいコードに囲まれてしまい、途方に暮れているかもしれません!
〇ソースコードを読みやすくする真の目的
周りの人に開発を楽しんでもらう
読みにくいコードの修正は、誰もが嫌がります。
もしかしたら、そのシステムの担当になることすら避けられてしまうかもしれません。エンジニアの多くは、プログラミングを好きで楽しいと思って取り組んでいます。
もし、読みやすいソースのシステムなら、喜んで担当してくれるようにります。
(そういったシステムは作るのが難しく、数が少ないため....)利益を生む
後任者をイライラさせたり残業過多に追い込めば、その分できる作業が減り、残業代は増え、組織全体の損失になります。
逆に、読みやすいコードを書くことで業務時間が減り、取り組めることが増え、いずれ利益にもつながるでしょう。この記事で、可読性の向上に少しでも意義を感じてもらえれば幸いです。
Happy Coding !! (((o(゚▽゚)o)))
- 投稿日:2020-06-02T19:15:09+09:00
あともう少し…MySQLサービス起動後、Railsサーバが起動しない3
発生した背景
MySQLサービスが復旧したところで、Railsを起動すると以下のエラーが発生した。
/Users/ichikawadaisuke/projects/krown/vendor/ruby/2.5.0/gems/bootsnap-1.4.6/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require': dlopen(/Users/ichikawadaisuke/projects/krown/vendor/ruby/2.5.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib (LoadError) Referenced from: /Users/ichikawadaisuke/projects/krown/vendor/ruby/2.5.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle Reason: image not found - /Users/ichikawadaisuke/projects/krown/vendor/ruby/2.5.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle対応手順
MySQLサービスを再インストールしたため、既存のGemが動作しなくなったと判断。
Gemの再セッティングを実施する。
①以下コマンドにて原因を多角的に調査する$ bundle update $ rails s (これで復旧するかを試してみるも、Railsサーバは起動しなかった) $ bundle doctor (MySQLに紐つくような目立ったエラーは発生していない)②以下のコマンドでGemを入れ替える
$ bundle exec gem uninstall mysql2 Successfully uninstalled mysql2-0.5.2 $ bundle install --path vendor (同コマンドで改めてGemを入れなおす)③やっと…Railsが起動した…
Use Ctrl-C to stop Started GET "/" for ::1 at 2020-06-02 18:46:42 +0900 ActiveRecord::NoDatabaseError (Unknown database 'krown_development'):④あとはお決まりのコマンドを実行して、無事終了しました?
$ bundle exec rake db:create $ bundle exec rake db:migrate
- 投稿日:2020-06-02T18:51:32+09:00
has_oneについてメモ
- 投稿日:2020-06-02T18:45:15+09:00
HerokuにBugsnagを導入
Heroku × Railsです。
アドオンを追加→APIキーを取得
ダッシュボードから操作する方法と、コマンドラインから操作する方法があります。
ダッシュボードから操作する場合
- Herokuのダッシュボードにアクセス
- Resourcesタブを開く
- Add-onsの下の検索窓に'Bugsnag'と入力
- Provisionをクリック
- Settingsタブを開く
- Reveal Config Varsをクリックし、BugsnagのAPIキーを確認する
コマンドラインから操作
Heroku CLIがインストールされている状態で以下のコマンドを叩く
$ heroku addons:create bugsnag $ heroku config:get BUGSNAG_API_KEY 70d9b0852a968b1d0d0e329b5507f287 #APIキーアプリケーション側の設定
Gemfilegem 'bugsnag'$ bundle install $ rails generate bugsnag 70d9b0852a968b1d0d0e329b5507f287 # APIキー
config/initializers/bugsnag.rb
が生成される。デフォルトではAPIキーがベタ書きされているので、環境変数にしまう。dotenv
というgemを使って以下のように記述しました。config/initializers/bugsnag.rbBugsnag.configure do |config| config.api_key = ENV['BUGSNAG_API_KEY'] #修正 endproduction環境でのみ動くように修正
config/initializers/bugsnag.rbBugsnag.configure do |config| config.api_key = ENV['BUGSNAG_API_KEY'] config.notify_release_stages = ['production'] #追加 endその他
raise
等を使って自分で発生させている例外を捕捉したい場合、Bugsnag.notify(exception)
を使う。begin raise 'Something went wrong!' rescue => exception Bugsnag.notify(exception) end参考
- 投稿日:2020-06-02T18:34:31+09:00
初心者向けRailsでブログを作ってみるチュートリアルその1
これはなに?
初心者向けRailsでブログを作ってみるチュートリアルその0 の続きです。
今回はブログサービスを作ります。
では、ブログサービスの機能を分解して考えてみましょう
実際のブログサービスにはいくつか機能がありますが、今回はブログサービスと呼ぶために必要なミニマムの機能を開発しましょう。機能一覧
訪問者用機能
- 記事閲覧機能
- コメント機能
管理機能
- 管理者ログイン機能
- 記事投稿機能
この中で、次のステップから最初に最低限ブログらしいものに必要な「記事閲覧機能」を作っていこうと思います。
サイトマップ
ワイヤーフレーム
今回は最初に作る記事閲覧機能に含まれる2画面についてのワイヤーフレームを draw.io で作ってみました。
今回は、全体の機能がコンパクトなためワイヤーフレームと次回以降でやるモデリングにとどめて細かい仕様設計などはしません(実際開発者が1-3名程度のスタートアップや新規事業だともっと大雑把なワイヤーフレームしかない状態で進めてもまあまあうまくいったりします)記事一覧画面
記事詳細画面
完成版にはコメント機能をつけますが、最初の時点では省略します
チュートリアルその1まとめ
今回は、開発に移る前の設計の初期段階として何を作るのか、というところを大まかに定義しました。
次回はプロジェクトのセットアップを行います。
- 投稿日:2020-06-02T18:32:12+09:00
道のりは長い…( ´Д`)y━・~~ MySQLが起動しない事象への対応
Railsを起動するため、Gem、bundleの再設定を行いました。ようやくアプリケーションを起動することができたのですが、アプリケーションにアクセスするとエラー出力され、アプリが動きません。
非常に道のりが長いですが、1つ1つ対応を進めていきます。エラー内容:
* Listening on tcp://localhost:3000 Use Ctrl-C to stop Started GET "/" for ::1 at 2020-06-02 11:31:07 +0900 Mysql2::Error::ConnectionError (Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)): (省略)①そもそもサービスが起動していなかった。(mysql.server statusで確認)
②ログを確認すると、プロセスを起動する際にファイルのオープンに失敗している
(ichikawadaisukenoMacBook-Air.local.err )200602 11:51:16 mysqld_safe mysqld from pid file /usr/local/var/mysql/ichikawadaisukenoMacBook-Air.local.pid ended③そういえば、先日Mysqlが稼働しなかったため、homebrewコマンドでインストールしなおした経緯がある。/usr/local/Cellar配下をみると、v5.6系とv8.0が存在していた。
競合している可能性もあるので、先日追加したv8.0系はアンインストールした。④さらにリンクも再設定すれば復旧するかもしれないと考え、以下を試した。
CMD> brew unlink mysql@5.6 Unlinking /usr/local/Cellar/mysql@5.6/5.6.42... 0 symlinks removed CMD> brew link --force mysql56 Linking /usr/local/Cellar/mysql@5.6/5.6.42... 99 symlinks created⑤この後、以下のファイルで直接5.6系のサービスを起動しようとするも
/usr/local/Cellar/mysql@5.6/5.6.42/support-files/mysql.server startERROR! The server quit without updating PID file (/usr/local/var/mysql/ichikawadaisukenoMacBook-Air.local.pid).⑥出来るだけ、mysqlの再インストールは選択したくなかったのですが、時間を消耗してしまうので、以下のコマンドからまず環境をクリーンにしました。
※ファイルが存在している場合はバックアップを取得する brew uninstall mysql56 $ sudo rm -rf /usr/local/mysql $ sudo rm -rf /Library/StartupItems/MYSQL $ sudo rm -rf /Library/PreferencePanes/MySQL.prefPane $ sudo rm -rf /Library/Receipts/mysql-.pkg $ sudo rm -rf /usr/local/Cellar/mysql* $ sudo rm -rf /usr/local/bin/mysql* $ sudo rm -rf /usr/local/var/mysql* ※ここにはファイルが存在したため、bk取得 $ sudo rm -rf /usr/local/etc/my.cnf $ sudo rm -rf /usr/local/share/mysql* $ sudo rm -rf /usr/local/opt/mysql*⑦最後にインストールを実行し、希望のサービスが稼働していることを確認しました。
[\W staff@term]brew install mysql56 Updating Homebrew... ==> Downloading https://homebrew.bintray.com/bottles/mysql%405.6-5.6.47.catalina.bottle.tar.gz Already downloaded: /Users/ichikawadaisuke/Library/Caches/Homebrew/downloads/c270819d76ed326059143e1b4c6c6c0ab672e4259c328c140ec71d917babc348--mysql@5.6-5.6.47.catalina.bottle.tar.gz ==> Pouring mysql@5.6-5.6.47.catalina.bottle.tar.gz ==> /usr/local/Cellar/mysql@5.6/5.6.47/bin/mysql_install_db --verbose --user=ichikawadaisuke --basedir=/usr/local/Ce ==> Caveats A "/etc/my.cnf" from another install may interfere with a Homebrew-built server starting up correctly. MySQL is configured to only allow connections from localhost by default To connect: mysql -uroot mysql@5.6 is keg-only, which means it was not symlinked into /usr/local, because this is an alternate version of another formula. If you need to have mysql@5.6 first in your PATH run: echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrc For compilers to find mysql@5.6 you may need to set: export LDFLAGS="-L/usr/local/opt/mysql@5.6/lib" export CPPFLAGS="-I/usr/local/opt/mysql@5.6/include" To restart mysql@5.6 after an upgrade: brew services restart mysql@5.6 Or, if you don't want/need a background service you can just run: /usr/local/opt/mysql@5.6/bin/mysql.server start ==> Summary ? /usr/local/Cellar/mysql@5.6/5.6.47: 344 files, 155.2MB [\W staff@term]/usr/local/opt/mysql@5.6/bin/mysql.server status SUCCESS! MySQL running (37799)次はまたRailsが動かなくなりました…?
- 投稿日:2020-06-02T18:15:00+09:00
ターミナルでよく使うコマンド集(Rails編)
バージョンを確認するコマンド
ターミナル#Rubyのバージョンを確認するコマンド ruby --version #Railsのバージョンを確認するコマンド rails --version #RubyGemsのバージョンを確認するコマンド gem -vrails関連で使うコマンド
ターミナル#railsのサーバの起動 rails s #railsサーバの終了 control + C #コントローラの作成 rails g controller name[option] #railsアプリの作成 rails new アプリケーション名 #DBとmodelの作成 rails g model テーブル名 カラム:データ型 カラム:データ型 #railsに直接値を代入したり操作する際に使用 rails console #railsコンソールの起動 rails c #railsコンソールの終了 exitbundle関連
ターミナル#gemfileを元にgemのinstallを行う bundle install #gemのバージョンアップ bundle update
- 投稿日:2020-06-02T17:48:20+09:00
macOSをバージョンアップしたらrails s出来なくなった
問題
① macOS Catalina のバージョンを10.15.4にアップデートする
② 現在制作途中のアプリケーションのディレクトリにてrails sする
③ 以下のようなエラーが出る
Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
解決
https://nodejs.org/ja/download/current/
上記のサイトにて、最新版のNode.jsをインストールするか
ターミナルで、homebrewを用いてインストールを行う
% brew install nodejs
すると、無事rails sでローカルサーバーを起動できた。
- 投稿日:2020-06-02T17:07:16+09:00
capistranoで構築した環境でassetsの中身を1から作り直したい
なぜそんなことをしたくなったのか
capistranoのassets:precompileが走っている時にEC2がメモリ不足に陥り、インスタンスを再起動させた結果、deployが中途半端なところで終わってしまいました。
もし中途半端なコンパイル結果をもとにWebサーバーが動いて実行時エラーなんて起きたときには目も当てられないので、なんとかまっさらな状態に戻そうとしてあれこれしました。バージョン情報
rails (5.2.4.2) capistrano (3.11.0) sprockets (3.7.2) sprockets-rails (3.2.1)前提条件
current_pathはこのパスとする
- /var/www/app_name/current
shared_pathはこのパスとする
- /var/www/app_name/shared
先に結論
結論から言うと、やるべきことはこれです。
- /var/www/app_name/shared/public/assets の中身を消す
- /var/www/app_name/shared/tmp/cache/assets の中身を消す
- いつもどおりデプロイ
注意点があります。
capistranoにはdeploy:clobber_assets
のようなassetsをいかにも消しそうなコマンドが標準で用意されていますが、
これを使わずちゃんと手で消すということです。理由は後述します。説明
capistranoのディレクトリ構成
まず、capistranoによってデプロイされたサーバーの
/var/www/app_name
の中は、下記のような構造になっています。├── current (releases内の最新のディレクトリにシンボリックリンクが貼られてる) ├── releases │ ├── 20200601101105 │ ├── 20200601102714 │ └── 20200601105159 ├── repo ├── revisions.log └── sharedこのcurrentの下、つまり、releases/20200601105159の下には、あなたのプロジェクトのリポジトリにあるような構成になっているでしょう。
そこにはapp/があり、config/があり、public/があるはずです。このpublic/の下にはビルドされた静的ファイルが詰め込まれたassets/が入っている……ように見せかけて、
/var/www/app_name/current/public/assets
は/var/www/app_name/shared/assets
へのシンボリックリンクになっています。そして
/var/www/app_name/current/tmp/cache
は同様に/var/www/app_name/shared/tmp/cache
へのシンボリックリンクになっています。assets:precompileのキャッシュの仕組み
デフォルトのSprocketsは、development環境とproduction環境でtmp/cache/assetsにアセットをキャッシュします。
こう書かれている通り、tmp/cache/assetsにコンパイル結果のキャッシュがあるので、これを消します。
capistranoだと/var/www/app_name/shared/tmp/cache/assets
がこれにあたるので消します。Sprocketsのデプロイ結果のキャッシュの仕組み
assets:precompileのキャッシュとは別に、Sprocketsはデプロイ結果のファイルも取っておいてあります。
Sprocketsのコードにこんなのが書かれています。module Sprockets module Exporters # Writes a an asset file to disk class FileExporter < Exporters::Base def skip?(logger) if ::File.exist?(target) logger.debug "Skipping #{ target }, already exists" true else logger.info "Writing #{ target }" false end end def call write(target) do |file| file.write(asset.source) end end end end enddeploy:assets:precompileしているときに、標準出力でログがずらっと出てきているのを目にしていませんか? アレを実現しているのがおそらくは上のコードです。
logger.info "Writing
のところを見てください。こんな感じ:
01 I, [2020-06-01T08:56:09.691790 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/develop/application-232387090aed00e6b038… 01 I, [2020-06-01T08:56:09.692557 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/develop/application-232387090aed00e6b038… 01 I, [2020-06-01T08:56:17.418572 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/lb-0002/application-d1bedc9937772b59211a… 01 I, [2020-06-01T08:56:17.418856 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/lb-0002/application-d1bedc9937772b59211a… 01 I, [2020-06-01T08:56:21.414096 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/lb-0003/application-5a60e0a26af1e40a9188… 01 I, [2020-06-01T08:56:21.414368 #10361] INFO -- : Writing /var/www/app_name/releases/20200601085319/public/assets/lb-0003/application-5a60e0a26af1e40a9188…この
skip?
の判定に引っかかった場合。
つまり、この例だと/var/www/app_name/releases/20200601085319/public/assets/develop/application-232387090aed00e6b038…
のdigest込みのファイルが既に存在していた場合、
Sprocketsはファイルを書き出しません。なので、capistranoだと
/var/www/app_name/shared/assets
に同じファイルがあった場合、このskip?でスキップされてしまうということです。
消しておく必要がありますね。おや? 便利なコマンドがありそうだが……?
capistranoは
cap -T
で全てのコマンドを表示してくれます。
assets関係だとこんなコマンドが見つかります。cap deploy:cleanup_assets # Cleanup expired assets cap deploy:clobber_assets # Clobber assets標準で
deploy:clobber_assets
というコマンドが用意されているではありませんか!
clobberとはぶん殴るという意味です。強制的に新しいassetsにしてくれそうだ! こりゃいいや! と思って使うと、実は思ったような挙動をしてくれません。$ bundle exec cap review deploy:clobber_assets 00:00 deploy:clobber_assets 01 bundle exec rake assets:clobber 01 I, [2020-06-01T11:22:46.062204 #6756] INFO -- : Removed /var/www/app_name/releases/20200601094959/public/assets 01 Removed webpack output path directory /var/www/app_name/releases/20200601094959/public/packsいかにもassetsをディレクトリごと消してくれていそうな雰囲気ですが、よく見るとRemoveしているのはただのシンボリックリンクで、肝心の中身は消えていません。マジか。
そして、そもそもコンパイル時のキャッシュであるtmp/cacheの方は消してくれていません。このことについてはissueも上がっているようです。
なので、「結論」に書いた通り、手動でコマンドを実行して消すか、自分でコマンドを定義してやるのが良さそうです。
- 投稿日:2020-06-02T16:10:08+09:00
Railsアプリを作成してGitHubにSSHでPush
VPSのセットアップしてcapistranoでデプロイする流れで、Railsアプリを作成する必要があったので簡単にまとめます。情報量の関係上、Rails5です。安全に行きたいので。
環境
Rails 5.2.2
Ruby 2.4.1
MySQL 5.7You're on Railsを表示
$ mkdir sample_app $ cd sample_app $ touch Dockerfile docker-compose.yml Gemfile Gemfile.lockDockerfileFROM ruby:2.4.1 RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs RUN mkdir /app_name ENV APP_ROOT /app_name WORKDIR $APP_ROOT COPY ./Gemfile $APP_ROOT/Gemfile COPY ./Gemfile.lock $APP_ROOT/Gemfile.lock RUN bundle install COPY . $APP_ROOTdocker-compose.ymlversion: "3" services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root ports: - "3306:3306" web: build: . command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/app_name ports: - "3000:3000" links: - dbGemfilesource 'https://rubygems.org' gem 'rails', '5.2.2'Gemfile.lock#空
$ docker-compose run web rails new . --force --database=mysql --skip-bundle $ docker-compose build --no-cache #--no-cacheオプションが無いと、bundle installが実行されないことがあるconfig/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: db development: <<: *default database: app_name_development test: <<: *default database: app_name_test production: <<: *default database: app_name_production username: app_name password: <%= ENV['APP_NAME_DATABASE_PASSWORD'] %>$ docker-compose up
$ docker-compose run web rails db:create
http://localhost:3000 にアクセスして
Yay!You're on Rails!
を確認適当なページを作成
$ docker-compose run web rails g controller tests index
config/routes.rbRails.application.routes.draw do get 'tests/index' root to: 'tests#index' endhttp://localhost:3000 にアクセスして表示を確認
sshキーペアを作成しGitHubに登録
すでに登録済みの場合はとばしてください。
$ mkdir -p ~/.ssh/github $ cd ~/.ssh/github $ ssh-keygen -f id_rsa $ vim ~/.ssh/config~/.ssh/configHost github.com #ここが「github」だと動かないので注意 HostName github.com Port 22 IdentityFile ~/.ssh/github/id_rsa User git$ pbcopy < id_rsa.pubGitHubにリポジトリを作成
- GitHubにログイン
- 画面右上のアイコン > Your repositoriesをクリック
- Newをクリック
- リポジトリ名を入力し Create repository をクリック
Push
$ git add -A $ git commit -m "First commit" $ git remote add origin git@github.com:<githubのアカウント名>/<リポジトリ名>.git $ git push -u origin master
- 投稿日:2020-06-02T14:10:20+09:00
【Rails6】Docker+Rails6+puma+nginx+mysql【環境構築*初心者必見】
本記事の目的
本記事ではDockeを用いてRails6の環境構築を行うことを目的としています。
Rails6ではyarnというjsのパッケージ管理ツールとwebpackerがデフォルトとなっているので、Rails5の手順で環境構築を行うとエラーが出てしまいます。
よって本記事ではRails6対応の環境構築を目的としています。※Dockerそのものについてはあまり触れませんので、Docker基礎を学習してからの方が良いかもしれません。
ディレクトリ構成
環境構築する際の全体の構成を以下に示します。
ここでは「webapp」というファイルを作成してアプリケーションを作っていきます。全体構成/webapp ├── containers │ └── nginx │ ├── Dockerfile │ └── nginx.conf ├── docker-compose.yml ├── Dockerfile ├── environments │ └── db.env ├── Gemfile └── Gemfile.lockDockerfile(Rails用)
Rails用のDockerfileは以下のように記述します。
Rubyのバージョンは2.7.1を用います。ここでのポイントは、yarnとNode.jsのインストールコマンドを書いている点です。
また、本記事ではNodeのバージョンを現時点での最新14.0を使っています。
もし、アプリケーションを作成した時に「Nodeをアップグレードしてください」と出た場合、setup_14〜の数字を最新のバージョンに変えてみてください。DockerfileFROM ruby:2.7.1 # リポジトリを更新し依存モジュールをインストール RUN apt-get update -qq && \ apt-get install -y build-essential \ nodejs # yarnパッケージ管理ツールインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ 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 -y yarn # Node.jsをインストール RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - && \ apt-get install nodejs # ルート直下にwebappという名前で作業ディレクトリを作成(コンテナ内のアプリケーションディレクトリ) RUN mkdir /webapp WORKDIR /webapp # ホストのGemfileとGemfile.lockをコンテナにコピー ADD Gemfile /webapp/Gemfile ADD Gemfile.lock /webapp/Gemfile.lock # bundle installの実行 RUN bundle install # ホストのアプリケーションディレクトリ内をすべてコンテナにコピー ADD . /webapp # puma.sockを配置するディレクトリを作成 RUN mkdir -p tmp/socketsGemfile
インストールするRailsのバージョンを指定します。
Rails6に対応するように書いています。Gemfilesource 'https://rubygems.org' gem 'rails', '~> 6'Gemfile.lock
こちらはファイルの作成のみでOKで、中身は書かなくて構いません。
Dockerfile(Nginx)
DockerfileFROM nginx:1.15.8 # インクルード用のディレクトリ内を削除 RUN rm -f /etc/nginx/conf.d/* # Nginxの設定ファイルをコンテナにコピー ADD nginx.conf /etc/nginx/conf.d/webapp.conf # ビルド完了後にNginxを起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.confNginx設定ファイル
nginx.conf# プロキシ先の指定 # Nginxが受け取ったリクエストをバックエンドのpumaに送信 upstream webapp { # ソケット通信したいのでpuma.sockを指定 server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; # ドメインもしくはIPを指定 server_name example.com [or 192.168.xx.xx [or localhost]]; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # ドキュメントルートの指定 root /webapp/public; client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @webapp; keepalive_timeout 5; # リバースプロキシ関連の設定 location @webapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://webapp; } }DB情報ファイル
ここでのユーザー名やパスワードは変更して構いません。
db.envMYSQL_ROOT_PASSWORD=db_root_password MYSQL_USER=user_name MYSQL_PASSWORD=user_passworddocker-compose.yml
docker-vcompose.ymlversion: '3' services: app: build: context: . env_file: - ./environments/db.env command: bundle exec puma -C config/puma.rb volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log depends_on: - db db: image: mysql:5.7 env_file: - ./environments/db.env volumes: - db-data:/var/lib/mysql web: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp ports: - 80:80 depends_on: - app volumes: public-data: tmp-data: log-data: db-data:Railsの生成(Rails new)
Dockerコンテナ内でRailsを生成しなければいけないので、docker-compose run コマンドを使います。
ここではGemをインストールしません。$ docker-compose run --rm app rails new . --force --database=mysql --skip-bundlepuma.rbの編集
先ほどのコマンドで生成されたpuma.rbファイルを以下のように編集します。
puma.rbthreads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i threads threads_count, threads_count port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { "development" } plugin :tmp_restart app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", truedatabase.ymlの編集
Railsはデフォルトで、localhost上でDBが動作するようになっているので、hostを先ほど作成したdbに変更します。
また、ここにおける「MYSQL_USER」 と「 MYSQL_PASSWORD」 は DBファイルで定義した環境変数名を設定してくだい。database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch('MYSQL_USER') { 'root' } %> password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %> host: db development: <<: *default database: webapp_development test: <<: *default database: webapp_testイメージのビルド
docker-compose.ymlで、app・db・webのbuildに指定されているDockerfileを元にイメージを作成します。
$ docker-compose buildコンテナ起動
ビルドが完了しイメージができたら以下のコマンドでコンテナを立ち上げます
$ docker-compose up -dここでコンテナが起動しているのかを以下のコマンドを入力して確認します。
docker-compose psそうすると以下のようにコンテナの状況が見れると思います。
Name Command State Ports --------------------------------------------------------------------------- webapp_app_1 bundle exec puma -C config ... Up webapp_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp webapp_web_1 /bin/sh -c /usr/sbin/nginx ... Up 0.0.0.0:80->80/tcpwebpackerのインストール
起動したコンテナ内でwebpackerをインストールするので、以下のコマンドでインストールします。
Dockerfileになにかしら記入すれば、いちいちコマンドを入力しなくても良いとは思いますが、今回はこの方法を用います。docker-compose exec app rails webpacker:install以下のメッセージが出現すればインストール完了です。
Webpacker successfully installed ? ?DBの作成
DBの作成は必須なので、コンテナ内でDBを作成します。
docker-compose exec app rails db:create確認
以下のリンクをクリックして「You're on Rails」が表示されるか確認しましょう。
http://localhost
上手くいけば、Rails6で起動できていることが分かるかと思います。補足
localhostに変更内容が反映されていなくて、思うような結果が得られなければ、一度コンテナを閉じて、再起動させるのがいいでしょう。
コンテナ終了docker-compose downコンテナ起動docker-compose up参考サイト
以下の記事を参考にしながら環境構築をしました。
本記事だけでなく、以下のサイトも確認してみてください。①Docker + Rails + Puma + Nginx + MySQL
②DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】
③[Docker] Node.js以外のコンテナに追加でNode.jsの最新版をインストールするDockerfileの記述
- 投稿日:2020-06-02T13:08:33+09:00
カテゴリー編集機能の実装
はじめに
メルカリ風アプリを作成しています。
商品編集機能の実装を行いましたので、記載していきます。
カテゴリー機能にはancestry を使っております。
①商品出品時に登録したカテゴリーが孫カテゴリーまで表示される
②新しくカテゴリーを選択できる。
を念頭に作成しました
下のgifが完成品です。コードと解説
HAML
.listing-form-box .listing-product-detail__category = f.label 'カテゴリー', class: 'listing-default__label' %span.listing-default--require 必須 .listing-select-wrapper--edit .listing-select-wrapper--edit__parent = f.collection_select :category_id, Category.roots, :id, :name ,{prompt: "選択してください", selected: @product.category.parent.parent_id}, {class: 'listing-select-wrapper--edit__parent--select', id: 'parent_category_edit', name: "" } .listing-select-wrapper--edit__child = f.collection_select :category_id, @product.category.parent.parent.children, :id, :name ,{prompt: "選択してください", selected: @product.category.parent_id}, {class: 'listing-select-wrapper--edit__child--select', id: 'child_category_edit', name: "" } .listing-select-wrapper--edit__grandchild = f.collection_select :category_id,@product.category.parent.children, :id, :name ,{prompt: "選択してください", selected: @product.category.id}, {class: 'listing-select-wrapper--edit__grandchild--select', id: 'grandchild_category_edit', name: "product[category_id]" }collection_selectの後ろの方でselectedというのがありますが、そちらで登録していたカテゴリーを引っ張り出しています。孫カテゴリーのidを登録したいので、親カテゴリーと子カテゴリーにはnameで空欄にしています。これでカテゴリーに変更がなかった場合に孫カテゴリーが登録されます。上記の①はできました!
controller
def edit @product = Product.find(params[:id]) end def update @product = Product.find(params[:id]) if @product.update(update_params) redirect_to root_path, notice: '更新されました' else render :edit end end def get_category_children @category_children = Category.find(params[:category_id]).children end def get_category_grandchildren @category_grandchildren = Category.find("#{params[:child_id]}").children end private def update_params params.require(:product).permit(:buyer_id, :category_id, :product_name, :explain, :price, :brand, :condition, :arrive_at, :shipping_fee, :region_id, images_attributes: [:src, :id]) endコントローラーと後ほど書くjbuilderに関してはcreateアクションの時とほぼ一緒です。
下記のURLを参考にしました。
書いていただいた方、ありがとうございます!
https://qiita.com/gakinchoy7/items/ac1d8e64e33c3ddd377bjbuilderとjQuery
get_category_children.json.jbuilder
json.array! @category_children do |child| json.id child.id json.name child.name endget_category_grandchildren.json.jbuilder
json.array! @category_grandchildren do |grandchild| json.id grandchild.id json.name grandchild.name endjQuery
// オプションを作成 $(function(){ function appendOption(category){ var html = `<option value="${category.id}" data-category="${category.id}">${category.name}</option>`; return html; } // 子カテゴリー用のhtmlの作成。子カテゴリーのidはいらないので name=""としています。 function appendChild(insertHTML) { var childSelectHTML = ''; childSelectHTML = ` <div class="listing-select-wrapper--edit__child"> <select class="listing-select-wrapper--edit__child--select" id="child_category_edit" name=""> <option value="---" data-category="---">---</option> ${insertHTML} </select> </div>`; $('.listing-select-wrapper--edit').append(childSelectHTML); } // 孫カテゴリー用のhtmlを作成。孫カテゴリーのidが欲しいのでname="product[category_id]"としています。 function appendGrandChild(insertHTML) { var grandChildSelect = ''; grandChildSelect = `<div class="listing-select-wrapper--edit__grandchild"> <select class="listing-select-wrapper--edit__grandchild--select" id="grandchild_category_edit" name="product[category_id]"> <option value="---" data-category="---">---</option> ${insertHTML} </select> </div>`; $('.listing-select-wrapper--edit').append(grandChildSelect); } // 親カテゴリーの値が変わった時の処理を書きます $('#parent_category_edit').on('change', function() { // 親カテゴリーのデータを取得して変数にいれる var parentCategoryEdit = document.getElementById('parent_category_edit').value; if (parentCategoryEdit != '選択してください'){ // ajaxの処理。urlを/products/get_category_childrenにしないとrenderでeditに戻された時に上手く働かない $.ajax({ url: '/products/get_category_children', type: 'GET', data: { category_id: parentCategoryEdit }, dataType: 'json' }) // 成功した時の処理 .done(function(children){ // 元々あった子カテゴリーと孫カテゴリーを消す。 $('.listing-select-wrapper--edit__child').remove(); $('.listing-select-wrapper--edit__grandchild').remove(); // insertHTMLを定義して中身にオプションをつける。 var insertHTML = ''; children.forEach(function(child){ insertHTML += appendOption(child); }); // オプション付きのinsertHTMLをappendChildにいれる。 // 上のappendChildで定義された$('.listing-select-wrapper--edit').append(childSelectHTML);により一番、つまり親カテゴリーのしたに差し込まれる。 appendChild(insertHTML); }) .fail(function(){ alert('カテゴリー取得に失敗しました'); }) }else { $('#child_category_edit').remove(); $('#grandchild_category_edit').remove(); } }); // 子カテゴリーとやっていることは基本的に同じです $('.listing-select-wrapper--edit').on('change', '#child_category_edit', function(){ var childIdEdit = document.getElementById('child_category_edit').value; if (childIdEdit !== "---") { $.ajax({ url: '/products/get_category_grandchildren', type: 'GET', data: { child_id: childIdEdit }, dataType: 'json' }) .done(function(grandchildren) { if (grandchildren.length != 0) { $('#grandchild_category_edit').remove(); var insertHTML = ''; grandchildren.forEach(function(grandchild){ insertHTML += appendOption(grandchild); }); appendGrandChild(insertHTML); } }) .fail(function(){ alert('カテゴリー取得に失敗しました'); }) }else { $('#grandchild_category_edit').remove(); } }) })これで商品編集画面にてカテゴリー選択が新たにできるようになりました!
最後に
ajaxに関して理解が曖昧な点があったので最初は作るのに苦労しました。
youtubeやキータを漁って良かったと思います。
上記の記述でもっと簡単に書ける等のアドバイスをいただけたら幸いです。
- 投稿日:2020-06-02T12:53:56+09:00
rails6 + nginx のapiに別なdocker-composeのNext.jsフロントエンドからアクセスしたい
環境
Rails 6.0.3
Nginx 1.17.9
Next.js 9.4.4
docker 19.03.8やりたいこと
バックエンド、フロントエンドをそれぞれ別なdocker-composeで立ち上げて、フロントエンドからバックエンドのapi
http://localhost/api/v1/prefs
(都道府県API)を叩く。解決したこと
- 異なるdocker-compose間の
localhost
による通信- rails6での
host
の追加1. 異なるdocker-compose間の
localhost
による通信バックエンド・フロントエンドのアプリケーションをそれぞれ立ち上げて、フロント側から簡易的にapiにアクセスしようとした。
pages/index.tsximport Link from 'next/link' import Layout from '../components/Layout' import 'isomorphic-fetch'; function IndexPage({ results }: {results: any}){ return ( <Layout title="Home | Next.js + TypeScript Example"> <h1>Hello Next.js ?</h1> {results[0].pref} <p> <Link href="/about"> <a>About</a> </Link> </p> </Layout> ) } IndexPage.getInitialProps = async ({ req }: {req: any}) => { const res = await fetch('http://localhost/api/v1/prefs'); const data = await res.json(); return { results: data, }; } export default IndexPageapiサーバまでリクエストが届いていないようで、そちらにはログが出ない。
そもそもdocker-composeで立ち上げたアプリケーションはそれぞれが別のネットワークになっているので、localhost
にはapiサーバが存在していない。こちら1を参考に、フロント側のdocker-composeを編集した。
docker-compose.ymlversion: '3' services: react-next: build: context: ./ dockerfile: ./Dockerfile container_name: react-next tty: true volumes: - ./app:/app ports: - '8080:8080' command: sh -c "yarn run dev" # 以下追記 networks: - バックエンドのネットワーク名 networks: バックエンドのネットワーク名: external: trueバックエンドのネットワーク名は
docker network ls
で調べることができる。
NAMEを記載しておく。
過去のたくさんアプリケーションを立ち上げていると、その分のネットワーク名がすべて出るので、該当のものを探す。記載したらフロントエンドのコンテナに入ってみる。
今回はシェルとしてzsh
を入れているので、フロントエンドのコンテナ(コンテナ名:react-next
)に入るコマンドは
docker-compose run --rm react-next /bin/zsh
コンテナに入ったらフロントエンドの
server
コンテナにアクセスしてみる。
ping -c4 server
通信はできるようになった。
しかし、エラーは変わらず。2. rails6での
host
の追加通信はできるようになったのに、なぜリクエストは通らないのか。
こちら2を参考に、index.tsxを書き換えた。
pages/index.tsximport Link from 'next/link' import Layout from '../components/Layout' import 'isomorphic-fetch'; function IndexPage({ results }: {results: any}){ return ( <Layout title="Home | Next.js + TypeScript Example"> <h1>Hello Next.js ?</h1> {results[0].pref} <p> <Link href="/about"> <a>About</a> </Link> </p> </Layout> ) } IndexPage.getInitialProps = async ({ req }: {req: any}) => { // 以下変更 const res = await fetch('http://server/api/v1/prefs'); const data = await res.json(); return { results: data, }; } export default IndexPageしかし、変わらず。
なぜなのか。
コンテナに入って、やけくそで
curl http://server/api/v1/prefs
を実行した際に気になる結果が。
server
ホストがブロックされた、とある。
エラーメッセージで検索をしたところ、こちら3を見つけた。このページ通りにバックエンドのrailsサーバの設定を書き換える。
config/environments/development.rbRails.application.configure do # 略 # 追記 config.hosts << "server" # 略 end変更したらrailsサーバを再起動。
もう一度curl
コマンド叩いてみる。お!
ブラウザに急ぐ。
そこには燦然と輝く『北海道』の文字。
無事にapiから都道府県のデータ取得ができました。
- 投稿日:2020-06-02T12:06:33+09:00
【Rails】Google Mapの表示方法
目標
前提
下記実装済み。
・Googleアカウントを作成済み。
・Slim導入
Google Cloud Platform
に登録1.下記リンクにアクセス
2.「使ってみる」をクリック
3.プロジェクト名(適当で良い)を入力し、「作成」をクリック
4.「請求先アカウントの作成」をクリック
5.利用規約にチェックを入れ、「続行」をクリック
6.請求情報を入力し、「無料トライアルを開始」をクリック
APIキー
を取得1.「APIの概要に移動」をクリック
2.「APIとサービスを有効化」をクリック
3.「Maps JavaScript API」をクリック
4.「有効にする」をクリック
5.「認証情報」をクリック
6.「APIとサービスの認証情報」をクリック
7.「認証情報を作成」をクリック
8.「APIキー」をクリック
9.一旦「閉じる」をクリック
10. 「APIキーの名前」をクリック
11.認証情報の設定をする
①アプリケーションの制限
なし
を選択する。②APIの制限
キーを制限
を選択し、プルダウンメニューからMaps JavaScript API
を選択する。③
Maps JavaScript API
が選択されている事を確認して、保存
をクリック
12.赤枠で囲われているマークをクリックし、APIキーをコピー
実装
1.APIキーを環境変数化
①「gem 'dotenv-rails'」を導入
Gemfilegem 'dotenv-rails'ターミナル& bundle
②アプリケーション直下に「.env」ファイルを作成
※アプリケーションのディレクトリに移動してから下記コマンドを実行ターミナル$ touch .env③
.env
ファイルを編集.envGOOGLE_MAP_API = 'コピーしたAPIキー' # 追記④
.gitignore
ファイルを編集.gitignore/.env # 追記2.ビューを編集
~html.slim/ マップを表示 #map style='height: 500px; width: 500px;' / APIを読み込み - google_api = "https://maps.googleapis.com/maps/api/js?key=#{ ENV['GOOGLE_MAP_API'] }&callback=initMap".html_safe script{ async src=google_api } javascript: let map; function initMap() { geocoder = new google.maps.Geocoder() // マップを作成 map = new google.maps.Map(document.getElementById('map'), { // マップの中心に表示する場所の緯度経度を指定 center: { lat: 40.7828, lng:-73.9653 }, zoom: 12, }); // マーカーを立てる場所の緯度経度を指定 marker = new google.maps.Marker({ position: { lat: 40.7828, lng:-73.9653 }, map: map }); }
- 投稿日:2020-06-02T12:06:23+09:00
[Rails]初学者がform_withの流れを整理・理解するための記事
はじめに
Rails学習初期に、form_withの流れが理解できなかったのでまとめます。
Rails5.2.4です。先にまとめ
「早くまとめろよ!」という方もおられるかと思いますので、先に流れをまとめます。
簡単に解説
UserモデルとPostモデルがある状況です。
①newアクションで、ビューページ(new.html.erb)を表示
newアクションを呼び出すリクエストが出されたら、まずはpostの新規投稿(new)ページが表示される
※イメージ
②newアクションで生成している
@post
インスタンスをビューに渡すpost_controller.rbclass PostsController < ApplicationController ~~ def new @post = Post.new #ここで生成されている@postが、new.html.erbに渡される end ~~④createアクションを呼び出す
上記の画像のように、投稿する
ボタン(form_withのsubmit)をクリックすると、form_withがcreateアクションを呼び出してくれます。※form_withヘルパーメソッドは、渡されたインスタンス(この場合は
@post
)のプロパティを見て、createに飛ばすかupdateに飛ばすかを判断してくれる便利な子です。form_withが考えてること- @post が空 → 初めて作るんだな!じゃあcreate! - @post が空じゃない → 変更したいんだな!じゃあupdate!⑤post_paramsメソッドを呼び出す
post_controller.rbclass PostsController < ApplicationController ~~ def create #createアクションが呼び出され、Post.create(post_params)が実行される→ post_paramsが呼び出される Post.create(post_params) redirect_to root_path end private def post_params params.require(:post).permit(:title, :content).merge(user_id: current_user.id) end ~~⑥paramsで受け取った値のうち、permitで受け取る値を指定(許可)
paramsで受け取る値の状態[1] pry(#<PostsController>)> params => <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"oLGgLMTcqSPi7cbK9j1wFhH5rqiwXYO7GyRoZcZFZe6Y5VdbHrWCOyeo37kgW/bsl+eANQrz7p/lAzZMnAS8Gg==", "post"=>{"title"=>"今日学んだこと", "content"=>"form_withは賢い子!"}, "commit"=>"投稿する", "exept"=>:index, "controller"=>"posts", "action"=>"create"} permitted: false>見にくいので本来ない位置で改行していますが、通常は1行で返ってきます。
"post"=>{"title"=>"今日学んだこと", "content"=>"form_withは賢い子!"},
がpost_params
で扱う値です。
permit
で受け取る値を許可しておかないと、意図しない値がテーブルに保存される可能性があるので、指定がほぼ必須です。⑦post_paramsの値でPostをcreateする(成功すればテーブルに保存される)
post_paramsメソッドで返された値で、Post.createすることになるので、
実質下記と同じ状態です。def create Post.create(title: "今日学んだこと", content: "form_withは賢い子!", user_id: 1) redirect_to root_path endこの流れを確認した上で、もう一度冒頭の画像を見ると理解が深まると思います!
おわりに
form_tag、form_forとの違いはこちらの記事にまとめています。
[Rails]hamlでのform_with/form_for/form_tagの書き方間違い等ありましたらご指摘いただけると幸いです。
- 投稿日:2020-06-02T11:52:08+09:00
【Rails】rails newしてPostgreSQLでデータベース作成まで
はじめに
今年はWebにも少しづつ挑戦しようということで、参考文献の一番多そうなRailsをイジイジしています。取り敢えずローカルでの環境構築を終えてRails newして色々と試しているところです。
このあたりで一度頭の中を整理しつつテンプレ化しておきたいのと、間違いの指摘など頂けたら嬉しいなあと思って記事を書いています。
あとはRails newがうまくいかない人の参考になれば嬉しいです。環境
terminalWindows10 ruby 2.6.6 Rails 6.0.3.1 psql (PostgreSQL) 12.3
環境構築に関しては書きませんので必要に応じてお調べください。
データベースはPostgreSQLに変更します。
それとgemについては基本的にローカルに入れてます。どちらでもいいみたいなんですが、なんとなくそうしています。アプリケーションのディレクトリ内にGemfileを作成する
ディレクトリは適当に作ってください。
terminalC:\Users\user\sample_app> bundle initGemfileに追加するgemを記述する
作成したGemfileをエディタで開き、以下を追加する。
Gemfilegem 'rails'//コメントアウト(#)を外すだけ gem 'pg'//PostgreSQLに変更する場合gemのバージョンを指定したほうがいいのか、よく分からなかったので一先ず指定しないでおく。
bundle installする
terminalbundle install --path vendor/bundle
--path vendor/bundleはgemをローカルにインストールする場合に指定する。こうすることでvendor/bundle内にgemがインストールされるらしい。
--path vendor/bundleは最初の一回目だけ指定すれば、あとは省略できるみたい。rails newする
terminalbundle exec rails new . -d postgresql --skip-turbolinks --skip-test
bundle execはRailsをローカルにインストールした場合につける。以降全てのrailsコマンドにつけます。
-d postgresql --skip-turbolinks --skip-testはオプションでこれら以外にも色々あるみたいなので必要に応じてお調べてください。
いまいち分からないものが多いので取り敢えずみんな書いているものだけ書く。SQL Shellでデータベースを作成する
SQLShell(psql)create role APPLICATION_NAME with createdb login password 'PASSWORD'; select * from pg_user;APPLICATION_NAMEにはユーザーネーム(アプリ名)、PASSWORDには任意のパスワードをいれます。
select * from pg_user;でロールが作成されているか確認します。database.ymlを更新する
configフォルダ内のdatabase.ymlに以下を記述します。
database.yml・ ・ default: &default adapter: postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: APPLICATION_NAME//追加(データベース作成時に決めたユーザーネーム) password: PASSWORD//追加(データベース作成時に決めたパスワード) host: localhost//追加 ・ ・database.ymlを保存したらデータベースも更新します。
terminalbundle exec rails db:migrate:reset
サーバーを起動する
terminalbundle exec rails s
ブラウザでhttp://localhost:3000/
にアクセスして画像が表示されれば成功。
- 投稿日:2020-06-02T11:09:20+09:00
複数の正規表現にmatchするかの判定
こんな正規表現のバリデーションメソッドがあった時、
def customer_number_valid_format? return true if a.blank? return true if b.blank? binding.pry regex = /\A(\d{5})-?(\d{5})-?(\d{1})-?(\d{2})\z/, /\A(\d{4})-?(\d{3})-?(\d{3})\z/ # p regex => [/\A(\d{5})-?(\d{5})-?(\d{1})-?(\d{2})\z/, /\A(\d{4})-?(\d{3})-?(\d{3})\z/] return true if regex.blank? unless customer_number.match?(regex) ? self.errors.add(:customer_number, :invalid_and_confirm, target: 'お客様番号') end endunless customer_number.match?(regex)ここで
customer_number
が12345-12345-1-12
か1234-123-123
の時にtrue
を返して欲しいが上記コードだと[27] pry(#<Order>)> customer_number.match?(regex) TypeError: wrong argument type Array (expected Regexp)となる。
match?
はStringクラスのメソッドだからだね。
https://docs.ruby-lang.org/ja/latest/method/String/i/match=3f.html解決
配列に入ってるどっちかの正規表現にあってるか判定するには
Regexp.union
というものを使うらしい。customer_number.match?(Regexp.union(regex))[25] pry(#<Order>)> Regexp.union(regex) => /(?-mix:\A(\d{5})-?(\d{5})-?(\d{1})-?(\d{2})\z)|(?-mix:\A(\d{4})-?(\d{3})-?(\d{3})\z)/ # 配列ではなくパイプで繋がれ他文字列になる [26] pry(#<Order>)> low_voltage_customer_number.match?(Regexp.union(regex)) => true
- 投稿日:2020-06-02T10:28:52+09:00
投稿時にファイルから選択した画像を表示する方法メモ(HTMLファイル上でJS)
Railsで画像投稿時にファイルから選択した画像をその場で確認できる方法。
htmlファイル%img{id:“image-file”} :javascript document.addEventListener(‘change’, function(e){ let file = e.target.files[0]; let fileReader = new FileReader(); fileReader.onload = function() { let dataUri = this.result; let img = document.getElementById(‘image-file’); img.src = dataUri; } fileReader.readAsDataURL(file); });・addEventListener さまざまなイベント処理を実行することができるメソッド
・document Chrome等のブラウザ上で表示されたドキュメントを操作する事
・change changeイベントを発生
・target.files ファイルの取得する
・FileReader ユーザーのコンピューター内にあるファイル (もしくはバッファ上の生データ) をウェブアプリケーションから非同期的に読み込むことが出来る。
・result ファイルの内容を返す
・getElementById 指定された idの属性を持つ、要素の参照を返します
・readAsDataURL ファイルオブジェクトをData URIに変換するメソッド
- 投稿日:2020-06-02T09:17:59+09:00
jQuery1系をWebpackerで流用した話
背景
新規開発プロジェクトにてデザインの一部を他アプリから流用したいリクエストがありました。
そのアプリはjquery1系で動いていたため、そのまま流用しても後述の環境では動かず・・・。
Chromeの開発者ツールによるデバッグで「$ is not defined」が頻発したりとだいぶハマったので備忘録として残します。局所的にjqueryを利用するため、アプリ内におけるグローバル化は実施しておりません。
参考
以下の回答が大変参考になりました!
環境
Rails: 6.0.2
Webpacker: 4.2.2
jQuery: 3.5.1
パッケージマネージャ: yarn流用したコード(抜粋)
test.js
'use strict'; (function($){ // 各処理 var hoge = (function () { var $fuga = $('viewのclassまたはid属性') return{ piyo: function () { // 取得したclass,id属性に対してjqueryで実現したい処理 } } })(); $(window).on('load', function(){ // ページが読み込まれた時に実行するモジュール化された関数たち hoge.piyo(); }); })(jQuery);CDNによるjquery読み込み
test.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>修正したコード(抜粋)
test.js
'use strict'; import $ from 'jquery'; $(function(){ // 各処理 var hoge = (function () { var $fuga = $('viewのclassまたはid属性') return{ piyo: function () { // 取得したclass,id属性に対してjqueryで実現したい処理 } } })(); $(window).on('load', function(){ // ページが読み込まれた時に実行するモジュール化された関数たち hoge.piyo(); }); });webpackerによるjavascript読み込み
[webpacker管理対象ディレクトリ]/packs/app.js
import '../[任意のディレクトリ]/test.js';test.html.slim(要件に従いslimを採用しております)
= javascript_pack_tag 'app'
- 投稿日:2020-06-02T00:36:21+09:00
開発中の Rails アプリケーションに後から Active Storage を追加したくなったときの話
rails new
したときにはいらないと思っていた Rails の機能を後から追加したくなること、皆さんはありませんか? 最近作っているアプリでそんなことがあったので対処法をまとめておきます。前提
API モードで作り始めた Rails アプリケーションで試していますが、API モードでなくても成り立つ話だと思います。
バージョンは公開時点で最新の 6.0.3.1 です(バージョンアップ大切)。
経緯
Active Storage の使い方は Rails ガイド なり先人の記事に詳しくまとまっているので省略します。
これに沿って作っていこうとしたところ、その一番最初の手順である
rails active_storage:install
の実行に失敗しました。task がないって言われた...。┏╸..t/football-game-reporter-api · ⎇ add-game-catch-image ‹✔› ┗╸❯❯❯ bundle exec rails active_storage:install rails aborted! Don't know how to build task 'active_storage:install' (See the list of available tasks with `rails --tasks`) bin/rails:4:in `<main>' (See full trace by running task with --trace)一覧を出してみると確かにない...。
┏╸..t/football-game-reporter-api · ⎇ add-game-catch-image ‹✔› ┗╸❯❯❯ bundle exec rails --tasks rails about # List versions of all Rails frameworks and the environment rails app:template # Applies the template supplied by LOCATION=(/path/to/template) or URL rails app:update # Update configs and some other initially generated files (or use just update:configs or update:bin) rails db:create # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all t... rails db:drop # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to dr... rails db:environment:set # Set the environment value for the database rails db:fixtures:load # Loads fixtures into the current environment's database rails db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog) rails db:migrate:status # Display status of migrations rails db:prepare # Runs setup if database does not exist, or runs migrations if it does rails db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n) rails db:schema:cache:clear # Clears a db/schema_cache.yml file rails db:schema:cache:dump # Creates a db/schema_cache.yml file rails db:schema:dump # Creates a db/schema.rb file that is portable against any DB supported by Active Record rails db:schema:load # Loads a schema.rb file into the database rails db:seed # Loads the seed data from db/seeds.rb rails db:seed:replant # Truncates tables of each database for current environment and loads the seeds rails db:setup # Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the da... rails db:structure:dump # Dumps the database structure to db/structure.sql rails db:structure:load # Recreates the databases from the structure.sql file rails db:version # Retrieves the current schema version number rails log:clear # Truncates all/specified *.log files in log/ to zero bytes (specify which logs with LOGS=test,development) rails middleware # Prints out your Rack middleware stack rails restart # Restart app by touching tmp/restart.txt rails secret # Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessi... rails spec # Run all specs in spec directory (excluding plugin specs) rails spec:models # Run the code examples in spec/models rails spec:validators # Run the code examples in spec/validators rails stats # Report code statistics (KLOCs, etc) from the application or engine rails time:zones[country_or_offset] # List all time zones, list by two-letter country code (`rails time:zones[US]`), or list by UTC offset (`rails... rails tmp:clear # Clear cache, socket and screenshot files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear, tmp:screen... rails tmp:create # Creates tmp directories for cache, sockets, and pids rails yarn:install # Install all JavaScript dependencies as specified via Yarn rails zeitwerk:check # Checks project structure for Zeitwerk compatibility対処法
Rails 本家の README に書いてある通り
require "active_storage/engine"
すれば十分でした。NOTE: If the task cannot be found, verify that require "active_storage/engine" is present in config/application.rb.
試してみると無事に task が追加されています。
┏╸..t/football-game-reporter-api · ⎇ add-game-catch-image ‹✚1› ┗╸❯❯❯ git diff diff --git a/config/application.rb b/config/application.rb index b47c87a..dec7181 100644 --- a/config/application.rb +++ b/config/application.rb @@ -5,7 +5,7 @@ require "rails" require "active_model/railtie" require "active_job/railtie" require "active_record/railtie" -# require "active_storage/engine" +require "active_storage/engine" require "action_controller/railtie" # require "action_mailer/railtie" # require "action_mailbox/engine" ┏╸..t/football-game-reporter-api · ⎇ add-game-catch-image ‹✚1› ┗╸❯❯❯ bundle exec rails --tasks rails about # List versions of all Rails frameworks and the environment rails active_storage:install # Copy over the migration needed to the application (以下略)これで Active Storage を実行する準備が整いました。
原因
おそらく
rails new
したときに--skip-active-storage
をしていたのでこの行がコメントアウトされており、それを元に戻し損ねていたのが原因です。本家の README を読めば一瞬でわかりますね、反省。あとは使えるはずの機能が使えないあたりで require が足りていないことくらいには気付きたかったです、もっと反省。
- 投稿日:2020-06-02T00:27:19+09:00
selectbox テスト Capybara::ElementNotFound
前提
rspec
Capybara
導入済み本題
今までほとんどfill_inを使用していたためselectboxのテストを行ってみたところ下記のようなエラーにハマりました。
Capybara::ElementNotFound: Unable to find field "北海道" that is not disabled
・間違い
system.article_spec.rbselect "北海道", from 1・変更点
system.article_spec.rbselect "北海道", from "article[place_id]"_form.htm<select class="form-control" id="article_place" name="article[place_id]"><option value="">選択してください</option> <option value="1">北海道</option> <option value="2">青森県</option> <option value="3">岩手県</option> <option value="4">宮城県</option> <option value="5">秋田県</option> <option value="6">山形県</option> <option value="7">福島県</option> <option value="8">茨城県</option> <option value="9">栃木県</option> <option value="10">群馬県</option> <option value="11">埼玉県</option> ・ ・ ・上記で問題なくテスト成功できました。