【Rails】associationを張ったModelを生成する時のmigrationの記述
一人のユーザは一つのプロフィールを有する、というようなAssociationをつくってみる
1:1です
前提
以下のような構成を目指す
User
- name
- profile_id
Profile
- text
モデルはこうなる
class User < ApplicationRecord belongs_to :profile end class Profile < ApplicationRecord end
こんな感じのことをしたい
p = Profile.new(text: 'hello') p.save! u = User.new(name: 'test user', profile: p) u.save! User.first.profile.name # 'hello'
Profileの生成は特に迷うことはない
rails g model profile text:string
db/migrate/yyyyMMddHHmmss_create_profile.rb
class CreateProfiles < ActiveRecord::Migration[5.2] def change create_table :profiles do |t| t.string :text t.timestamps end end end
で、Userを作っていく時に色々間違えたのでそのメモ
結論からいうと...
上記の
User
- name
- profile_id
こんな感じにUserにprofile_idを持たせてあげて、Modelにbelongs_to :profile
の記述するだけではダメで、
schema.rbにもbelongs_toが記述されていないと、正しくActiveRecordのassociationが効いてくれない
正しいパターン
rails g model user name:string profile:belongs_to
※belongs_toはreferenceでもよい
参考:
belongs_to
is an alias ofreference
https://stackoverflow.com/questions/7788188/what-is-the-difference-between-t-belongs-to-and-t-references-in-rails
このgenerateコマンドによって上記のModelと以下のmigrationファイルが生成される
db/migrate/yyyyMMddHHmmss_create_user.rb
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| # ↓が必要な行 # ついでにprofilesじゃなくて単数形のprofileであることにも注意 t.belongs_to :profile, foreign_key: true t.string :name t.timestamps end end end
:nameがt.string
、つまりstring型であるように
:profileは reference型 という型になる (belongs_to型とはあんまり言わない)
このreference型の:profileが、カラムprofile_idを生成してくれる
メモ:
ソース的には
ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference のあたり
add_reference(:table_name, :reference_name):
Adds a new column reference_name_id by default an integer.
ややこしい話はさておき、Migrationを適用するとこうなる
schema.rb
ActiveRecord::Schema.define(version: yyyy_MM_dd_HHmmss) do create_table "profiles", force: :cascade do |t| t.string "text" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.integer "profile_id" t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["profile_id"], name: "index_users_on_profile_id" # ここがポイント! end end
勘違いしてた失敗パターン
こんな感じただUserにprofile_idを持たせてあげて、Modelに
belongs_to :profile
の記述するだけではダメで、 schema.rbにもbelongs_toが記述されていないと、正しくActiveRecordのassociationが効いてくれない
これをやってしまったパターン
rails g model user name:string profile_id:integer # 正しいのは↓ # rails g model cat name:string profile:belongs_to
db/migrate/yyyyMMddHHmmss_create_user.rb
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :name t.integer :profile_id # 正しいのは↓ # t.belongs_to :profile, foreign_key: true t.timestamps end end end
Migrationを適用するとこうなる
schema.rb
ActiveRecord::Schema.define(version: yyyy_MM_dd_HHmmss) do create_table "profiles", force: :cascade do |t| t.string "text" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| t.integer "profile_id" t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false # ↓が足りてない # t.index ["profile_id"], name: "index_users_on_profile_id"0 end end
職場が変わって初めてのスクラム開発が辛い
打ち合わせが長い(多い)
打ち合わせの例・内容
スクラムのイベントとして行う 今の現場ではスプリントの期間は1週間
スプリントのキャパシティを明らかにする方法 – Ryuzee.com
以下は強制での参加 (言い方は悪いが便宜上...)
イベント | 頻度 | 時間 | 備考 |
---|---|---|---|
プランニング | 週1 | 2h | よく3hまで伸びる。一番辛い |
レビュー | 週1 | 1h | |
レトロスペクティブ | 週1 | 1h | |
朝打ち合わせ | 毎日 | 0.5-1h | 細かい仕様・実装の話になると2hくらいにも |
夕打ち合わせ | 毎日 | 0.5-1h | 同上 |
その他、任意参加で仕様や実装の相談などが週に[0.5h|2h]*2程度あったりなかったりする
打ち合わせが長いと何が辛い
- 開発する時間が少なくなる
- 残業している人が多いように思えるが
- 長時間の拘束
- 会話の内容がわからない
- これはそもそもまだドメイン知識や技術知識がないからだろうけど
打ち合わせはなぜ長い
- イベントが多い
- メンバーが多い?
- 開発規模が大きい?
- プランニングほか実装の相談は必然的に増える
- 込み入った話をしすぎる
- プランニング然り、朝夕打ち合わせ然り
- 仕様が固まっていない箇所の実装の話が出る
打ち合わせを短くする・減らすために
- イベントを減らす・頻度を下げる
- プランニングは頻度を下げても合計時間は変わらなそう
- レトロスペクティブは2週間に1回くらいでいいのではないか
- 不要だと思っている訳ではないけど、毎週じゃなくてもいいと思う
- それってスクラム的に許されるの?
- 打ち合わせ中に別件で込み入った話になりそうだったら別途打ち合わせを設ける
- 打ち合わせを行う前にはゴールを決める
流れで別の打ち合わせに入るとゴールが不明瞭になりやすい
- 打ち合わせを行う前にはゴールを決める
- プランニングで込み入った話をしない
- 現状細かい実装の話までしている
- 開発の内容(画面がどう変わる)とかはチームに共有すべきだと思うけど詳細な実装まで共有する必要ある?
- 正直自分が担当すると決まっていない限り実装箇所なんて覚えられない
- 覚えられない話なら全体にせずメモとして書き残す程度でいいのではないか
- 正直自分が担当すると決まっていない限り実装箇所なんて覚えられない
- 打ち合わせが長くなったら休憩をいれる
- う~ん...
もともと仕様詰め・実装相談・チーム改善などについて打ち合わせをすること自体は嫌いではなかった
でもそれは打ち合わせ自体がそもそも少なくて開発の中でたまに起こるイベントとして楽しみだったから?
上記の話を共有する前に、スクラムの各イベントの目的や前提を勉強しないといけないと思う
もしスクラムの定義を崩壊させるような提案だったなら僕はスクラム開発に向いてないのかもしれない
【Go】interface{}とは一体なんなのか
interfaceじゃなくてinterface{}について
どっちもinterfaceだけど僕的には分けて考えたほうが良いと思った
この人の言っていることが大変しっくりくる
(淡白な学習は僕に毒だから、こういう人間の所感が入っている記事だと同意が得られて嬉しい)
結論
- 型っぽい
- Any的なもの
調べる
A Tour of Go曰く
The interface type that specifies zero methods is known as the empty interface:
interface{}
An empty interface may hold values of any type. (Every type implements at least zero methods.)
The interface typeという言葉を見るに型ということみたい
全ての型は少なくとも0個のメソッドを実装しているから
empty interface (→interface{}
) は任意の型の値を保持できる。ということらしい
実際にGoのreflect.TypeOf()メソッドの引数にこのinterface{}は使われている
// TypeOf returns the reflection Type that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. func TypeOf(i interface{}) Type { eface := *(*emptyInterface)(unsafe.Pointer(&i)) return toType(eface.typ) }
俺たちのオブジェクト指向言語CSharp
つまりこれはC#でいうところのObject型みたいなものなのではないか
と考えると分かりやすい (分かりやすいけど「違う!」と怒られそうなのでここで予防線をきちんと張る)
Supports all classes in the .NET class hierarchy and provides low-level services to derived classes. This is the ultimate base class of all .NET classes; it is the root of the type hierarchy.
Object Class (System) | Microsoft Docs
任意の型の値を保持できるという点ではdynamic型っぽくもあるけど、今回はObject型の方がずれがなさそう
ついでにRubyでも丁度Object型が似たようなもの
詳しくないけどJavaもそんな感じみたい
※Goのinterface{}はC#でいうところのObject型みたいなもの。という雑な理解で逃がすのが楽そうだけど
厳密にC#でinterface{}的なことをやろうとしたらこうなる
interface IHoge {} public class Test: IHoge {} // IHogeが空だから何も実装しなくていい
まとめ
全ての型における基底となる型がよくあるオブジェクト指向言語ではObject型として用意されている
Goにおいてはinteface{}がそんな感じの役割を果たしている
(役割であってそのものではない!!)
一般的なinterface、つまり「クラスや構造体に決まった振る舞い(メソッド)を定義するもの」はC#でもGoでも似たような理解で概ね良さそうだけど、
Goのinterface{}だけは用途的に切り離して考えたほうがやさしいと思う
interface{}じゃなくてAnyとかだったら嬉しかったなぁ
(それこそtype Any interface{}
って感じにエイリアスをつくるような感じで)
おまけ
あまりにinterface{}が理解できず、型なのかどうなのかすら怪しかった時にロシアの詩人フョードル・チュッチェフの詩を思い出したのでここに引用しておく
Умом Россию не понять,
Аршином общим не измерить:
У ней особенная стать —
В Россию можно только верить.ロシアは頭ではわからぬ
並みの尺度では測れぬ
ロシアならではの特質がある
ロシアは信じることができるのみ。
ロシアは頭ではわからぬ 並みの尺度では測れぬ ロシアならではの特質がある... - The Embassy of the Russian Federation to Japan | Facebook
interface{}は信じることができるのみ。
インドカレーレシピレビュー 01
レシピについて
自分が作るにはタイトルがやや恥ずかしい(執筆時、僕は26歳であり男子という年齢でもない)が、写真が美味しそうだったので作った
二人前というのがちょっと苦しいところですな
鶏もも肉をマリネしないのが他の一般的なレシピに比べてちょっと楽
油の量が書いてなかったため途中で注ぎ足したりした
工程3でスパイスを用意とあるがその時点では材料のブラックペッパーとクミンは使わない
大変紛らわしいので注意!
所感(個人差あり)
玉ねぎは執拗に焼いたが全体的に味のコク、喉への引っ掛かりが足りなすぎる
→ バターかヨーグルトが必要か?あるいは油を増やす
トマトの酸味をもう少し落としたい
お湯500mlで大味になりすぎているかも
ジャワカレースパイシーブレンドには敵わず
新大久保 THE JANNAT HALAL FOOD 徹底攻略Wiki
新大久保でいい感じにスパイスが安く売っているお店の攻略メモ
公式で通販をやっているらしいがなかなか難易度が高いように思える。それに店頭の方が安いみたい
弱い日本人はいきあたりばったりで買えばいいだろうと思っていても外国人に対して萎縮してしまいがちなのでこの手の予習は必須であるといえる
リスト
もっとたくさんあるけど、買ったものを記載
これらのスパイスは店内入って右手、レジカウンターの隣のあたりにある
ビビって出ないでちゃんと確認する胆力が試される
スパイス名 | 量(g) | 金額 | 販売 | 原産国 | 備考 |
---|---|---|---|---|---|
コリアンダー(パウダー) | 1000g | 850円 | サルタージ株式会社 | インド | |
チリ(ホール) | 100g | 150円 | ザ・ジャンナット株式会社 | インド | |
チリ(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
アフリカンホットぺぺ(パウダー) | 100g | 350円 | ザ・ジャンナット株式会社 | アフリカ | ペペってなんだよって思ったらペッパー(ガラムマサラの別名とかかと思って適当に買ってしまった) |
クミン(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
クミン(ホール) | 100g | 150円 | ザ・ジャンナット株式会社 | インド | |
パプリカ(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
ターメリック(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
ブラックペッパー(パウダー) | 100g | 350円 | ザ・ジャンナット株式会社 | インド | |
ブラックマスタードシード(ホール) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
グリーンカルダモン(ホール) | 25g | 200円 | ザ・ジャンナット株式会社 | インド | パッケージにはカードダムンと書いてあるが... |
クローブ(ホール) | 50g | 200円 | ザ・ジャンナット株式会社 | インド | |
フェンネル(ホール) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
フェンネル(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
フェネグリーク(ホール) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
フェネグリーク(パウダー) | 100g | 200円 | ザ・ジャンナット株式会社 | インド | |
シナモン(ホール) | 50g | 200円 | ザ・ジャンナット株式会社 | インド | |
シナモン(パウダー) | 50g | 200円 | ザ・ジャンナット株式会社 | インド |
最終確認日:2020/07/18
メモ
店員さんは日本語で会話してくれるので助かる
店内雰囲気の参考になるブログ
【GO】【WSL】WSL1 + VSCode + Remote-WSLで環境構築する
WSL内にGoをインストールして、WSL内にmain.goファイルを作ったりして、
ホストのVSCodeからRemote-WSLでそれを開いたり実行するための構築手順
WSL1としているのにはそれに起因するバグがあるから
WSL内にGoをインストール
コレを参考にインストールする
環境変数についてひとつだけ
WSL1では起動時に~/.bash_profile
を実行しないみたいなので、
~/.bashrc
に書いてよいのではと思うところです
参考
WSL2では状況が変わってるかもわからん
VSCode側の設定
ここらへんを拡張機能でいれる
- Remote WSL
- Remote Development
- Go
※Remoteなんとか系は必要に応じて適当に入れて
Failed to run "go env" to findなんとかかんとか
ここまできて、適当に拡張子が.goなファイルを開くとこんな感じのことを言われた
Failed to run "go env" to find GOPATH as the "go" binary cannot be found in either GOROOT(undefined) or PATH(......
go envを実行してもgoのバイナリがGOROOTにもPATHにもないよという話で、
いやいやそんなことはないだろうと思ったらホストのWin10の環境変数を見に行っているみたい
エラーメッセージが違うせいで解決に時間がかかったけどこのやり方でOK
もしかしたらついでにgo.gopathも設定しておくといいかも
【Go】【WSL】WSL1 + Go + VSCode + Remote-WSLでデバッグ実行ができない
WSL2が出たばっかり(執筆時2020/06/02)なのに、なんで今頃WSL2じゃなくて1なのかというと、
WSL2に色々不具合があって、面倒くさそうだからWSL1を使っていたところ踏んでしまった問題だから...
ちなみに僕が恐れた不具合
概要
「デバッグの開始」が一向に進まない
厳密に言うと、API server listening at: 127.0.0.1:6594
という表示を出してから全く進みなし
でも「デバッグなし」で実行ならできる
こっちに気づかない人は多いかも?
どういうこと
色々端折って引用すると
Go dlv debugger uses some system calls that are not supported in WSL1.
...
WSL2 contains a fully fledged Linux kernel with full system call compatibility.
...
In WSL2 go debugging works without issues. Also you can run any Linux program natively (Docker containers, kubernetes, etc.)
総括
WSL2つかわないとだめそう
(VisualStudioでC#を開発していた僕の目にこの環境問題は大変恐ろしく映った)