Rails でアプリを作る② RSpec 導入
テストを書いていきます。今回はRSpecを使用します。以下を Gemfile
に追加してください。
[Gemfile]
group :development, :test do # 省略 gem "rspec-rails" end
% bundle
RSpec を設定する
RSpecをインストールします。
% rails g rspec:install create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb
RSpecの出力をドキュメント形式に変更するために、/rspec
を編集します。
[.rspec]
--require spec_helper --format documentation
Railsには、railsコマンド、Rakeコマンド、テストを高速に実行するためのプリローダーであるSpringがデフォルトで付属しています。
Spring is a Rails application preloader. It speeds up development by keeping your application running in the background, so you don't need to boot it every time you run a test, rake task or migration.
binstub
を使用すると、Spring を Rspec で動作させることができます。binstub
を使うには、 gem spring-commands-rspec
を Gemfile
の development
グループに配置する必要があります。Springもコメントアウトされていたのでコメントインしました。
[Gemfile]
group :development do # 省略 gem "spring" gem "spring-commands-rspec" end
% bundle
binstub
を作成します。
% bundle exec spring binstub rspec
* bin/rspec: generated with Spring
アプリケーションの bin
ディレクトリに rspec
という実行ファイルが作成されます。
動作確認をします。
% bin/rspec xxxx/3.0.3/lib/ruby/gems/3.0.0/gems/spring-4.0.0/lib/spring/application.rb:101:in `block in preload': Spring reloads, and therefore needs the application to have reloading enabled. Please, set config.cache_classes to false in config/environments/test.rb.
エラーが出ました。Springはアプリケーションでリロードを有効にする必要があるようです。
https://github.com/rails/spring
Please, make sure config.cache_classes is false in the environments that Spring manages. That setting is typically configured in config/environments/*.rb. In particular, make sure it is false for the test environment.
[config/environments/test.rb]
Rails.application.configure do # 省略 config.cache_classes = false # 省略
もう一度動作確認をします。
% bin/rspec DEBUGGER[spring app | kioku | started 7 mins ago | test mode#97048]: Attaching after process 96821 fork to child process 97048 Running via Spring preloader in process 97048 No examples found. Finished in 0.00044 seconds (files took 0.16712 seconds to load) 0 examples, 0 failures
問題なく動作しました。
最後に、rails g
コマンドで同時生成されるファイルを変更します。
[config/application.rb]
# 省略 module Kioku class Application < Rails::Application # 省略 config.generators do |g| g.test_framework :rspec, fixtures: false, view_specs: false, helper_specs: false, routing_spec: false end end end
続きは次回。
Rails でアプリを作る①
Railsを使う機会があったので、復習のためにアプリを作ろうと思います。
ちょうど資格の勉強をしているので、学習に関連するアプリが良いかなと。エビングハウスの忘却曲線に基づき、復習するタイミングを管理する学習記録アプリです。
アプリの作成
RubyMineでアプリの雛形を作成します。アプリ名は「kioku」としました。
データベースの変更
データベースをPostgreSQLに変更します。rails6からは rails db:system:change
が使えるようになりました。
% rails db:system:change --to=postgresql
を実行します。
このコマンドを実行すると、Gemfile
と config/database.yml
が変更されます。Gemfile
が変更されたので、bundle
コマンドを実行します。
% handle
デフォルトで作成された db/development.sqlite3
は必要ないので削除します。
rails db:create
コマンドでデータベースを作成します。
% rails db:create Created database 'kioku_development' Created database 'kioku_test'
モデルの検討
モデルについて考えます。アプリの登場人物について考えます。
- 学習記録に関する情報
- 復習に関する情報
まず、「学習記録に関する情報」の属性について考えてみます。
- タイトル
- 内容
学習記録の情報モデルを作成します。モデルは rails g model [モデル名] [カラム名:型]
というコマンドで作成します。
% rails g model Task name:string content:string
マイグレーションファイルは、以下のように作成されます。
[db/migrate/20220312000839_create_tasks.rb].
class CreateTasks < ActiveRecord::Migration[7.0] def change create_table :tasks do |t| t.string :name, null: false, default: "" t.string :content, null: false, default: "" t.timestamps end end end
rails db:migrate
を実行してDBに反映させます。
% rails db:migrate
続きは次回。
LaravelとNUXTを使ったプロジェクトの準備
Laravel側
プロジェクトの作成
laravel new ${プロジェクト名}
laravel new synapse_laravel
バージョンを指定する場合
$ composer create-project ”laravel/laravel=6.*” synapse_laravel
サーバーを起動
cd synapse_laravel php artisan serve
API作成
Route::get('/', function() { return 'helloworld'; });
http://localhost:8000/api
に接続するとhelloworld
と表示
NUXT側
プロジェクトの作成
npm create-nuxt-app ${プロジェクト名}
npx create-nuxt-app synapse_nuxt
@nuxtjs/axiosの導入
cd synapse_nuxt npm install --save @nuxtjs/axios
nuxt.config.jsファイルを編集してmodules
に"@nuxtjs/axios"
を追記する
modules: [ "@nuxtjs/axios" ],
サーバーを起動
yarn run dev
http://localhost:3000/
に接続するとロゴの下にsynapse_nuxt
と表示
API使用
page/index.vueファイルを編集
<template> <div class="container"> <div> <Logo /> <h1 class="title"> {{ data }} //synapse_nuxtを編集 </h1> // 省略 </div> </div> </template> <script> export default { async asyncData(app) { //ページコンポーネントがローディングされる前に呼びされる const data = await app.$axios.$get('http://localhost:8000/api') return { data } } } </script>
http://localhost:3000/
に接続するとロゴの下にhelloworld
と表示されていたら成功!!
リーダブルコード第3章「誤解されない名前」の輪読会をした備忘録と感想
毎週月曜日に「リーダブルコード」の輪読会を行っています。 今回は3章を終えた感想や備備忘録を書きます。 3章は、名前が「他の意味と間違えられることはないだろうか?」というテーマです。
誤解されない名前
英語がネイティブでない自分にとって、英語のニュアンスを掴むことは難しいです。
たとえばfilter
という単語。
辞書をひくと
〈水・ガスなど〉をろ過する, こしてきれいにする; …をろ過して取り除く; 〈光・音など〉の一部を除去[カット]する, 遮断する; 〈不要・有害なもの〉を除去する; 〈人・物〉を取捨選択する
とありますが、この説明を見ると「除外する」という意味がありそうです。
しかし、phpでarray_filter
はTRUE
のものを配列で返します。
つまり、「選択をする」という意味をもっています。
このように英語の単語は曖昧なニュアンスを含んでいるので、「選択をする」という意味で名前をつけるならばselect()
とすることで、誤解のない名前になります。
length
という単語も、どういう使われ方をしているかで名前を付けます。
最大の長さという意味で使うのであればmax_length
とします。
さらにlength
という単語自体も曖昧で、「バイト数」なのか「文字数」なのか、はたまた「単語数」なのか?
文字数という意味で使うのであればmax_char
とするのが良さそうです。
正直、ここまでは考えていなかったです・・。 いろんな解釈ができる名前は避け、明確な名前をつけましょう。
限界値と範囲と包含/排他的範囲
「以上」か「より大きい」か?「以下」か「未満」か? この違いで起こるエラーを「off_by_oneエラー」というようです。
off_by_oneエラーを避けるには「>=」と「>」に注意するというのもありますが、誤解されない名前をつけることでも避けることができます。
商品カートの上限値であればCART_TOO_BIG_LIMIT
という名前ではなく、限界値を含むMAX_ITEMS_IN_CART
とつけるべきです。
範囲を指定するときはfirstとlastを使うというのは馴染みが深いです。
print integer_range(start=2, stop=4)
「2, 3」ではなく「2, 3, 4」を表示したいのであれば、(start, stop)ではなく(first, last)を使うというものです。
包含/排他的範囲にはbeginとendを使う。
PrintEventsInRange(“OTC 16 12:00am”, “OTC 17 12:00am”)
PrintEventsInRange(“OTC 16 12:00am”, “OTC 16 11:59.9999pm”)
うーん。。こちらは馴染みがないですが、意識しておかないとついstart
とかlast
とかを使ってしまいそうですね。
ブール値の名前
ブール値の頭にisやhasをつけるのもすでにできていることで、とくに議論はなかったです。 ブール値では否定形は避けるというのも納得です。というか書いててわかりにくいですよね。
× bool disable_ssl = false;
○ bool use_ssl = true;
この項目は共感しやすかったです。
ユーザの期待に合わせる
get
やsize
は「軽量アクセサ」が期待されるというのは、今までまったく意識してこなかったです。
ふつうにDBから取得するときはget
くらいの意識しかなかったですね。
全件取得のときとかは気をつけないとですね。
まだまだ、馴染みがないことも多く、経験の無さを実感します。 とくにユーザが期待することとかは、周りの同僚も意識していなく、結局はチーム内で共通の認識があれば良いねという結論に達しました。 ただ、このような認識の違いがあるということはしっかり覚えておかないと、別のプロジェクトに行ったとき苦労しそうだなと思いました。
【JavaScript】canvasで画像上に座標を指定してブロック枠を描画する方法
- Vue.jsを使用
- 画像を描画
- 画像上に座標を指定してブロック枠を描画
コード
<template> <div> <!-- canvas要素を配置、サイズ、refを指定 --> <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight" /> </div> </template>
<script> export default { data() { return { canvasWidth: 400, canvasHeight: 800 } }, computed: { // 画像のURLを取得しています imageUrl() { return this.$store.getters["images/getImageUrl"] }, // ブロックの各頂点の座標を取得しています coordinate() { retun this.$store.getters["coordinates"/getCoordinate"] } }, async mounted() { // DOMが生成されている必要があるのでmounted内で呼び出し await this.getImageUrl() this.draw() }, methods: { async getImageUrl() { await this.$store.dispatch( "images/getImageUrl", ) }, draw() { // * $refsでcanvas要素を取得 const canvas = this.$refs.canvas // 平面に描画するので2d const ctx = canvas.getContext("2d") // img要素を作成 const img = document.createElement("img") // src属性にURLを指定 img.src = this.imageUrl // 画像の読み込みが終わったあとに描画したいのでloadイベントのあとで処理 img.addEventListener("load", () => { // 元の画像の横幅を取得 const originalWidth = img.naturalWidth // 縮尺を計算 const reducedScale = this.canvasWidth / originalWidth // 座標空間の変形 // 変形を適用する場合には、先に変形を指定してから図形を描画するという順序になります。 // 変形を後から指定しても、先に描画した図形には変形が適用されないので注意してください。 ctx.scale(reducedScale, reducedScale) // 画像の描画、img要素と描画したい位置を指定 ctx.drawImage(img, 0, 0) // 線の太さを指定 ctx.lineWidth = 5 // 線の色を指定 ctx.strokeStyle = "#0f0" // 各頂点を取得 cost xMax = this.Coordinate.x_max cost xMin = this.Coordinate.x_min cost yMax = this.Coordinate.y_max cost yMin = this.Coordinate.y_min // 新しいパスを開始 ctx.beginPath() // パスの始点を移動 ctx.moveTo(xMin, yMin) // どこまで線を引くか指定、右に移動 ctx.lineTo(xMax, yMin) // 下に移動 ctx.lineTo(xMax, yMax) // 左に移動 ctx.lineTo(xMin, yMax) // パスを閉じる ctx.closePath() // 線を描画 ctx.stroke() }) } } } </script>
【Laravel】インストール時のエラー、zip展開できない
$ composer global require laravel/installer
とするとこんなエラーが出ました。
Problem 1 - laravel/installer v3.0.1 requires ext-zip * -> the requested PHP extension zip is missing from your system. - laravel/installer v3.0.0 requires ext-zip * -> the requested PHP extension zip is missing from your system. - Installation request for laravel/installer ^3.0 -> satisfiable by laravel/installer[v3.0.0, v3.0.1]. Installation failed, deleting ./composer.json.
laravel/installer
はPHPのzipの拡張機能を必要としているよ。
でもあなたのsystemにはそれが無いじゃない。
と言っているようです。
どうやらMacにプリインストールされているPHPではzipを展開するext-zip
が入っていないらしい。
$ php --ri zip Extension 'zip' not present.
たしかに無い。
HomebrewでPHPを再インストールします。
$ brew install php@7.3
パスを通します。
$ brew link php@7.3
ターミナルを再起動させて再度Laravelのインストールを行います。
$ composer global require laravel/installer
無事インストールされました。
`chmod`は`chage mode`という意味
$ chmod a+x /usr/local/bin/composer
chmod
とはLinaxコマンドの一つ。
change modeという意味。パーミッションを設定する。
a
がすべての権限。
x
が実行権限。
a+x
はすべてのユーザに実行権限を与える。
これで、いつでもcomposer
を呼び出すことができる。