RUNTEQ記録(9)rails console
*今日やったこと
rails console課題
①作業用のアプリ作成
rails _バージョン_ new アプリ名
②所定のテーブル作成
rails g model モデル カラム1:データ型 カラム2:データ型・・・
❸DB Browser for SQLiteをインストール
データベースの中身を確認できる
課題に入る
ProgateのSQL
課題3までは特に躓く要素がなかったので、サクサクできたのですが、課題4のテーブルの結合の仕方を求めて、何となくSQLのjoinを思い出したので、ProgateのSQL課題を全てやり直して見ましたが特に使う箇所がなかったですね。
せっかくやったのでSQL備忘録(少し)
「データを取得してください」
データベースに送る命令(クエリ)
クエリを書く言語=SQL
whereで条件検索 whereの検索対象は全体
group byでグループ化
sumなどの関数実行
グループ化した後の条件指定はhaving havingの検索対象はグループ化されたデータ
実行順序
fromでテーブル指定
複数テーブルがあればjoin,onで結合
whereで取得条件
グループ化 group by
関数実行 sum, count,avg,max,min
havingでグループ化したデータに対して条件検索
検索 select, distinct
順序 order by
limit指定
課題の解答動画を見る
テーブルの結合をrails consoleだけで完結させることが出来ずに、解答動画を確認。
(rails consoleで完結させることしか頭になく、設定ファイルをいじってはいけない縛りかと思っていました😓)
データを関連付ける必要があるので、idのデータ型はreferences
まず、自分は講師の方が指摘していた良くないやり方でテーブルを作成していました。
良くないやり方「rails g model Task name:string user_id:integer」
自分が入力したコード「rails g model Task name:string user_id: bigint」
確かに事前準備の指示に不穏な箇所、「user_id : bigint(reference)」みたいな書き方がされていたけど、括弧書きだからいいかとスルーしていました。初見殺しだ・・・笑
テーブルの内容を変更しようと試みる
テーブルの内容の変更ってどうやるんだっけ?
どうやるんだっけ?が渋滞している😰
書籍の思い当たるところとWeb検索で一度カラムを削除し、新しく追加するやり方を知る
①削除用のファイルを作成し、中身を書き換える
$rails g migration RemoveUserIdColumnFromTasks
def change
remove_column :tasks, :user_id, :bigint
end
$rails db:migrate
②追加用のファイルを作成、中身変更
$rails g migration AddUserColumnToTasks
def change
add_column :tasks, :user, ;reference
end
$rails db:migrate
なんかエラーが出てきた
-- add_column(:Tasks, :user, :references)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
(エラーが発生したので以降の操作を全てキャンセルしたよ的なエラー)
よく分からないので、今の状況を確認
$rails db:migrate:status
database: /Users/****/workspace/runteq/rails_introduction_2/rails_console_app/db/development.sqlite3
Status Migration ID Migration Name
--------------------------------------------------
up 20211204011718 Create users
up 20211204012806 Create tasks
up 20211204035958 Create categories
up 20211204040115 Create task categories
up 20211204043359 Remove user id column from tasks
down 20211204043754 Add user id column to tasks
追加だけできていないことだけは分かった。
色々調べて見たけど、タイプミスではなさそう?
http:// https://qiita.com/naokishizuka/items/e51b5ea9ec56dd0471f7
↑のサイトを発見
・Rails5では、デフォルトで作成されるidがbigintになっているそう
・参照元テーブルのカラムをintegerで作成すると良くないことが起きるらしい
・foreign keyとやらが作成されないので、テーブルのカラムをbigintで作成しようね
そして、下記のどちらでも変わらなそうなことが書かれていた・・・
def change
add_column :tasks, :user_id, :bigint
end
def change
create_tables :tasks do |t|
t.references :user
end
そもそも、削除したり再度追加したりする必要はない?
とりあえず、先に進めるために前者の方で進めることに・・・
(エラーが出て進めなくなった場合は、テーブルを作り直すつもりでしたが案の定上手く行かなくなりアプリを作り直しました)
user.referencesでテーブルを作っていれば、自動的に入力されているという「belongs_to :user」はapp>models>task.rbの中に記載されていなかった。
このため、手動で入力をする
class Task < ApplicationRecord
belong_to :user
end
そして、なんやかんや進めていき、
TaskCategory.create(task: task1, category: benkyo)
TaskCategory.create(task: task2, category: benkyo)
TaskCategory.create(task: task3, category: zatuji)
TaskCategory.create(task: task4, category: goraku)
中間テーブルを実行しようとすると、エラーが出てきました。
エラー発生
ActiveModel::UnknownAttributeError (unknown attribute 'task' for TaskCategory.)
(TaskCategoryにtask属性がない)
ここら辺から、事前準備の弊害と思しきエラーが見られるように・・・
確かに、テーブル作成時に、「rails g model Task name:string task:references」という作り方をしていないため、taskという属性はないという指摘は分かる気がする。
もう一つのやり方を試すことに、
task_idとcategory_idを使います。
TaskCategory.crate(task_id: 1, category_id: 2)
(0.1ms) begin transaction
TaskCategory Create (5063.7ms) INSERT INTO "task_categories" ("task_id", "category_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["task_id", 1], ["category_id", 2], ["created_at", "2021-12-04 07:21:03.957653"], ["updated_at", "2021-12-04 07:21:03.957653"]]
(0.1ms) rollback transaction
Traceback (most recent call last):
2: from (irb):36
1: from (irb):37:in `rescue in irb_binding'
ActiveRecord::StatementInvalid (SQLite3::BusyException: database is locked: INSERT INTO "task_categories" ("task_id", "category_id", "created_at", "updated_at") VALUES (?, ?, ?, ?))
二つ目のやり方では、ロールバックされてしまいました。
分解してやってみると、saveができていない様です。
振り出しに戻る
動画の指定通りにテーブルを作成しました。
idのデータ型をreferencesにして作成
user=User.new(name: “あや”, age: 🥺)
user.save
↓
自分は上のように2行で書いていたけれど、createで1行でかける
user = User.create(name: “太郎” age: 12)
アソシエーションの設定をいじる
task.rbとuser.rbの中身を変更
前述したuser.referencesでテーブルを作っていれば、自動的に入力されているという「belongs_to :user」は今回はしっかり書いてありました。
【task.rb】
【user.rb】
↑dependent: :destroyは紐づけたテーブルでも削除すると連動してレコードが消えるというやつ
↑課題後に眺めていて気が付いたが、同じやり方でテーブルを作ったものの自分のマイグレーションファイルにはNOT NULL制約がなかった。あとから追加するやり方で追加すれば良いんだろうけど、なぜあらかじめ入っていないのかは分からない。
タスクを作る
user = User.find(1) でユーザーを検索
ArgumentError (The :dependent option must be one of [:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception], but is :destory)
いきなりエラー発生
dependentオプションが下記の内の一つに違いない
class User < ApplicationRecord
has_many :tasks, dependent: :destory
end
スペルミスでした。
分かりやすいエラー親切や・・・
userと関連付けてタスクを作成する
user=User.find(1)
user.tasks.create(name: “Rubyを勉強する”)
ちなみに私は二流(Task.create(name: “勉強” user_id: 1))でした笑
userと関連付けてタスクを作成することでuserに紐づいたタスクが作られる
オブジェクトを指定して作成することもできる
Task.create(name: “本を読む”, user: user)
カテゴリ作成
Category.create(name: “趣味”)
特定のIDを決めて紐付けるやり方だと、多対一の関係で、柔軟性があるとは言えない。
中間テーブルを作って紐づけた方が良い。
①タスクを取ってくる
task1=Task.find(1)
task2=Task.find(2)
task3=Task.find(3)
②Category.allでカテゴリのIdを確認
zatuji=Category.find(1)
benkyo=Category.find(2)
goraku=Category.find(3)
外部キーが二つある場合はいきなりモデル.createでもいい
TaskCategory.create(task: task1, category: benkyo)
TaskCategory.create(task: task2, category: benkyo)
TaskCategory.create(task: task3, category: zatuji)
DB Browser for SQLiteでちゃんと関連付けたテーブルができたか確認
大丈夫でした!!
感想
最初から、解答を見るのは駄目だと思って、分からない箇所は調べて進めているものの、自分が検討違いなことを調べてどんどん斜め後ろに後退していることに、解答を見て初めて気が付きます。
これも勉強というか経験だなと思いつつ、カリキュラムの進度がどんどん悪化しているので、ある程度で見切りをつけるべきなんだろうとも思います。
プログラミングを勉強したい自分と、受講期間に追われている感覚で焦燥感ばかりになっている自分がいる感じ😔踏ん張る