言語・フレームワーク | Rails(Progate)、Rails(それ以降)、Rails(ルーティング)、JavaScript、Laravel |
外部サービス | S3、heroku |
基礎 | コマンドライン、Git、Docker |
俺 | Github、Qiita質問履歴、はてなのプロフィール、記事一覧 |
その他 | tagfoto(制作したWebサービス)、色々実験ページ |
Oracle Linux Server 逆引きコマンド
なんだこれ
マジで罠が多すぎるって。
VPSでDocker入れてるんですよ、そこでcomposeでrailsとmysqlのコンテナ動かしてるんですよ、mysqlがなんか調子悪いんですよ、そしたらmysqlのコンテナにexecで入るじゃないですか、そんでmysqlのログ見ようとするじゃないですか、でもなんでかログが無いんですよ、んでChatGPTとかググったりしたらmy.cnfを修正するとログが出せるようになる(mysqlにログインしてコマンド打ってもいいけど)とのことでvimインストールしようとすると詰んだ。aptコマンドが無いってさ。
俺が間違ってたのは、ここでずっとChatGPTに聞きまくったこと。マジでミスった。というか、聞き方が悪かったのかな。まずはそのコンテナ(に使われてるDockerイメージ)のOSを特定する必要があるのでは?とふと思い、その方法をGPTに聞くと教えてくれた(/etc/os-releaseをcatで見ると書いてる)、それが件名のOracle Linux Serverである。でもGPTに対して、vimをどうインストールするかを聞いたがどれも違う(yum使えない)のでググったら一発。それ、および今後も色々使いそうなコマンドをメモするためにこの記事を書いた。
MySQL逆引き
とにかく安価かつ手軽に自分のWebサービスを公開するならVPSが最適なのかな
結論から書くと
調べたり試したりしてみた範囲内では、Kagoya cloud VPSにDockerを導入するのが最も手軽かつ安価だった。ただ、herokuやAWSなど色々試してきたり、ターミナル等のコマンドラインで少しばかりいごいごする知識があるのが前提ではあるので、これを「手軽」と呼んでいいのかは、自分でも少し疑問に思う。
VPSとは
あえて調べずに書くが、「CPUやメモリやOSを指定して、手軽にサーバーが使える」サービス。厳密には色々あったと思うけど。これを契約して、そこに前述のCPU等を指定したら、すぐにサーバーが使える。サーバー上で何かをインストールしたり、Dockerを起動させたりする際は、コマンドラインを使う。ブラウザ上のVPSの管理画面で使うこともできるが、基本はMacならターミナル、Winならコマンドプロンプト(PowerShellとかGitBashかも)、あるいはWin/Mac共通だとVSCodeでコマンドを使うことになると思う。これらの、「VPS管理画面」以外のコマンドラインツールは、以下「ターミナル等」と記載する。
ターミナル等でどうやってVPSにアクセスするのか
俺のようなIT素人だと、そもそも「え、管理画面以外からアクセスできるんや!」ってなるんですわ。なんでできるか。SSLを使うから。SSLとは何か。すまん、概念はなんとなく分かってるつもり(公開鍵と秘密鍵でうまいこと通信)だが、説明は省く。とにかく、SSLで接続する。やり方については、どのVPSサービスも分かりやすいマニュアルを用意してくれているのでそれに従えばOK。
例えば俺の使ってるkagoyaだと、ターミナル等で所定の文字列「ssh -i 秘密鍵までのパス root@VPSのIPアドレス」を入力するとターミナル等がVPSに繋がり、以後、ターミナル等で入力するコマンドは、自分の普段使っているコンピュータに対してではなく、契約したVPSに対して命令するものになる。
VSCodeだと、普段はアプリのフォルダを開いていごいごするが、リモートエクスプローラーという拡張機能を使ってSSHに接続し、VPS上のフォルダを開くことができる。基本はこちらでコードをいごいごして、コンテナを起動したりログを見たりはターミナル等でSSH接続して見るのがいいと思う。
ここに至るまで
その1 heroku
これは、自分のGithubの任意のリポジトリと連携させて、それをすぐ動かせるサービス。昔は無料だったらしいが、今は有料。執筆時点での最安の使い方は(以下月額)、基本料金5ドル、JawsDBという拡張機能でデータベース容量5MBまで、これが無料、計5ドル。執筆時点でざっくり750円。なお、よく紹介されてるheroku拡張機能のHeroku Postgresは1アプリごとに5ドルかかる。俺はそのことを忘れて練習用アプリ4つに適用していたことがある。請求を見てビビった。というか、JawsDBが無料なの、かなり後半に知ったぞ。
その2 AWS
なんか主流っぽいので頑張って覚えた。構成はECS、RDS。前者がコンテナをそのまま動かせるやつ、後者がデータベース。平均して13ドル(1900円)掛かっていた。ほとんど(11ドルくらい)がECSの料金。これを安くできんかなと思い、色々調べていた
その3 Kamal
Railsの作者が作ったサービス。ただ、動かし方が理解できず、その中で「自宅サーバーとかVPSがあれば動くっぽい」ということは理解できた感じ。今だと少しは理解できたので、そのうちやるかも。
その4 VPS+Dokku
前項でVPSの存在をうっすら知り、色々調べていた際に、Dokkuというものを知る。VPS上にインストールすることで、自分のVPSで「herokuみたいなやつ」使い放題!という夢のようなものである。VPSを契約し、初期設定としてOSのインストールと併せてDokkuのインストールまでやってくれるVPSサービスがあったので、これ幸いとばかりにインストール、Dokku起動、起動、起動・・・。あれ?マニュアル通りなのになぜか動かない、等いろいろあった。
結局、何とか動かせた、かと思いきやherokuと微妙に違う点が多々あり、デプロイはできるがherokuビルドパック(herokuのサーバー上にインストールしないといけないものが、ビルドパックとして用意されている。画像処理とか。)がそのまま使えない。それ故、herokuでは動いていたのにVPS上では一部の機能が動かない、等の不満があり、「これだったらコンテナをそのまま動かした方がシンプルでよくないか?」と思ってしまった。
その5 VPS+Docker
現状がこれ。VPS上に、git cloneで自分のアプリを持ってきて、次にDockerをインストールし、あとは自分のアプリのcomposeを起動するだけ。これだとURLがIPアドレスのままなのでカッコ悪いよね。なので、公開するとしたらドメインを取ってDNSを設定したり、SSL化(親切な人がcomposeの書き方をネットに挙げてくれてる)などやる必要はあるが、割とすんなりできるはず。少なくともDokkuよりは遥かに手軽だった。
なおVPSは、さくら、conoha、indigo、XServer、kagoyaと使い、kagoyaに決めた。500円。さくらはお試し期間があるのだが、何かを適用するために(DNSだったかな?)は本契約する必要があり、その最低利用期間が3ヶ月。前のめり過ぎて、それに気づかず契約しちゃったよ。よく読んでない俺が悪いんだが、なんか悪質だなあと思った。あと、XServerはお試し期間がない。なので、「とにかくVPSというものを体験してみたい」という俺のような人は、さくらとXServerは避けるのが無難と思います。この辺りは別記事を書きたい。
課題
バックアップ。俺はほぼ知識ゼロなので、これから勉強です。
Laravel俺用逆引きリファレンス
前提
コマンドライン
アプリ作る
curl -s "https://laravel.build/アプリ名" | bash
sail立ち上げ
./vendor/bin/sail up
sail 〇〇 が使えるようにする
alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'
breez(全部のっけ的なスターターキット)
sail composer require laravel/breeze --dev sail artisan breeze:install sail artisan migrate sail npm install sail npm run dev
日本語化
sail composer require askdkc/breezejp --dev sail artisan breezejp
モデル作成(マイグレーション付き)
sail artisan make:model Post -m
マイグレートする
sail artisan migrate
マイグレートしたやつを戻す
sail artisan migrate:rollback
マイグレーションファイル追加(カラム追加)
sail artisan make:migration add_column_user_id_to_posts_table --table=posts
コントローラー作成(resource付き)
sail artisan make:controller PostController --resource --model=Post
コンポーネント作成
sail artisan make:component Message
tinker
モデル全件取得
$posts = \App\Models\Post::all();
モデル1件取得
$post = \App\Models\Post::find(1);
モデルに何のカラムが入ってるか見る
\Illuminate\Support\Facades\Schema::getColumnListing('posts');
モデル
belongsTo
<?php public function user() { return $this->belongsTo(User::class); }
hasMany
<?php public function posts() { return $this->hasMany(Post::class); }
submitで受け付けるパラメーターを設定
railsのpermit的なやつか。モデルに書くんだねえ
<?php protected $fillable = [ 'title', 'body', 'user_id', 'image', ];
コントローラー
インスタンスを作る
<?php $post=new Post();
インスタンスに代入(自動で、認証ユーザーのIDを取得)
この辺勉強中だが、Laravelってこのあたりのユーザー認証系が、標準で組み込まれてるみたい。この辺はRailsよりもかなりとっつきやすいのでは。
<?php $post->user_id=auth()->user()->id;
インスタンスをデータベースに保存
<?php $post->save();
リダイレクト
<?php return redirect()->route('post.create');
メッセージ表示
<?php return redirect()->route('post.create')->with('message', '投稿を作成しました');
バリデーション
<?php $inputs=$request->validate([ 'title'=>'required|max:255', 'body'=>'required|max:1000', 'image'=>'image|max:1024' ]); $post=new Post(); $post->title=$inputs['title']; $post->body=$inputs['body']; //以下略。ちなみに、インスタンス作成時にわざわざinputsに置き換える必要もない
ビュー
中身にするには
上記の続き。各ビューは、下記タグで囲む。
<?php <x-app-layout> </x-app-layout>
フォーム
- このケースは、postコントローラーのstoreアクションを使う
- @csrfを入れることで、クロスサイトリクエストフォージェリ(Webアプリケーションのユーザーが意図しないリクエストを偽造し、ユーザーが意図しない処理を実行させる攻撃)を防ぐ
<?php <form method="post" action="{{route('post.store')}}" enctype="multipart/form-data"> @csrf
コンポーネントを使う(breez標準付属のprimary-button)
<?php <x-primary-button class="mt-4"> 送信する </x-primary-button>
コンポーネントのコンストラクター設定
Messageというコンポーネントの場合。下記はMessage.phpに書く。オブジェクト指向のコンストラクターですな。あ、「コンポーネントのコンストラクター」って「長久命の長助さん」っぽいな
<?php public $message; public function __construct($message) { $this->message = $message; }
コンポーネント本体
上記の続き(上記とセットでコンポーネントを作るのが基本のやり方)。下記はmessage.blade.phpに書く。issetは、変数が存在するかの真偽値を返すphpの組み込み関数。Railsだとこんなの付けなくても変数だけ書いたんでよかったような・・。exist?か。いかん、この辺の理解が浅いな。戻り値をどうするかで使い分けるんだっけ。trueではなかったときにnilかfalseかというところで。
<?php @if(isset($message)) <div> {{$message}} </div> @endif
コンポーネントを使用する
- タグで囲んだ場合は、コンポーネント本体のslot部分が、「コンポーネントを指定したビュー内のタグで囲われてる部分」に置き換わるという理解。
- タグで囲わなかったら、まるっとコンポーネントに置き換わるという理解。
<?php // <x-ファイル名> </ファイル名> // <x-ファイル名 :データ名=データの定義> </ファイル名> // <x-ファイル名 :データ名=データの定義 /> <x-message :message="session('message')" />
匿名コンポーネント
上記の例でいくと、コンストラクター用のMessage.phpを作らず、message.blade.phpだけを作ること。使用の仕方は上記と同じ。
<?php @props(['message']) @if(isset($message)) <div> {{$message}} </div> @endif
標準コンポーネント(バリデーションエラー)
<?php <x-input-error class="mb-4" :messages="$errors->all()"/>
バリデーションエラー後、入力したものを自動入力してくれる
これもRailsのform_withだと標準ではあるけど、こっちの方が明示的で好感が持てるなあ。ほんまform_with嫌い。書き方が柔軟すぎて。
<?php value="{{old('title')}}"
コンポーネント(カスタマイズしたバリデーションエラー)
Laravel教科書では、画像を再添付させるためにカスタムコンポーネントを使用している。注意書きレベルのものをエラーと同じ文字装飾で表示するのってどうなんだろう。なんか引っかかるなあ。
<?php @props(['errors']) @if ($errors->any()) <div {{ $attributes }}> <div class="font-medium text-red-600"> エラーの内容を確認してください。 </div> <ul class="mt-3 list-disc list-inside text-sm text-red-600"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach @if(empty($errors->first('image'))) <li>画像ファイルがあれば、再度、選択してください。</li> @endif </ul> </div> @endif
ルーティング
resource
<?php Route::resource('post', PostController::class);
上記を分解
<?php Route::get('post', [PostController::class, 'index'])->name('post.index'); Route::get('post/create', [PostController::class, 'create'])->name('post.create'); Route::post('post', [PostController::class, 'store'])->name('post.store'); Route::get('post/{post}', [PostController::class, 'show'])->name('post.show'); Route::get('post/{post}/edit', [PostController::class, 'edit'])->name('post.edit'); Route::patch('post/{post}', [PostController::class, 'update'])->name('post.update'); Route::delete('post/{post}', [PostController::class, 'destroy'])->name('post.destroy');
マイグレーションファイル
モデル新規作成時にカラムを設定
nullableとすると、必須ではなくなる。これ、もしかしてバリデーション的なものなのか?この辺は勉強。
<?php $table->string('title'); $table->text('image')->nullable();
foreignId
ここもよく分からん。integerではないのは、他のモデルのidを使うからか?それともbelongsしてるからか?
<?php $table->foreignId('user_id');
特定のカラムの後に追加
一発目のマイグレート以降のカラム追加時に使う。
<?php $table->foreignId('user_id')->after('image');
Laravelを最新版公式に沿ってシンプルに導入。あと感想。
なぜ使おうと思った?
地理的な問題で、Rails書ける仕事ってなかなか募集していないので、ならば次にやるべきフレームワークは?という観点でLaravelを選んだ。WordPressも同時進行で触ってみる予定。
どのような動きをしたか
色んなワードでググったが、そこには、まごうことなき地獄が広がっていた。QiitaやZennの初心者が導入しました記事、ベテランによるあれやこれやカスタマイズしまくってる(あんま参考にならない)導入事例、Windows向けの丁寧なチュートリアル(一番参考になりそうだったけど、Macと結構違うんですよね・・。導入後は参考にできそうだけど)、はしょりの多い分かりにくい公式、などなど。
とりあえず、phpの環境構築自体が鬱陶しい感じだったので、ならば学んだDockerを使おうかと思いそれで色々見てると、金言発見。
根本的な間違いは「初心者が書いた変なブログを参考にしてること」
Laravelで絶対にやってはいけないことの筆頭。
初心者から見ると「ブログを書いてる人はきっとLaravelに詳しいんだろう」と勘違いするけどそんなことは全くなく「ブログを書いてるのも99%は初心者」
ベテランから見ると間違ったことばかり書いてる初心者で迷惑すぎる存在。開発環境にDockerを使いたいなら公式のLaravel Sailを使う。これ以外は全部無視していい。
公式ドキュメト通りにlaravel.buildで新規プロジェクトを作ればそのまますぐsailが使えるように全部準備される。
DBが使えるように.envも自動で変更されるので自分で変更するような余計なことはしなくていい。
初心者が間違えるのは変なブログを見てしなくていい余計なことをするから。
引用元: https://teratail.com/questions/r1tal080g333xx
あまりに耳が痛いが、早めにこの回答に出会えて良かったと思う。という訳で公式見ながらLaravel Sailを使ったら、あっさり導入完了。Docker最高。そりゃあさあ、Dockerなしで導入する知識もあった方がいいと思いますよ。でも、とりあえず、LaravelやPHPの概念に触れたいんですよ。衝動なんですよ、これは。
Laravel Sailとは
非常に説明しにくいが、Laravel公式が(Railsと違って)親切にも用意してくれている、「LaravelをDockerで簡単に導入できるようにしてくれる」一連のコマンドのようなものです。フレームワークやライブラリではない。
やった手順
以下、MacでDockerをインストールしている前提で、導入〜ビュー表示までです。Qiitaの素人記事とか玄人記事と違って、「2023/09/06時点の最新版のLaravelの公式ドキュメントにのっとって最低限のことだけやってる」と思います。思い・・ます。
- ターミナル開く
- cdにて、アプリのフォルダがいっぱい入ってるフォルダに行く(俺の場合はprojects)
- curl -s "https://laravel.build/任意のアプリ名" | bash を実行(なんか不安になるよな、このコマンド。引数渡せるのか?って思うし)
- 5分くらいかかる
- cdで任意のアプリ名に移動
- ./vendor/bin/sail up を実行すると、docker compose upとかrails sみたく、以後ログが出るようになるので、それ以降にLaravel関連のコマンドを使う場合はターミナルで別窓を作ったりVSCode上のターミナルを使う
- alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail' を実行すると、以後sail 〇〇でphp 〇〇の代わりのコマンドを使えるようになる。すごいね、Docker。すごいね、Sail。ちなみにここまでは全て公式ドキュメントどおり。以下は、公式ドキュメントのMVCのそれぞれの箇所を見てもあまりシンプルな事例を書いてないせいで、他のチュートリアルとかChatGPTとかで調べた。いや、ほんまRailsチュートリアルとかドキュメントと違って、公式ドキュメントって、各項目、のっけから応用しまくりなコードがバンバン出てくるのよ。どうなってんの?Railsが優しすぎるのか?やさしさに包まれすぎてるのか?
- sail artisan make:controller PostController でコントローラーを作る。今回はpostという名前にします
- sail artisan make:model Post でモデルを作る。今回はデータベースいろわんのであまり意味ないですが。
- mkdir resources/views/post と touch resources/views/post/index.blade.php でビューファイルを作ります。ここにビューファイルを置きます。
- web.phpに下記コード1を追加(ルーティングの設定です)
- PostController.phpのclass PostController extends Controller内にコード2を追加
- index.blade.phpをコード3にまるっと書き換え(サンプルなんでなんでもいいですが)
- この状態でlocalhost/post に行くと、サンプルページが表示されるはず。
コード1
// use〇〇の下に use App\Http\Controllers\PostController; // 最下に Route::get('/post', [PostController::class, 'index']);
コード2
public function index() { return view('post.index'); }
コード3
<!DOCTYPE html> <html> <head> <title>Sample Page</title> </head> <body> <h1>Welcome to the Sample Page</h1> <p>This is the sample view for the index action of SampleController.</p> </body> </html>
これから
モデルをいごいごしまくるど!おー!!
GitHubのこの世で一番シンプルなシェルスクリプト(add,commit,pushするだけ)
なんすかこれ
仕事だともっと複雑なシェルスクリプトが必要なんだろうけど、一人でいごいごやってるだけの俺のような人間からすると、もっとシンプルなやつが欲しい。という訳でほとんど検索にも引っかからないようなサイトながら、俺もそんなサイトに助けられまくってるので書くぜ〜
手順
- アプリのルートフォルダ上にg.shというファイルを作る
- そこに下記のコード1をコピペ
- cdでアプリのルートフォルダに移動しておく
- そこで「./g.sh "コミットメッセージ"」と入力。コミットメッセージは任意のものを入れてください。ちなみに俺は日本語でgと入力すると「./g.sh ""」と変換されるようにしています。
- まとめてadd,commit,pushしてくれる
コード1
#!/bin/bash git add . git commit -m "$1" git push origin main
Dockerコマンド
起動・終了・削除
compose.ymlを起動
新しい書き方だとハイフンいらんらしいがネットに書いてるやつほとんどハイフンついてる
docker compose up
上記をバックグラウンドで起動(ログが出ない)
docker compose up -d
特定のコンテナのみcompose up
docker-compose up -d service1
上記を再ビルド
docker compose up --build
上記を停止
docker compose stop
特定のコンテナのみcompose stop
docker-compose stop service1
上記を停止し削除
docker compose down
特定のコンテナ停止
docker stop NAMESもしくはコンテナIDの一部
(いずれもdocker psしたら分かる)
すべてのコンテナを停止
docker stop $(docker ps -q)
特定のコンテナ削除
docker rm NAMESもしくはコンテナIDの一部
すべてのコンテナを削除
docker rm $(docker ps -q)
特定のイメージを削除
docker image rm <イメージ名またはイメージID>
もしくは
docker rmi <イメージ名またはイメージID>
全てのイメージを削除
docker image prune -a
状態把握
コンテナの状況を見る(起動中のものだけを対象)
docker ps
コンテナの状況を見る(すべて)
docker ps -a
イメージ見る
docker images
ログを見る(直近が出てくる)
docker compose logs
ログを見る(流し続ける)
docker compose logs -f