- 投稿日:2020-03-31T23:50:59+09:00
dockerでGemfile(gem追加)更新したら後、データベースが消えた、gemが反映しない
サーバーを再起動してますか????
#dockerではない通常開発の場合
dockerなしcontrol c でサーバー終了 rails sこれでgem反映します。
ということはdockerもサーバーを再起動しなければいけない。
dockerあり$ docker-compose restartこれで反映されます。
- 投稿日:2020-03-31T22:08:10+09:00
RubyのFloat(arg, exception: true)をbuiltinで再実装してみた
はじめに
この記事は以前書いた以下の記事で紹介したbuiltinを使って
Float(arg, exception: true)
というメソッドを再定義してみた記事になります。Ruby(とC)でRubyを実装してみた(builtinで遊んでみた)
やっていることは前回の記事とおおよそ同じです。前回と異なる点は、特定のクラスのメソッドではなく、どこでも呼び出すことができるメソッドをbuiltinで再定義してみたという点です。
前回の記事を書いた後、
raise
やFloat
などのメソッドをbuiltin対応ができるのか気になり試してみた感じですね。結論から言うと、そういったグローバルなメソッドもbuiltinで対応することができるようです(意図した挙動かは確認とっていないので、推奨されたものではないかもしれませんが……)
builtinって?
builtinとはRuby(とC)でRuby自体を実装するというものです。詳しくは前回の記事を読んでいただければと思います。
Ruby(とC)でRubyを実装してみた(builtinで遊んでみた)
環境構築
前回の記事の環境をそのまま使用しています。特に大きな変更点などもありません。
Ruby(とC)でRubyを実装してみた(builtinで遊んでみた)
やってみた
Floatメソッドの実装場所を探す
まずは
Float
メソッドが実装されているソースを探します。Rubyのメソッドは大体こんなかんじで定義されています。rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0);第一引数がメソッドが定義されているクラス/モジュールの変数になります。大体、
rb_cArray
などのようにクラス名やモジュール名で作成されています。第二引数の"to_s"
はRuby側で呼び出されるメソッド名になっています。第三引数はメソッドが呼び出された際に実行するCの関数で、最後の引数がメソッドが受け取る引数の数を指定しています。今回、再実装したいのは
Float
メソッドですのでRubyのソースコード内からgit grep \"Float\"
などで検索してみましょう。
するとobject.c
で以下のように実装されているようです。rb_define_global_function("Float", rb_f_float, -1);それでは再実装していきます。
Floatメソッドの再実装
前回の記事では
Hash#delete
を再実装していました。またbuiltin対応のため、common.mk
などの修正していました。
ですが、現在のRubyのmasterのコードではobject.c
で実装されていたKernel#clone
をbuiltinに対応させているので、それらの修正は必要ありません。修正が必要なソースは
object.c
とkernel.rb
の二つになります。object.cの修正
object.c
ではまずFloat
メソッドを定義している以下のコードを削除します。void InitVM_Object(void) { Init_class_hierarchy(); // 省略 - rb_define_global_function("Float", rb_f_float, -1); // 省略 }次に、
Float
メソッドの処理を定義しているrb_f_float
を以下のように修正します。- /* - * call-seq: - * Float(arg, exception: true) -> float or nil - * - * Returns <i>arg</i> converted to a float. Numeric types are - * converted directly, and with exception to String and - * <code>nil</code> the rest are converted using - * <i>arg</i><code>.to_f</code>. Converting a String with invalid - * characters will result in a ArgumentError. Converting - * <code>nil</code> generates a TypeError. Exceptions can be - * suppressed by passing <code>exception: false</code>. - * - * Float(1) #=> 1.0 - * Float("123.456") #=> 123.456 - * Float("123.0_badstring") #=> ArgumentError: invalid value for Float(): "123.0_badstring" - * Float(nil) #=> TypeError: can't convert nil into Float - * Float("123.0_badstring", exception: false) #=> nil - */ static VALUE static VALUE - rb_f_float(int argc, VALUE *argv, VALUE obj) + rb_f_float(rb_execution_context_t *ec, VALUE main, VALUE arg, VALUE opts) { - VALUE arg = Qnil, opts = Qnil; - - rb_scan_args(argc, argv, "1:", &arg, &opts); - return rb_convert_to_float(arg, opts_exception_p(opts)); + return rb_convert_to_float(arg, opts_exception_p(opts)); }builtinを使い、キーワード引数を受け取るので
int argc, VALUE *argv
ではなくVALUE main, VALUE arg, VALUE opts
としています。またVALUE main
はグローバルなメソッドが暗黙の裡に受け取っている引数を代わりに受け取るために追加しています。これで
object.c
での修正は完了です!kernel.rbの修正
Rubyでは、どこからでも呼び出すことができるグローバルなメソッドは
Kernel
モジュールにて再定義することができます。たとえば、
puts
メソッドは以下のようにモンキーパッチすることができます。module Kernel def puts *args p "hoge" end end puts :ho #=> "hoge" と表示されるこれを使い、
kernel.rb
内に以下のようにFloat
メソッドを追加します。module Kernel + + # + # call-seq: + # Float(arg, exception: true) -> float or nil + # + # Returns <i>arg</i> converted to a float. Numeric types are + # converted directly, and with exception to String and + # <code>nil</code> the rest are converted using + # <i>arg</i><code>.to_f</code>. Converting a String with invalid + # characters will result in a ArgumentError. Converting + # <code>nil</code> generates a TypeError. Exceptions can be + # suppressed by passing <code>exception: false</code>. + # + # Float(1) #=> 1.0 + # Float("123.456") #=> 123.456 + # Float("123.0_badstring") #=> ArgumentError: invalid value for Float(): "123.0_badstring" + # Float(nil) #=> TypeError: can't convert nil into Float + # Float("123.0_badstring", exception: false) #=> nil + # + def Float(arg, exception: true) + __builtin_rb_f_float(arg, exception) + end + # # call-seq: # obj.clone(freeze: nil) -> an_object # # Produces a shallow copy of <i>obj</i>---the instance variables of # <i>obj</i> are copied, but not the objects they reference. # #clone copies the frozen value state of <i>obj</i>, unless the # +:freeze+ keyword argument is given with a false or true value. # See also the discussion under Object#dup. # # class Klass # attr_accessor :str # end # s1 = Klass.new #=> #<Klass:0x401b3a38> # s1.str = "Hello" #=> "Hello" # s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello"> # s2.str[1,4] = "i" #=> "i" # s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">" # s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">" # # This method may have class-specific behavior. If so, that # behavior will be documented under the #+initialize_copy+ method of # the class. # def clone(freeze: nil) __builtin_rb_obj_clone2(freeze) end end先ほどbuiltin対応させた
rb_f_float
を__builtin_rb_f_float
で呼び出しています。これでkernel.rb
での修正はOKです。最後に
あとは
make
とmake install
を実行してビルドできればbuiltinでの実装は完了です。おわりに
こんな感じで
Float
やInteger
などのメソッドをbuiltin対応できそうです。パッチとして送るかは別として、結構応用できそうだったのが面白かったですね。ちなみに、以下のようなベンチマークを試してみたところパフォーマンス向上は期待できそうにないかなという感じでした。
benchmark: float: "Float(42)" float_true: "Float(42, exception: true)" float_false: "Float(42, exception: false)" loop_count: 10000以下結果
Calculating ------------------------------------- compare-ruby built-ruby float 37.495M 15.878M i/s - 10.000k times in 0.000267s 0.000630s float_true 1.109M 1.211M i/s - 10.000k times in 0.009015s 0.008261s float_false 1.227M 1.191M i/s - 10.000k times in 0.008150s 0.008395s Comparison: float compare-ruby: 37495314.0 i/s built-ruby: 15878056.0 i/s - 2.36x slower float_true built-ruby: 1210507.2 i/s compare-ruby: 1109250.0 i/s - 1.09x slower float_false compare-ruby: 1226948.7 i/s built-ruby: 1191128.5 i/s - 1.03x slower仮に
Float
などのメソッドをbuiltin対応する場合はパフォーマンスよりもコードのメンテナンス性などを重視することになるのかなと思いますね。
- 投稿日:2020-03-31T20:55:22+09:00
仮想環境でRails API × Nuxt.jsのアプリケーション開発をしたいが、まずブラウザに表示されない!
自己紹介
- 現在プログラミングの学習中の者です
- 言い回しや知識に関して、諸所間違い等あるかと思います
- その際は、ご指摘いただけますと幸いです
やりたいこと
RailsをAPIとして使用し、Nuxt.jsをフロント側に使用する開発において、
それらを仮想環境で開発を開始すること。具体的には、@saongtx7様が書いてくださった
こちらの記事を仮想環境で進めたいと思ったことがきっかけです。[入門]Rails API × Nuxt SPA × Firebase Authで作る Todo Appチュートリアル
https://qiita.com/saongtx7/items/d97ef5aec393e704fd3f本当に素晴らしいチュートリアルでした。
この場を借りて感謝申し上げます。問題点
私の場合このような問題が起こりました。
- Rails側でポート指定をしてもブラウザに表在されない(rails s -b 5000)
- Rails側でポートを指定せずに起動した場合、Nuxt.jsとポート番号が競合する
結論
1.Vagrantfileへ追記をする
まず、仮想環境のあるディレクトリに移動してください。
Vagrantfileがあると思いますのでテキストエディターで起動し、以下の追記をお願いします。
Vagrantfile
//省略 config.vm.network "forwarded_port", guest: 3000, host: 3000 config.vm.network "forwarded_port", guest: 5000, host: 5000 #追記! //省略2.Railsで起動をする際に-b 0.0.0.0を指定する。
大前提としてrails new --apiができており、アプリケーションのディレクトリは完成しているものとします。所定の場所に移動したら、ターミナルで以下を入力し、起動してください。
rails s -b 0.0.0.0 -p 5000
3.Nuxt.jsのpackage.jsonを書き換える
こちらも大前提として、npx create-nuxt-appができているものとします。所定の場所に移動する前に、テキストエディターでディレクトリを開き、直下のpackage.jsonを開いてください。
package.json//省略 "scripts": { "dev": "HOST=0.0.0.0 PORT=3000 nuxt", //変更後 "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate" }, //省略これができたら、通常通り
npm run dev
(yarnでインストールしている方は違うかも…?)そして、
locallhost:3000
にアクセス。
自分はこれで解決し、無事仮想環境でもRails/Nuxtの同時起動ができました!参考
初学者ながら加筆させていただいた部分としましては、
- Rails s時の書き方
- Vagrantfileの書き方
以上になります。
超独学プログラマ様の以下の記事に救われました。
本当に何日も悩みましたので・・・Nuxt.jsからRailsへ、初めてのapi通信でHelloを表示しよう
https://blog.cloud-acct.com/posts/spa-nuxt-firstapi/最後に、初投稿となりますので至らない点もあるかと思います。
何かお気づきの点がございましたら、後学のためご指摘をお願いいたします。
この記事が誰かのためになれば幸いです。
- 投稿日:2020-03-31T19:25:36+09:00
railsのルーティングからOpenAPI(V3)ドキュメントを自動生成・管理するツールを作成し、10ヶ月間会社で運用した話(下期編)
前回、railsのルーティングからOpenAPI(V3)ドキュメントを自動生成・管理するツールを作成し、4ヶ月間会社で運用した話(開発秘話もあるよ)
という記事で下期の進捗も報告すると書いたのでその記事になります。使用したツール
自分で作ったr2-oasです。
4ヶ月の実績
※会社の許可をとりデータを載せております。
全体の実績
赤線が目標ライン。目標は、5個/週 です。
各週の実績
10月の中旬に進捗がないのは、他のプロジェクトを引き継ぐために必死だったからです。
着手する余力がなかったです。12/30の週に進捗がないのは正月休み。その他進捗がなかったのは個人の実績
チームとの話し合いでAPIドキュメント書いていくのはシンドイとなったので個人でコツコツやってました。
私の9ヶ月の進捗実績は、
7.56個/週
でした。
下期だけの進捗だと3.8個/週
でした。最初、
週10個/週
を目標にやっていたおかげもあってそんなにひどい結果にならずにすんだとはいえ、目標未達成です。残念です。
進捗管理表
これまで乗せてきたグラフや表はこの進捗管理表から自動生成されてます。
pathsファイル というのがrailsで言うところのコントローラーに対応してます。
後で紹介しますが、r2-oas は「コントローラー毎にAPIドキュメントが書ける」特徴があります。まとめ
下期は個人でコツコツやってました。途中でなげだすのはよくないと思うので、上司と話あって継続で
5個/週
でやっていきます。
項目 実績/目標 個人合計(個) 189個 個人平均(個/週) 7.58個/週 下期個人平均(個/週) 3.8個/週 r2-oasのチュートリアル
r2-oas
ってなんだよ。って人向けのチュートリアルです。r2-oasが得意とすることは既に完成されたAPIのAPIドキュメントを自動で作成することです。そしてコードベースで書いていかないので、途中からでも始められるし、途中でやめやすいというのが特徴です。rails6でAPIドキュメントを作ってみましょう。
SwaggerUIやSwaggerEditorで開いたりする場合は以下の準備が必要です。
$ brew cask install chromedriver $ docker pull swaggerapi/swagger-ui:latest $ docker pull swaggerapi/swagger-editor:latestrails newしたら、Gemfileのdevelopmentに
r2-oas
を追加してください。group :development do gem 'r2-oas' end準備
$ rails _6.0.0_ new example-600 -d mysql --skip-bundle $ cd example-600 $ bundle install --path vendor/bundle $ # mysql2のエラーが出るときは以下を実行して、bundle installをやり直す。 $ # bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"scaffoldで適当にルーティングを作成する。
$ bundle exec rails g scaffold user name:string age:integer $ bundle exec rails g scaffold task status:string content:string $ bundle exec rails g scaffold Api/V1/Account status:string content:string $ bundle exec rails g scaffold Api/V2/CustomPost status:string content:string一旦コミットする
$ git init $ git add . && git commit -nm "initial commit " $ # OpenAPI(V3)形式のドキュメントの雛形生成 $ bundle exec rake routes:oas:docs # ドキュメントはコロコロ変わるのでgitignoreに追加する。 $ echo 'oas_docs/oas_doc.yml' >> .gitignore $ # 一旦コミットする $ git add . && git commit -nm "generate docs"SwaggerEditor(UI)で開く。
PATHS_FILE
という環境変数を指定したほうが最小限のドキュメントだけビルドされるので動作は軽いです。$ bundle exec rake routes:oas:editor $ # もしくは $ # こんな風にpathsファイル毎に開くこともできます。環境変数のPATHS_FILEを指定します。 $ PATHS_FILE=oas_docs/src/paths/task.yml bundle exec rake routes:oas:editorここでは
PATHS_FILE
を指定して開いてみましょう。
GET /tasks
のsummary
を「タスク一覧取得」に修正GET /tasks
の422
に関しての情報をすべて削除以上ができたら、ターミナルに戻り
Ctrl+C
を押してみましょう。wait for signal trap ... ^CI, [2020-03-30T11:52:20.903111 #21328] INFO -- : [Analyze OAS file] start I, [2020-03-30T11:52:20.908564 #21328] INFO -- : [Analyze OAS file (tags)] start I, [2020-03-30T11:52:20.910406 #21328] INFO -- : Write schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/tags.yml I, [2020-03-30T11:52:20.910440 #21328] INFO -- : [Analyze OAS file (tags)] end I, [2020-03-30T11:52:20.910450 #21328] INFO -- : [Analyze OAS file (paths)] start I, [2020-03-30T11:52:20.915803 #21328] INFO -- : Write schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/task.yml I, [2020-03-30T11:52:20.915851 #21328] INFO -- : [Analyze OAS file (paths)] end I, [2020-03-30T11:52:20.915865 #21328] INFO -- : [Analyze OAS file (components)] start I, [2020-03-30T11:52:20.915883 #21328] INFO -- : [Analyze OAS file (components/schemas)] start I, [2020-03-30T11:52:20.918129 #21328] INFO -- : Write schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/components/schemas/task.yml I, [2020-03-30T11:52:20.918168 #21328] INFO -- : [Analyze OAS file (components/schemas)] end I, [2020-03-30T11:52:20.918182 #21328] INFO -- : [Analyze OAS file (components/requestBodies)] start I, [2020-03-30T11:52:20.920313 #21328] INFO -- : Write schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/components/requestBodies/task.yml I, [2020-03-30T11:52:20.920364 #21328] INFO -- : [Analyze OAS file (components/requestBodies)] end I, [2020-03-30T11:52:20.920381 #21328] INFO -- : [Analyze OAS file (components/securitySchemes)] start I, [2020-03-30T11:52:20.920889 #21328] INFO -- : [Analyze OAS file (components/securitySchemes)] end I, [2020-03-30T11:52:20.920908 #21328] INFO -- : [Analyze OAS file (components/parameters)] start I, [2020-03-30T11:52:20.921348 #21328] INFO -- : [Analyze OAS file (components/parameters)] end I, [2020-03-30T11:52:20.921365 #21328] INFO -- : [Analyze OAS file (components/responses)] start I, [2020-03-30T11:52:20.921804 #21328] INFO -- : [Analyze OAS file (components/responses)] end I, [2020-03-30T11:52:20.921820 #21328] INFO -- : [Analyze OAS file (components/examples)] start I, [2020-03-30T11:52:20.922285 #21328] INFO -- : [Analyze OAS file (components/examples)] end I, [2020-03-30T11:52:20.934988 #21328] INFO -- : [Analyze OAS file (components/headers)] start I, [2020-03-30T11:52:20.940521 #21328] INFO -- : [Analyze OAS file (components/headers)] end I, [2020-03-30T11:52:20.940773 #21328] INFO -- : [Analyze OAS file (components/links)] start I, [2020-03-30T11:52:20.944804 #21328] INFO -- : [Analyze OAS file (components/links)] end I, [2020-03-30T11:52:20.944943 #21328] INFO -- : [Analyze OAS file (components/callbacks)] start I, [2020-03-30T11:52:20.945420 #21328] INFO -- : [Analyze OAS file (components/callbacks)] end I, [2020-03-30T11:52:20.945540 #21328] INFO -- : [Analyze OAS file (components)] end I, [2020-03-30T11:52:20.945569 #21328] INFO -- : [Analyze OAS file] end I, [2020-03-30T11:52:21.162340 #21328] INFO -- : container id: fddeedcd579c4e53ec549778ae5dc3888796b011543e504f77b93706d4dac232 removed I, [2020-03-30T11:52:21.162463 #21328] INFO -- : [R2-OAS] endこんな感じにログが流れて差分を確認すると以下の様になっているはずです。
これをcommitしましょう。
git add . && git commit -nm "Write GET /tasks"このようにAPIドキュメントを書いていきます。
完成したAPIドキュメントだけ表示したい
そういう場合もあるでしょう。そのためにr2-oasには、
.paths
ファイルに完成したpathsのyamlファイルを書いていきます。今、
oas_docs/src/paths/task.yml
が完成したとすると、# pathsディレクトリ以下の相対パスを書きます。 echo 'task.yml' >> .pathsこうすることで環境変数のPATHS_FILEが指定される時以外は、
oas_docs/src/paths/task.yml
に関してのAPIドキュメントに関してだけしか表示されなくなります。$ bundle exec rake routes:oas:ui I, [2020-03-30T12:00:39.428227 #22297] INFO -- : [R2-OAS] start I, [2020-03-30T12:00:39.543178 #22297] INFO -- : [Generate OAS schema files] start I, [2020-03-30T12:00:39.543224 #22297] INFO -- : [Generate OAS schema files] end I, [2020-03-30T12:00:39.543237 #22297] INFO -- : [Generate OAS docs from schema files] start I, [2020-03-30T12:00:39.543595 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/openapi.yml I, [2020-03-30T12:00:39.543683 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/external_docs.yml I, [2020-03-30T12:00:39.543797 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/tags.yml I, [2020-03-30T12:00:39.543882 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/info.yml I, [2020-03-30T12:00:39.544091 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/servers.yml I, [2020-03-30T12:00:39.544328 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/task.yml I, [2020-03-30T12:00:39.544437 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/components/schemas/task.yml I, [2020-03-30T12:00:39.544537 #22297] INFO -- : Use schema file: /Users/yukihirop/RubyProjects/example-600/oas_docs/src/components/requestBodies/task.yml I, [2020-03-30T12:00:39.552871 #22297] INFO -- : [Generate OAS docs from schema files] end wait for single trap ...pahtsファイルの一覧が知りたい
PATHS_FILEを指定して書くと軽くなるといってもpathsファイルのyamlファイルのpathを調べるのがだるい。
その問題のために一覧を出すコマンドがあります。(ただ動作が遅いのでshellスクリプトで解決したがいいかもしれません。)$ bundle exec rake routes:oas:paths_ls /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/action_mailbox/ingresses/postmark/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/action_mailbox/ingresses/sendgrid/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/action_mailbox/ingresses/mandrill/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/action_mailbox/ingresses/mailgun/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/action_mailbox/ingresses/relay/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/active_storage/disk.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/active_storage/representation.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/active_storage/blob.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/active_storage/direct_upload.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/user.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/api/v1/account.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/api/v2/custom_post.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/task.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/rails/conductor/action_mailbox/inbound_email.yml /Users/yukihirop/RubyProjects/example-600/oas_docs/src/paths/rails/conductor/action_mailbox/reroute.ymlcool-pecoを使った便利なスクリプト
pecoを便利につかうためのcool-pecoを使って便利スクリプトを書いておくといいです。
api-editor
・api-ui
で pathsファイルを選択してEnterでSwaggerを開くことができるようになります。pecoでAPIドキュメント編集
#pecoでAPIドキュメント編集 function peco-api-editor(){ local unit_paths_file_path=$(find . -type f -name "*.yml" | grep paths | peco) if [ -n "$unit_paths_file_path" ]; then res="PATHS_FILE=$unit_paths_file_path bundle exec rake routes:oas:editor" fi _cool-peco-insert-command-line $res } alias api-editor=peco-api-editorpecoでAPIドキュメント閲覧
#pecoでAPIドキュメント閲覧 function peco-api-ui(){ local unit_paths_file_path=$(find . -type f -name "*.yml" | grep paths | peco) if [ -n "$unit_paths_file_path" ]; then res="PATHS_FILE=$unit_paths_file_path bundle exec rake routes:oas:ui" fi _cool-peco-insert-command-line $res } alias api-ui=peco-api-uiおわりに
次回は9月に進捗を報告します。
目標は5個/週
です。
- 投稿日:2020-03-31T19:22:16+09:00
【超初心者向け】RubyをインストールしたらRubyで遊んでみよう!!その1
※本記事はRubyがインストールされた前提の記事です。
Rubyをインストールしたあと、とにかくRubyをいろいろ触ってみて慣れていくための記事です。お役に立てば幸いです。
環境
Ruby 2.5.1
MacOS Mojave Ver.10.14.6インタラクティブRuby(irbコマンド)
ターミナルから直接Rubyのプログラムを動かす「対話シェル」機能を起動させます。irbは「interactive Ruby」の略です。この機能は本来の手順である
【コードを記述】▶︎【ファイルを実行】ではなく、
【コードを常に読み込み】▶︎【実行】してくれる為Rubyの簡単な動作確認などに重宝します。操作法
MacOSの場合、Terminalを立ち上げてirbと入力し、enterキーを押します。
Terminalirb(main):001:0>このような画面になったら「対話シェル」が起動しています。次に"Hello World"と入力してください。
irb(main):001:0> "Hello World" => "Hello World"と表示されていれば成功です。お疲れ様でした。
- 投稿日:2020-03-31T18:19:36+09:00
Rails ウィザード形式導入について 1
はじめに
Qiitaサボっておりましたが、学習は継続してしっかりやっております!
むしろチーム開発を通じて、アプリ開発が楽しくてたまらない状態です!
しかし、サボりっぱなしは気持ちよくないので、リスタートさせてください(泣)上述の通り、チーム開発でフリマサイトを開発致しました。
その際、ユーザーの新規登録画面でウィザード形式を導入致しましたので、内容を整理します。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。ウィザード形式とは
- 世に出ているアプリ等でも見かける画面が切り替わりながらユーザー等の登録を行うもの
- ウィザード形式とは、対話するように順番に操作が進んでいくインターフェースのこと
なぜウィザード形式が必要なのか
- 使いやすくなる
- UXのクオリティが高まる
私自身も「使いやすい」、「何がどこにあるのか」が分かり易いアプリは、いい印象です。
え? そんなところをクリックできたのか!
マイページに飛んで、また入力か。それらを回避できるイメージです!
前提条件
- 今回はuser情報に併せて、destination(住所)情報をウィザード形式で入力できる
- deviseは導入済み
- deviseのデフォルト状態での新規登録・ログイン機能は実装済み
では早速!
destinationsモデルの設定
- destinations(住所)情報の実装をするので、マイグレファイルを設定します!
db/migrate/20XXXXX.rbclass CreateDestinations < ActiveRecord::Migration[5.2] def change create_table :destinations do |t| t.integer :post_code t.text :destination t.references :user t.timestamps end end endバリデーション、アソシエーションの設定
- まずはdestinationの方から!
app/models/destination.rbclass Destination < ApplicationRecord belongs_to :user, optional: true validates :post_code, :destination ,presence: true end
- 続いて、userの方も!
app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :name, :age ,presence: true has_one :destination enddeviseのカスタマイズ
deviseのコントローラの作成
- 編集(ウィザード形式実装のため)できるようにする為に、必要となります。
% rails g devise:controllers users
しかし、このままでは、devise管理化のコントローラーが呼ばれてしまいます。
呼びたいのはDevise::RegistrationsControllerを継承したUsers::RegistrationsControllerです!
% rails routesで確認してくださーい!
例えばですが、controller#Actionのdevise/registrations#newです。
ルーティングの設定
- どのコントローラを参照するのか設定
config/routes.rbRails.application.routes.draw do devise_for :users, controllers: { registrations: 'users/registrations', } root to: "top#index" endここでもう一度
% rails routesで確認してくださーい!
rails routesをすると、参照するコントローラが変更されていることが確認できます。
例えばですが、
controller#Actionのdevise/registrations#new
↓
controller#Actionのusers/registrations#new
になっているかと思います!今行ったことは、Devise::RegistrationsControllerを継承したUsers::RegistrationsControllerを作成したイメージです。
続きは次回!
さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
- 投稿日:2020-03-31T18:05:24+09:00
everydayrailsで Selenium::WebDriver::Error::WebDriverError: がでた (geckodrive)
macosです。
追記: すいません。この記事ではfirefoxを使えるようにしたのですが、chromeを使うべきだそうです。
「ドライバのダウンロード」
Unable to find Mozilla geckodriver.
というエラー文が出ていたので、(実際に出たエラー文cpし忘れたのでこれじゃないかもしれませんがほぼこれです) geckodriver をダウンロードする。ダウンロードは
https://github.com/mozilla/geckodriver/releases
このURLからした。macos,linux,winなどいくつか種類があるので自分のPCにあったのを選ぶ。
「ドライバをPATHに置く」
とりあえず初心者でPATHの設定が初めてだったのでディレクトリをDesktopに作成し、そこにブラウザでダウンロードしたgeckodriveを入れといた。
実際にPATHを通す
ターミナルで一応
$ echo $PATH
でPATHを確認(しなくていいけど)すると
/いつも通り出てくるデフォルトのPATH/
になってる
$ export PATH=$PATH:/Users/ユーザー名/Desktop/geckodriverを入れたディレクトリ名
でPATHを追加もう一回
$ echo $PATH
で確認してみると
/いつも通り出てくるデフォルトのPATH/Users/ユーザー名/Desktop/geckodriveを入れたディレクトリ名
になってた。これでPATHは通せたと思います。(違ったらすいません)
bin/rspec spec/features/tasks_spec.rb でテストしてみる
Could not find Firefox binary (os=macosx).
Firefoxが見つからないというエラー
$ brew cask install --appdir="/Applications" firefox
でHomebrewからダウンロード
これで
$ bin/rspec spec/features/tasks_spec.rb
が成功しました/usr/local/bin に保存する
上記の環境変数PATHを通すやり方では、ターミナルを消したときこの設定も消えてしまうので
/usr/local/bin という場所に保存する
/usr/local/bin
はユーザが追加のパッケージをインストールした場合の実行ファイルを保存する場所らしい。デフォルトでは存在しないので /usr/local/bin をsudoコマンドを使い作る
sudo mkdir /usr/local/bin
使えるようにしたいファイルを作成したPATHへ移動させる
sudo mv 移動させたいファイル名 /usr/local/bin/新しいファイル名
保存できたか確認する
which 確認したいファイル名
出力結果は
/usr/local/bin/geckodriver
なので保存できた
ターミナルを一回消して bin/rspec spec/features/tasks_spec.rb
通ったのでとりあえずオッケー。
環境変数PATHに関しては
https://reffect.co.jp/windows/full_understanding_mac
を参考にしました。ありがとうございました。間違っている箇所など見つけた場合コメントしていただけたら幸いです。
- 投稿日:2020-03-31T17:13:32+09:00
Rails 404エラー画面を設定した時にrefileで設定した画像が表示されなくなる
概要
備忘録代わりに書かせていただきます
Railsでroutesの最下行に
routes.rbget '*path', to: 'application#render_404',でどのパスにもいかなかった場合に404エラーを独自で出力するように設定した場合に、
Refile等で指定されたattachment_image_tagの画像が表示されない。原因
ログを見たらすぐに分かるんですけど、attachment_image_tagでURLを生成して、GETを送ってRoutesを通る時にrefileではroutesの設定が無いので、当てはまるパスがなく404のgetを返してしまうという話。
解決法
もっと綺麗なやり方があるのかもしれないですけど、とりあえずRoutesのconstraintsを使ってrequestオブジェクトのurlに"attachments/"が含まれている場合は404の行を通らないようにして回避しました。
もっといい方法100%あるような気がするので、よかったらコメントで教えていただけると嬉しいです。
routes.rbclass ErrorAvoid def initialize @url = "attachments/" end def matches?(request) @url.include?(request.url) end end Rails.application.routes.draw do get '*path', to: 'application#render_404', constraints: ErrorAvoid.new endとりあえず当面はこれで回避できます。
- 投稿日:2020-03-31T13:34:45+09:00
findとfind_byの違いを初心者がまとめてみました。
この記事ではfindとfind_byの違いについて分かりやすく伝わるように書いてみようと思います。
わかりにくいところがあれば参考記事も確認して、しっかりと理解していただければ幸いです。findとは
- idを検索キーとして、取得したいモデルから特定のデータを取得する方法
- findを使用する場合には、id以外では検索できない
- 要するに、取得したいデータのidが分かっている場合に使用するといい
- 検索の仕方は モデル名.find(id) 例:User.find(1)
使用方法
例えばUserモデルにあるtaroさんのデータが欲しいとします。
その場合、findで検索するとなると id で検索してあげる必要があります。Userモデル
id name age 1 taro 23 2 jiro 20 3 sabu 18 User.find(1) →ユーザモデル(User)から、idが1(find.(1))のものを取得こうすればtaroさんのインスタンス(すぐに使用できるデータ)が取得できます。
挙動は2.5.3 :001 > user1 = User.find(1) User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] => #<User id: 1, name: "taro", age: 23, created_at: "2020-03-31 02:27:04", updated_at: "2020-03-31 02:27:11">このように流れてきます。
そしてこのようにすればidが1(taroさん)のageだけを取り出すことができます。2.5.3 :002 > user1.age => "23"find_byとは
- id以外のカラムを指定して、1つのデータを取得する方法(idでも検索可能)
- id以外の値が分かっているときに使用できる
- 複数の条件指定が可能
- 値として返ってくるのは、条件にヒットした最初の1件のみ
- 検索の方法は モデル名.find_by(カラム名: 値) 例:User.find_by(name: "taro")
使用方法
例えばUserモデルにあるjiroさんのデータが欲しいとします。
その場合、find_byで検索するとなると カラム名: 値 で検索して上げる必要があります。Userモデル
id name age 1 taro 23 2 jiro 20 3 sabu 18 User.find_by(name: 'jiro') →ユーザモデル(User)から名前がjiro(name: 'jiro')のデータを取得と言う風になります。こうすればnameがjiroさんのデータを取り出すことができます。
挙動は2.5.3 :001 > user = User.find_by(name: 'jiro') User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "jiro"], ["LIMIT", 1]] => #<User id: 2, name: "jiro", age: 20, created_at: "2020-03-31 02:27:26", updated_at: "2020-03-31 02:27:26">このように流れてきます。そして、find_byでは 値として返ってくるのは条件にヒットした最初の1件のみ が返ってきます。
どういうことかと言うと
年齢が20才の2人がいたとします。Userモデル
id name age 1 taro 23 2 jiro 20 3 sabu 20 このような場合にfind_byを使用して User.find_by(age: 20) としても sabuさんのデータは取れません。
2.5.3 :001 > user = User.find_by(age: 20) User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."age" = ? LIMIT ? [["age", 20], ["LIMIT", 1]] => #<User id: 2, name: "jiro", age: 20, created_at: "2020-03-31 02:27:26", updated_at: "2020-03-31 02:27:26">idを順にみていくので、ageが20である最初のデータはidが2のjiroさんになってしまいます。なので、sabuさんのデータを取ろうと思うと、別の条件でとるしかないということになります。
また、 複数の条件指定が可能 というのはこのようにします。
例えば、兵庫県出身の20才のデータを取得したい時にはUserモデル
id name age pref 1 taro 23 大阪 2 jiro 20 東京 3 sabu 20 兵庫 2.5.3 :002 > user = User.find_by(age: 20, pref: '兵庫') User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."pref" = ? AND "users"."pref" = ? LIMIT ? [["age", 20], ["pref", "兵庫"], ["LIMIT", 1]] => #<User id: 3, name: "sabu", age: 20, pref: "兵庫", created_at: "2020-03-31 02:27:35", updated_at: "2020-03-31 03:49:24">このようにすれば、複数条件に当てはまる最初のデータが返ってきます。
また、find_byで取り出したデータもインスタンスなので、このようにすれば指定のカラムのデータを取得することができます。2.5.3 :003 > user.name => "sabu"データが見つからなかった時の違い
findの場合
例えば下のようなUserモデルがあったとして、間違えて User.find(4)と存在しないidを指定したとします。
Userモデル
id name age 1 taro 23 2 jiro 20 3 sabu 20 2.5.3 :004 > user = User.find(4) User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Traceback (most recent call last): 1: from (irb):4 ActiveRecord::RecordNotFound (Couldn't find User with 'id'=4)このように返ってきます。
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=4)ここでは、idが4のデータは見つかりませんでした。といった エラー が返ってきます。エラーが返ってくるとエラー画面が表示され、動かなくなってしまいます。
find_byの場合
同じUserモデルを使用して 間違えて User.find_by(name: 'gonta') と存在しないnameを指定したとします。
2.5.3 :005 > user = User.find_by(name: 'gonta') User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ? [["name", "gonta"], ["LIMIT", 1]] => nilこのように エラー ではなく nil が返ってきます。
nilが返ってくるということは、エラー画面は表示されずに処理が進みます。要するにどういうことか
例えばこのようなfindを使ったif文を書いたとします。
user = User.find(4) if user puts 'ユーザが見つかりました。' else put 'ユーザが見つかりませんでした。' endこの場合、userには何も代入されておらず、エラー画面が表示されて動きません。
しかし、find_byを使ったif文にするとuser = User.find_by(id: 4) if user puts 'ユーザが見つかりました。' else put 'ユーザが見つかりませんでした。' endこの場合には、userにはnilが代入されていることになり、if文のelseが適応となって ユーザが見つかりませんでした と出力されることになります。
まとめ
findとfind_byの違いってサービスを開発してみるまでは、正直意味が分かりませんでした。
違いをしっかり理解して使っていくようにしましょう。
最後まで読んでいただきありがとうございました。参考にした記事
find、find_by、whereの違い
【Rails初心者必見!】ひたすら丁寧にデータ取得を説明(find, where)
大変参考になりました。ありがとうございます。
- 投稿日:2020-03-31T10:19:09+09:00
heroku で Active Storage を通して GCS に接続時 Neither PUB key nor PRIV key: nested asn1 error が発生する
*ローカル環境では正しく接続できている前提です
ローカルで動いてもherokuで動かない
ローカル環境では正常に接続できていてもherokuにデプロイすると
Neither PUB key nor PRIV key: nested asn1 error
が発生する
エラー時のstorage.ymlstorage.ymlgoogle: service: GCS credentials: type: "service_account" project_id: "" private_key_id: "<%= Rails.application.credentials.private_key_id %>" private_key: "<%= Rails.application.credentials.private_key %>" client_email: "" client_id: "" auth_uri: "" token_uri: "" auth_provider_x509_cert_url: "" client_x509_cert_url: "" project: "My First Project" bucket: "hogehuga"credentialsを利用して秘密鍵を渡していた
herokuでコンソールを叩いても正常に読み込めているheroku側で改行がうまくいかないという情報もあったので
private_key: "<%= Rails.application.credentials.private_key.gsub("\\n", "\n") %>"
に変更したが、同様のエラーが発生した解決策 直接渡す
storage.ymlを
private_key_id: "<%= ENV['PRIVATE_KEY_ID'] %>" private_key: "<%= ENV['PRIVATE_KEY'] %>"
heroku config:set
でherokuの環境変数に直接秘密鍵をそのまま挿入
これで正常に接続でき、画像の保存と読み込みが行えます結論
credentials から値を持ってくるときにheroku側で何らかの想定しない処理が行われてしまっていると思われる
解決はしましたが、詳しい原因が分かっておりません
詳細がわかる方いましたらコメント頂けると幸いです
- 投稿日:2020-03-31T09:21:52+09:00
あなたの日本語をRails語に翻訳する辞書 データベース編
はじめに
TECH CAMPというプログラミング教室に40日ほど通った添野です。
本日はRailsで重要な概念「データベース」という概念を説明していきます。皆さんはRailsにおける「データベース」が何なのか説明できるでしょうか?
この記事を読めば、かなり具体的に説明できるようになります。※MySQLの使用を前提に記事を書いています
結論
データベースとは「配列に入った配列に入ったハッシュ」です。
わかりやすく説明するため、徐々に進化させて説明していきます。値
雑魚敵。ドラクエでいう「スライム」です。
最終的にビューで表示したいのはこいつです。りんご
配列
雑魚敵の集合体です。ドラクエでいう「キングスライム」です。[りんご , ゴリラ , ラッパ] 簡略化すると: [A,B,C]
配列に入った配列
キングスライムの集合体です。キングスライムって進化すんの・・・?
Rubyというゲームの場合は無限に進化します。[ [りんご , みかん , バナナ] , [ゴリラ , サル] , [ラッパ , ピアノ, トランペット , ギター] ] 簡略化すると: [ [A,B,C] , [D,E,F] , [G,H,I] ]
ハッシュ
ラスボスです。ドラクエでいうゾーマです。
Railsではこいつを「レコード」と呼びます。{名前: りんご, 値段: 100 , 色: 赤} 簡略化すると: { A:a, B:b , C:c }
配列に入ったハッシュ
歴代ドラクエのラスボスが合体した恐るべき存在です。
レコードがいっぱい並びます。つまり、Railsではこいつを「テーブル」と呼びます。[ {名前: りんご, 値段: 100 , 色: 赤} , {名前: みかん, 値段: 200 , 色: 橙} , {名前: バナナ, 値段: 60 , 色: 黄} ] 簡略化すると: [ {A:a, B:b, C:c} , {D:d, E:e, F:f} , {G:g, H:h, I:i} ]
配列に入った配列に入ったハッシュ
様々なゲームの歴代ラスボスを集めてそれぞれ合体させた存在を、さらに合体させた存在です。恐るべき最終形態。テーブルがいっぱい並びます。つまり、こいつがRailsにおける「データベース」の正体です。[ [ {名前: りんご, 値段: 100 , 色: 赤} , {名前: みかん, 値段: 200 , 色: 橙} , {名前: バナナ, 値段: 60 , 色: 黄} ] , [ {名前: ゴリラ, 年齢: 30 , 性別:オス , 性格: 乱暴} , {名前: サル, 年齢: 10 , 性別:メス , 性格: おとなしい} ] , [ {名前: ラッパ, 種別: 金管楽器} , {名前: ピアノ, 種別: 弦楽器} , {名前: トランペット, 種別: 金管楽器 } , {名前:ギター, 種別: 弦楽器} ] ] 簡略化すると: [ [ {A:a, B:b, C:c} , {D:d, E:e, F:f} , {G:g, H:h, I:i} ] , [ {J:j, K:k, L:l} , {M:m, N:n, O:o} , {P:p, Q:q, R:r} ] , [ {S:s, T:t, U:u} , {V:v, W:w, X:x} , {Y:y, Z:z, Ω:ω} ] ]
さて、「データベース」のことが分かってきたのではないでしょうか。
上記の「配列に入った配列に入ったハッシュ」を少し分解してみると、以下のように分けられます。
「果物」が入ってる配列[ {名前: りんご, 値段: 100 , 色: 赤} , {名前: みかん, 値段: 200 , 色: 橙} , {名前: バナナ, 値段: 60 , 色: 黄} ]「動物」が入ってる配列
[ {名前: ゴリラ, 年齢: 30 , 性別:オス , 性格: 乱暴} , {名前: サル, 年齢: 10 , 性別:メス , 性格: おとなしい} ]「楽器」が入っている配列
[ {名前: ラッパ, 種別: 金管楽器} , {名前: ピアノ, 種別: 弦楽器} , {名前: トランペット, 種別: 金管楽器 } , {名前:ギター, 種別: 弦楽器} ]これらがRailsにおいて、上から順に「果物テーブル」「動物テーブル」「楽器テーブル」と呼ばれるのです。
つまり、Railsのデータベース用語をまとめて説明すると、
- レコードは「ハッシュ」
- テーブルは「配列に入ったハッシュ」
- データベースは「配列に入った配列に入ったハッシュ」
です。
日本語をRails語に翻訳する
それでは、実際にデータベースから値を取り出します。
様々なゲームのラスボスが集結合体した恐るべき存在を、勇者の剣で「スライム」になるまで切り刻みます。今回のゴールは「果物テーブル」から「りんご」「みかん」「バナナ」を取り出すことにします。
まずはデータベースから「果物テーブル」を取り出す必要がありますね。日本語:データベースから「果物テーブル」を取り出す→ Rails語:「果物.all」
(テーブル名).all
とすると、そのテーブルだけ取り出せます。
まずは「いろんなゲームのラスボス集団」を「ドラクエのラスボス集団」まで刻みます。果物.all 結果: [ {名前: りんご, 値段: 100 , 色: 赤} , {名前: みかん, 値段: 200 , 色: 橙} , {名前: バナナ, 値段: 60 , 色: 黄} ]次は「果物テーブル」から「レコード」を取り出す必要があります。
日本語:「果物テーブル」から「レコード」を取り出す→ Rails語:「果物.all.each do |f| f end」
(テーブル名).all.each do |変数| 変数 end
とすると、全てのレコードを取り出すことができます。この.each do
というのは重要な呪文なので覚えましょう。読み方は「ドットイーチドゥー」です。.each do|変数|
の変数
は適当に決めちゃってオッケーです。今回はf
にしました。これを使って「ドラクエのラスボス集団」を「ドラクエのラスボス1体」まで刻みます。果物.all.each do|f| puts f end 結果: {名前: りんご, 値段: 100 , 色: 赤} {名前: みかん, 値段: 200 , 色: 橙} {名前: バナナ, 値段: 60 , 色: 黄}あとは出てきたラスボスがスライムになるまで切り刻むのみです。
日本語:「レコード」から「名前」を取り出す→ Rails語:「果物.all.each do |f| f.名前 end」
(テーブル名).all.each do |変数| 変数.(カラム名) endと書くと指定したカラムのレコードを取り出せます。ここでいう「カラム」はハッシュにおける「キー」のことです。つまり今回は「名前」です。
果物.all.each do|f| puts f.名前 end 結果: りんご みかん バナナおめでとうございます。ついに「果物テーブル」から「りんご」「みかん」「バナナ」を取り出すことに成功しました。実際に使う上では、ビューファイル上では以下のように記載します。
ERBの場合
index.html.erb<% 果物.all.each do|f| %> <%= f.名前 %> <% end %>hamlの場合
index.html.maml- 果物.all.each do|f| = f.名前他にも、pictweetで「Tweetsテーブルのnameカラムの情報を一覧表示したい」なら、コードは以下になります。
ERBの場合
index.html.erb<% Tweet.all.each do|t| %> <%= t.name %> <% end %>hamlの場合
index.html.maml- Tweet.all.each do|t| = t.nameまだ少しだけしっくりこないかもしれません。
私のpictweetだとTweet.all
じゃなくて@tweets
みたいな書き方だよ!という方。
コントローラーのファイルを開くと、こんな感じのモノが書かれてないでしょうか。def index @tweets = Tweet.all endこれはデータベースからTweetsテーブルを取り出して
@tweets
という変数(配列)にぶち込め!という意味です。MVCの流れって「コントローラ」の後に「ビュー」なので、先にこれが読み込まれているのです。だからビューで@tweets
というものを、Tweet.all
の代わりに使えます。そしてビューにはこんな事を書きますね。
<% @tweets.each do |tweet| %> <div class="content_post" style="background-image: url(<%= tweet.image %>);"> <%= simple_format(tweet.text) %> <span class="name"> <%= tweet.name %> </span> </div> <% end %>ゴチャゴチャしてますが、見るべきところはちゃんと決まっています。
まずは1行目の@tweets.each do |tweet|
。これはラスボス集団をラスボス一体まで刻む処理でした。そしてよく見てください、3行目と5行目です。
tweet.text
とか、tweet.name
って書いてあります。
これはレコードからカラムを取り出す、つまりラスボスを雑魚敵になるまで刻む処理です。
tweet.text
の起源を辿って書くとTweet.all.each do|tweet| tweet.text end
です。
これを日本語→Rails語訳を使って逆翻訳すると「データベースのTweetsテーブルから、textカラムを取り出せ」
になる訳です。これにて、データベースにおけるRails語を日本語訳することも可能になりました。
まとめ
データベースとは「レコードというハッシュがテーブルという配列に入ったものをデータベースという配列に入れたもの」です。
取り出し方
「データベースから〇〇テーブルを取り出す」
→〇〇.all
「データベースから取り出した〇〇テーブルから、レコードを取り出す」
→〇〇.all.each do |変数| 変数 end
「データベースから取り出した〇〇テーブルのレコードから、××カラムを取り出す」
→〇〇.all.each do |変数| 変数.×× end
あとがき
いかがでしたでしょうか。他にもwhereメソッドやparamsといった概念がデータベースの理解には必要ですが、全てはここに書いてある知識がベースとなった概念です。記事の内容を理解することができれば、自ずと他の概念も理解できるようになるはずです。
この記事が、皆様のご理解の一助となりましたら幸いです。
それでは。
- 投稿日:2020-03-31T08:45:37+09:00
vistaでkicad その3
概要
vistaでkicadやってみた。
sketchupで、vrml書いて、kicadで読み込んで見た。環境
windows vista 32bit
kicad 4.0.4
sketchup 8sketchupでbox書く。
skp_to_vrml.rbで出力。
#VRML V2.0 utf8 Shape { geometry IndexedFaceSet { coord Coordinate { point [ 1.000000 0.000000 -1.000000 , 0.000000 0.000000 -0.000000 , 0.000000 0.000000 -1.000000 , 0.000000 0.000000 -0.000000 , 1.000000 0.000000 -1.000000 , 1.000000 0.000000 -0.000000 , 1.000000 1.000000 -0.000000 , 0.000000 1.000000 -1.000000 , 0.000000 1.000000 -0.000000 , 0.000000 1.000000 -1.000000 , 1.000000 1.000000 -0.000000 , 1.000000 1.000000 -1.000000 , 1.000000 1.000000 -0.000000 , 0.000000 0.000000 -0.000000 , 1.000000 0.000000 -0.000000 , 0.000000 0.000000 -0.000000 , 1.000000 1.000000 -0.000000 , 0.000000 1.000000 -0.000000 , 0.000000 1.000000 -1.000000 , 0.000000 0.000000 -0.000000 , 0.000000 1.000000 -0.000000 , 0.000000 0.000000 -0.000000 , 0.000000 1.000000 -1.000000 , 0.000000 0.000000 -1.000000 , 0.000000 1.000000 -1.000000 , 1.000000 0.000000 -1.000000 , 0.000000 0.000000 -1.000000 , 1.000000 0.000000 -1.000000 , 0.000000 1.000000 -1.000000 , 1.000000 1.000000 -1.000000 , 1.000000 0.000000 -1.000000 , 1.000000 1.000000 -0.000000 , 1.000000 0.000000 -0.000000 , 1.000000 1.000000 -0.000000 , 1.000000 0.000000 -1.000000 , 1.000000 1.000000 -1.000000 , ] } coordIndex [ 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1, 12, 13, 14, -1, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, -1, 24, 25, 26, -1, 27, 28, 29, -1, 30, 31, 32, -1, 33, 34, 35, -1, ] } appearance Appearance { material Material {} } }kicadでvrmlを読み込む。
以上。
- 投稿日:2020-03-31T07:40:31+09:00
Kinx 実現技術 - Fiber
Fiber
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。作ったものの紹介だけではなく実現のために使った技術を紹介していくのも貢献。その道の人には当たり前でも、そうでない人にも興味をもって貰えるかもしれない。
前回のテーマは Garbage Collection。今回のテーマは Fiber。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
Fiber はこれまで使ったことがなかったのだが、途中で関数を中断できる機能は結構便利かも。効果的な使い道は 誰か教えてください。
尚、今回の記事を書いている途中で当初考えたやり方ではうまく行かないケースがあり、急遽修正しました。今回は反省の意味を含め、その流れも書いておきます。その方が何やっているか分かりやすそうというのもあり。恥ずかしすぎるが致し方ない。むむむ、見落とした…
実現方法
当初の発想
「基本、その時のフレームと実行再開位置が保存されていればうまくいくんじゃね?」
結果
「うまくいったぜ!チョロいもんだ」
本記事を書いてる途中
「マジか、動かねえ。何でだ?つか、あぁ、なるほど。当たり前だ。なぜ気付かなかった俺。」
改めた発想
「スタック状態と実行再開位置が保存されていればうまくいくに違いない」
結果
「かぁさん、俺やったよ!」
やったこと
当初
yield
の時の フレーム と 次回開始位置 を呼び出し元関数オブジェクトに保存。return
の際、フレーム情報はクリアせず に 実行開始位置だけクリアして リターン。これは後で使う。- 次回の関数呼び出しの際、関数オブジェクトに フレーム情報があれば
yield
後の再開とみなす。- 再開と判断した後、実行開始位置がクリアされて いれば
return
したということで FiberException 例外を発行。何がダメ?
- Fiber 中にさらに関数呼び出しされてそこで
yield
された場合、期待する関数オブジェクトにコンテキストが保存されない。- そらそうだ。結局、Fiber 中のスタック状態は全部保存しとかないとダメだった。
具体的にはこの記事の最後の Ruby の例が動かなかったんですね。
修正
- 関数オブジェクトに ファイバーであるという情報 と ファイバー開始時のフレーム以降のスタック と 実行位置 を保持できるフィールドを追加。
yield
の際、ファイバー開始時のフレーム以降のスタックをコピー し、次の実行開始位置 を記録してリターン。return
の際、ファイバーである情報はクリアせず に 実行開始位置だけクリアして リターン。これは後で使う。- 次回の関数呼び出しの際、関数オブジェクトがファイバーとなって いたら
yield
後の再開とみなす。- 再開と判断した後、実行開始位置がクリアされて いれば
return
したということで FiberException 例外を発行。resume
する際、どこからファイバーをスタートさせたかの情報 をスタック上に残しておく(コピー開始地点の記録)。解説
スタック状態について
当初はローカル変数がフレームに格納されているので、フレームを復元すれば良いと単純に考えてしまった。こんな感じ。
ところが、Fiber 中に関数呼び出しするとこんな感じに。これは正しく動かない。
これを正しく動かすためにはこうしないといけない。
今回は、スタックにマーキングするようにした。例外スタックのように実行コンテキストに分離する手もあるが何度も保存・復元する必要があるのでスタックのほうが楽。どちらにしても特急で直したためコード的に若干無駄があるので、後でリファクタリングします。
命令追加
もしかしたらもっと簡単にできたかもしれないが、ファイバー開始マークをするためだけの命令が1つ追加されています。もうちょっと汎用的にしたほうが良かったかな。まぁ、まずは動くことが重要なのでこれで。後でリファクタリングもできるし。
謎の特殊命令
_coroutine
キーワードが追加されていますが、当然、通常 使ってはいけません 。以下のようになっており、実際、return
とほぼ同じ動きをしますが、式を評価する前にスタック上に ファイバー開始したよ! というマークをスタックに残す動作をします。このマークを頼りに、yield
するときにどこまでのスタックを保存しておくのかをサーチします。Fiberクラスの内部定義(ちょっと違うけどイメージ)class Fiber(fiber) { public resume(...arg) { _coroutine fiber(...arg); } }書いててキーワードの位置が意味的に合っていない気がしたので、修正するかも。内部仕様なので、勿論動作は変わらずですが。
GC 対応
あと、忘れてはいけないのが GC でのマーキング。関数オブジェクトがスタックを持っている場合、そこからの参照先にも全部マークさせに行きます。
全部合わせると
具体的な差分は以下です。
はー、やっちまった感が半端ない。一応、直して動くことは確認したけれど。
isAlive
が必要とか、ファイバー例外まわりが多少おかしいので、もう少し修正する予定です。サンプル
Fibonacci
私自身は 良い 使い道がイマイチ(モヤっと)しているのですが、まずはどこかにあった Fiber によるフィボナッチ数列を Kinx で実現してみましょう。
こんな感じに無限ループで
yield
。var fib = new Fiber(&{ var a = 0, b = 1; while (true) { yield b; [a, b] = [b, a + b]; } }); var r = 35.times().map(&(i) => fib.resume()); r.each(&(v, i) => System.println("fibonacci[%2d] = %7d" % i % v));実行。
fibonacci[ 0] = 1 fibonacci[ 1] = 1 fibonacci[ 2] = 2 fibonacci[ 3] = 3 fibonacci[ 4] = 5 fibonacci[ 5] = 8 fibonacci[ 6] = 13 fibonacci[ 7] = 21 fibonacci[ 8] = 34 fibonacci[ 9] = 55 fibonacci[10] = 89 fibonacci[11] = 144 fibonacci[12] = 233 fibonacci[13] = 377 fibonacci[14] = 610 fibonacci[15] = 987 fibonacci[16] = 1597 fibonacci[17] = 2584 fibonacci[18] = 4181 fibonacci[19] = 6765 fibonacci[20] = 10946 fibonacci[21] = 17711 fibonacci[22] = 28657 fibonacci[23] = 46368 fibonacci[24] = 75025 fibonacci[25] = 121393 fibonacci[26] = 196418 fibonacci[27] = 317811 fibonacci[28] = 514229 fibonacci[29] = 832040 fibonacci[30] = 1346269 fibonacci[31] = 2178309 fibonacci[32] = 3524578 fibonacci[33] = 5702887 fibonacci[34] = 9227465よっしゃ、グッジョブ!
Ruby の例をいくつか
Rubyf = Fiber.new do n = 0 loop do Fiber.yield(n) n += 1 end end 5.times do p f.resume end #=> 0 1 2 3 4これを素直に Kinx に書き直してみる。
Kinxvar f = new Fiber(&{ var n = 0; while (true) { yield n; n++; } }); 5.times(&{ System.println(f.resume()); });実行。
0 1 2 3 4お・ん・な・じー。も一つの例も。
Rubydef enum2gen(enum) Fiber.new do enum.each{|i| Fiber.yield(i) } end end g = enum2gen(1..100) p g.resume #=> 1 p g.resume #=> 2 p g.resume #=> 3ただし、Range オブジェクトは今はないので代替手段で。
enum
は Kinx では予約語なので変数名も変えておきます。Kinxfunction enum2gen(enumArray) { return new Fiber(&{ enumArray.each(&(i) => { yield i; }); }); } var g = enum2gen(100.times().map(&(i) => i+1)); System.println(g.resume()); System.println(g.resume()); System.println(g.resume());実行。
1 2 3やったね。
これが動かなかった…
おわりに
やはりそもそも Fiber を使ったことがない、というのが敗因でしょう。色々使ってみよう。
結局 協調 スレッドなので、実際にスレッドである必要はないし、単一スレッドの中でのコンテキスト(スタック状態)を関数オブジェクトに保持して切り替えている、といった実装になっているだけ。スレッドという言葉に惑わされなければこれで悪くない気がしているのですが、何か根本的なところで思い違いをしているようであれば、ぜひぜひ ご指摘ください。
ということで、最初に紹介しようとしたものは紹介しましたね。一先ず、ライブラリの使い方とか、サンプルコードとかを紹介していくフェーズに戻ろうかと思います。
では、次回。
- 投稿日:2020-03-31T06:14:23+09:00
VS codeの初期設定とRuby on Railsの環境設定
初期設定につまづくとかなり時間をロスするので、まとめることにしました
VSCodeの初期設定
VSCode(Visual Studio Code)をインストール
- VSCodeダウンロードページを開く
- Download for Macをクリックして、ダウンロードを完了します
VS Codeに拡張機能を追加
追加する拡張機能
- Japanese Language Pack for Visual Studio Code →日本語表記にします。
- Ruby→Rubyの構文をチェックし、間違った箇所を指摘。
- HTML Snippets→HTMLタグ、CSSタグの入力を補完。
- Better Haml
- zenkaku→全角スペースを知らせてくれます。
- vscode-icons →言語ごとにファイルのアイコンを変えてくれます。
- Docker
実際にインストールする
4. インストールする
5. 反映させるためにvs codeを再起動「command + q」で終了し再度、起動する自動保存する設定
記述したのに、保存できていないと泣くので、自動保存するように設定しましょう
1. vs codeの設定を開く
2. ユーザー設定がひらけているか確認
3. Files: Auto Save「onFocusCange」が選択されていれば完了半角スペースの見分けがつくようにする
- VSCodeのサイドバーより、「管理」→ 「設定」の順に選択。
- 開いたページで「ユーザー設定」タブを開く。
- Editor: Tab Sizeを2に設定。 Editor: Render Whitespaceで「all」を選択。
Finderの設定
1.FInderを開く!
スクリーンショット 2020-03-31 6.29.45.png
2.Finderを選択の上、画面左上の「Finder」をクリック
3.環境設定をクリック
4.サイドバーに「owner」を追加
5.Finderにownerの表示が出る
Ruby on Railsの開発環境を整える
ターミナル#ホームディレクトリに戻す $ cdターミナル$ xcode-select --installHomebrewをインストール
ターミナル$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"途中でエンターキーを押して、進める必要があるので、押し忘れないでください。
インストールされたか確認
:ターミナル
$ brew -v
Homebrew 1.8.0など表示される
Homebrewのアップデート
ターミナル$ brew updateHomebrewの権限を変更
ターミナル$ sudo chown -R `whoami`:admin /usr/local/binRubyをインストール
ターミナル$ brew install rbenv ruby-buildrbenvをどこからも使用できるようにしよう
ターミナル$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profilebash_profileの変更を反映
ターミナル$ source ~/.bash_profilereadlineをinstall
ターミナルのirb上で日本語入力を可能にする設定を行うために、以下のコマンドでインストールターミナル$ brew install readlinereadlineをどこからも使用できるようにしよう
ターミナル$ brew link readline --forcerbenvを利用してRubyをインストール
ターミナル$ RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)" $ rbenv install 2.5.1利用するRubyのバージョンを指定
ターミナル$ rbenv global 2.5.1rbenvを読み込んで変更を反映
ターミナル$ rbenv rehashRubyのバージョンを確認
ターミナル$ ruby -vさきほど指定したバージョンになっていれば、OKです。
MySQLを用意
ターミナル$ brew install mysql@5.6MySQLの自動起動設定
MySQLは本来であればPC再起動のたびに起動し直す必要がありますが、面倒なので自動化
ターミナル$ mkdir ~/Library/LaunchAgents $ ln -sfv /usr/local/opt/mysql\@5.6/*.plist ~/Library/LaunchAgents $ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql\@5.6.plistどこからもmysqlを利用できるように設定
ターミナル# mysqlのコマンドを実行できるようにする $ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.bash_profile $ source ~/.bash_profile # mysqlのコマンドが打てるか確認する $ which mysql # 以下のように表示されれば成功 /usr/local/opt/mysql@5.6/bin/mysqlRailsを用意
bundlerをインストール
Rubyの拡張機能(gem)を管理するためのbundler(バンドラー)をインストール
ターミナル$ gem install bundlerRailsをインストール
ターミナル# インストール $ gem install rails --version='5.2.3' # 再読み込みして反映 $ rbenv rehash # 成功しているかバージョン確認 $ rails -vAppを保存するためのフォルダ(ディレクトリ)を作成する
ターミナル#ホームディレクトリに移動 $ cd ~ #projectsディレクトリの作成 $ mkdir projects $ cd ~/projects
- 投稿日:2020-03-31T01:30:32+09:00
[devise]現在ログインしているユーザ名が表示されない場合の解決策
環境
バージョン ruby 2.6.5 rails 5.2.4.2 devise 4.7.1 目標
現在ログインしているユーザの名前を表示させたい。
問題
@yasuno0327氏が公開していたdevise にusername カラムを追加し、usernameを登録できるようにする。を参考にして実装したところ以下のようなエラーを吐いた。
Errorundefined method `username' for nil:NilClass (意訳) NilClassのnilオブジェクトに`username`メソッドは定義されてないよ解決策
_current_username.html.erb<% if user_signed_in? %> <!-- 変更前--> <%= @user.username %> <!-- 変更後--> <%= current_user.username %> <% end %>解決に至るまでに引っかかったこと
1.エラー文はどういう意味を指しているのか?
どうやら、@userがnilになっていることを指しているらしい。
参考
2.@userがnilになっているのは何故?
インスタンス変数のスコープ外だから値が参照されない?
(正直、理解があやふやです。自分なりにかみ砕けたら、追記なり修正なり行います。)
[復習]各変数のスコープについて
種別 説明 文法 ローカル変数 それぞれのメソッドの中だけで存在しており、メソッドの処理が終了すると失われてしまう変数です。 通常の変数通り インスタンス変数 インスタンスに属する変数で、インスタンスの中からであれば、どのメソッドからでも参照・変更できます。インスタンスごとに作られる変数ですので、インスタンスごとに違う値を保持しています。インスタンス生成後、最初に代入された時点で生成されますが、メソッド内でしか生成できませんので、注意が必要です。 変数名の前に「@」 クラス変数 クラスで共通の変数として生成されますので、同じクラスから生成されたインスタンスすべてで共通の値を持つことになります 変数名の前に「@@」 クラスインスタンス変数 クラスメソッドからのみアクセスできる変数で、メソッド内ではなく、クラス定義内に定義しなければいけません。クラスが定義されると同時に生成され、クラス変数同様、1つのクラスで共通の値を持っています 変数名の前に「@」 引用
3.current_userと@userは何が違うのか?
メソッドか変数かの違い(...だと認識してます。)
current_user @user deviseのヘルパーメソッド userのインスタンス変数