【備忘録】docker images noneなイメージを全て削除したい
TL;DR
% docker images | grep none | xargs docker rmi `awk '{ print $3 }'`
conflictが起きて削除できないとき
Error response from daemon: conflict: unable to delete 78ef4af0ce83 (must be forced) - image is referenced in multiple repositories
上みたいなエラーが出たときは、-f
で強制的に削除してやりましょう
% docker images | grep none | xargs docker rmi -f `awk '{ print $3 }'`
【Vim】rails(ruby)でvim-lspを導入するとnokogiriで怒られる
どうもてぃ。
最近vimのneocomplete
とneocomplcache
のサポートが終わってることを知り、ちょうどいい機会だったのでlspに移行しようとした際にハマったので備忘録として。
lspの導入
lspとは…という説明はいろんなところでなされてるためここでは割愛します。
極ありふれた表現で簡単に表現すれば補完できるすごいやつです。凄いやつは使いたくなりますよね、vimmerならば。
vimrc
ずっと整理したいtomlにできないまま、また一年が経過しそうになってますが、こんな感じです。
" vim lsp call dein#add('prabirshrestha/async.vim') call dein#add('prabirshrestha/asyncomplete.vim') call dein#add('prabirshrestha/vim-lsp') call dein#add('mattn/vim-lsp-settings') call dein#add('prabirshrestha/asyncomplete-lsp.vim') if executable('solargraph') " gem install solargraph au User lsp_setup call lsp#register_server({ \ 'name': 'solargraph', \ 'cmd': {server_info->[&shell, &shellcmdflag, 'solargraph stdio']}, \ 'initialization_options': {"diagnostics": "true"}, \ 'whitelist': ['ruby'], \ }) endif
公式通りに必要なものをセットで入れてます。
まだ導入段階で解決できてないところ多いんですが、asyncomplete
入れてるのに自動補完されないんですよね…それはまた今度調査します。
Rubyではlsp用のgem solargraph
を使用するのでとりあえずローカルにぶち込みます。
$ gem install solargraph
とりあえず準備OK。
適当にRailsプロジェクトのファイルを開く
app/controllers/users_controller.rb
を開いたとしましょう。
Please do :LspInstallServer to enable Language Server ~~~
と出てくるので:LspInstallServer
でlspの設定。対象のgem等がインストールされていくはずです。
が、安定のnokogiriさんに阻まれました。
/home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.10/ext/nokogiri/tmp/x86_64-pc-linux-gnu/ports/libxml2/2.9.10/libxml2-2.9.10/libtool: File name too long Makefile:1015: recipe for target 'install-libLTLIBRARIES' failed make[3]: *** [install-libLTLIBRARIES] Error 126 make[3]: ディレクトリ '/home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.10/ext/nokogiri/tmp/x86_64-pc-linux-gnu/ports/libxml2/2.9.10/libxml2-2.9.10' から出ます Makefile:1792: recipe for target 'install-am' failed make[2]: *** [install-am] Error 2 make[2]: ディレクトリ '/home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.10/ext/nokogiri/tmp/x86_64-pc-linux-gnu/ports/libxml2/2.9.10/libxml2-2.9.10' から出ます Makefile:1479: recipe for target 'install-recursive' failed make[1]: *** [install-recursive] Error 1 make[1]: ディレクトリ '/home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.10/ext/nokogiri/tmp/x86_64-pc-linux-gnu/ports/libxml2/2.9.10/libxml2-2.9.10' から出ます Makefile:1786: recipe for target 'install' failed make: *** [install] Error 2 ======================================================================== *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/home/motty/.asdf/installs/ruby/2.6.3/bin/$(RUBY_BASE_NAME) --help --clean --use-system-libraries --enable-static --disable-static --with-zlib-dir --without-zlib-dir --with-zlib-include --without-zlib-include=${zlib-dir}/include --with-zlib-lib --without-zlib-lib=${zlib-dir}/lib --enable-cross-build --disable-cross-build /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/mini_portile2-2.4.0/lib/mini_portile2/mini_portile.rb:402:in `block in execute': Failed to complete install task (RuntimeError) from /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/mini_portile2-2.4.0/lib/mini_portile2/mini_portile.rb:373:in `chdir' from /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/mini_portile2-2.4.0/lib/mini_portile2/mini_portile.rb:373:in `execute' from /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/mini_portile2-2.4.0/lib/mini_portile2/mini_portile.rb:120:in `install' from /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/mini_portile2-2.4.0/lib/mini_portile2/mini_portile.rb:155:in `cook' from extconf.rb:365:in `block (2 levels) in process_recipe' from extconf.rb:257:in `block in chdir_for_build' from extconf.rb:256:in `chdir' from extconf.rb:256:in `chdir_for_build' from extconf.rb:364:in `block in process_recipe' from extconf.rb:262:in `tap' from extconf.rb:262:in `process_recipe' from extconf.rb:557:in `<main>' To see why this extension failed to compile, please check the mkmf.log which can be found here: /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.10/mkmf.log extconf failed, exit code 1 Gem files will remain installed in /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.10 for inspection. Results logged to /home/motty/.local/share/vim-lsp-settings/servers/solargraph/vendor/bundle/ruby/2.6.0/extensions/x86_64-linux/2.6.0/nokogiri-1.10.10/gem_make.out An error occurred while installing nokogiri (1.10.10), and Bundler cannot continue. Make sure that `gem install nokogiri -v '1.10.10' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: solargraph was resolved to 0.40.0, which depends on reverse_markdown was resolved to 2.0.0, which depends on nokogiri
親の顔ほどみたエラー。つらい。
動いてるスクリプトに設定を追加
自分が使っているパッケージマネージャーはdein.vim
です。
dein配下にあるsolargraphのスクリプトを確認してみます。パスは$HOME/.cache/dein/.cache/.vimrc/.dein/installer/install-solargraph.sh
でした(人によって違うと思うのでファイル名で検索するのもありかも)
#!/usr/bin/env bash set -e git clone --depth=1 https://github.com/castwide/solargraph . bundle install --without development --path vendor/bundle cat <<EOF >solargraph #!/usr/bin/env bash DIR=\$(cd \$(dirname \$0); pwd) BUNDLE_GEMFILE=\$DIR/Gemfile bundle exec ruby \$DIR/bin/solargraph \$* EOF chmod +x solargraph
とりあえず、よく解決する設定をこのファイルにぶち込みます。
#!/usr/bin/env bash set -e git clone --depth=1 https://github.com/castwide/solargraph . bundle config build.nokogiri --use-system-libraries # これ bundle install --without development --path vendor/bundle cat <<EOF >solargraph #!/usr/bin/env bash DIR=\$(cd \$(dirname \$0); pwd) BUNDLE_GEMFILE=\$DIR/Gemfile bundle exec ruby \$DIR/bin/solargraph \$* EOF chmod +x solargraph
gem追加
もう一点。エラーメッセージにあった、mini_portile関連でエラーになってるっぽかったのでローカルに追加します。
$ gem install mini_portile
とりあえずこれで設定はおk。
LspInstallServer再実行
はい、うまくいったー。
調べても全く出てこなかったので、自力で頑張ってみました。
vim-lspでgem関連エラーが出る場合は実行スクリプト内でgemの操作をやってみるといいかもしれませんね。
それでは、おつでした。
【Ruby on Rails】rails consoleでActionDispatch::Http::Uploadedfileを作成・保存する
どうもてぃ。
久しぶりのRailsで少々ハマったのでメモをば。
やりたいこと
ローカルのファイルを読み込んで、carrierwaveに割り当てているカラムに保存したい。
ただそれだけ。
Let's go
まずはファイルの読み込み。
今回はtmp/uploads/
配下にファイルを作っているものとします。
path = Dir.glob(Rails.root.join('tmp', 'uploads', 'test.pdf')) filename = File.basename(path) tempfile = File.open(path)
とりあえずこれで準備はおk
ActionDispatch::Http::Uploadedfileで読み込む
上記を使って読み込みます。
uploaded_file = ActionDispatch::Http::Uploadedfile.new( filename: filename, type: 'application/pdf', tempfile: tempfile ) User.first.update(file: uploaded_file)
User
モデルにUserFileUploader
をマウントしたfile
カラムがあるものとして保存してます。
class User < ApplicationRecord ・ ・ ・ # ↓こういうやつ mount_uploaders :file, UserFileUploader ・ ・ ・ end
終わり
ファイルタイプによってtypeをimage/jpeg
とかに変えれば画像もちゃんと保存できます。
定期的にRailsに触っておかないと忘れちゃいますね。
【Golang】sql-migrate upがCannot parse dateと出てうまくいかないとき
どうもてぃ。
今日もGolangやっていきます。
マイグレーションを実行してみた
% docker-compose exec golang sql-migrate up -config=config/dbconfig.yml Migration failed: Cannot parse dates. Make sure that the parseTime option is supplied to your database connection. Check https://github.com/go-sql-driver/mysql#parsetime for more info.
上記のようにエラーになってしまいます。
sql-migrate new
はうまくいってますが、up
がうまくいかない。コード上でparseTimeとかつかっているところなんてない。
ただ、エラーメッセージを見てみると、
Make sure that the parseTime option is supplied to your database connection.
これですよ。
parseTimeオプションを追加しろと。
↑
parseTimeはbool型のようなので、dbconfig.ymlの接続設定にparseTime=true
を追加しました。
development: dialect: mysql dir: pkg/db/migrations datasource: root:password@tcp(db:3306)/database_name?parseTime=true
これでマイグレーションが通るようになりましたとさ。
【Rails】enumからi18nを適応したhashを取得したいとき
どうもてぃです。
enumについてあんまり理解してなかったのでメモとして残します。
gemのenum_help
を入れている状態です。
環境
% lsb_release -a No LSB modules are available. Distributor ID: LinuxMint Description: Linux Mint 19.3 Tricia Release: 19.3 Codename: tricia
TL; DR
User model
class User < ApplicationRecord enum role: { admin: 0, manage: 1, guest: 2 } ・ ・ ・ end
locales/js.yml
ja: enums: user: role: admin: 管理者 manage: マネージャー guest: 一般 ・ ・ ・
コンソール
pry(main)> User.roles => {"admin" => 0, "manage" => 1, "guest" => 2} pry(main)> User.roles_i18n => {"admin" => "管理者", "manage" => "マネージャー", "guest" => "一般"}
終わり
Userのインスタンスから取得することもできますが、今回はインスタンスを生成せずにenumを使いたかったので、i18nを試してみたらいけました。
User.roles_i18n.invert
とすればselect_boxとかに使えそうですね。
【Golang】超絶簡素なwebサーバーを作る その3
どうもてぃ。
前回の記事がこちら。
template.html
を読み込んでstructを渡す形のコードを前回作成しました。
まずはそのコードから見ていきます。
tempalteにstructを渡す
type Article struct { Title string Body template.HTML } var tpl *template.Template func init() { tpl = template.Must(template.ParseFiles("template.html")) } func escapeHTML(html string) (tpl template.HTML) { tpl = template.HTML(html) return } func helloHandler(rw http.ResponseWriter, req *http.Request) { article := Article{ Title: "golang practice", Body: escapeHTML("<h1>hello golang</h1>"), } if err := tpl.ExecuteTemplate(rw, "template.html", article); err != nil { log.Fatalln(err.Error()) } }
該当箇所だけ取り上げました。
Article
のstructを定義し、helloHandler
で初期化してます。
func helloHandler(rw http.ResponseWriter, req *http.Request) { // ここね article := Article{ Title: "golang practice", Body: escapeHTML("<h1>hello golang</h1>"), }、 if err := tpl.ExecuteTemplate(rw, "template.html", article); err != nil { log.Fatalln(err.Error()) } }
そして、単にBodyを文字列としてtemplateにわたした際、htmlタグをエスケープしてくれないのでescapeHTML
関数を作成し、template.HTML
に変換する処理を入れてます(わざわざ別関数にしなくても良い気がしてきた…)
article := Article{ Title: "golang practice", Body: template.HTML("<h1>hello golang</h1>"), }
これでいいかも。
だた、この方法はXSSの対象となるやりかたなので、使用する際は十分注意するようにしてください。
エスケープせずうまく出力する方法は以下。
type Article struct { Title string Body string } var tpl *template.Template func safeHTMLTemplate(text string) template.HTML { return template.HTML(text) } func init() { funcMap := template.FuncMap{ "safehtml": safeHTMLTemplate } tpl = template.Must(template.New("").Funcs(funcMap).ParseFiles("template.html")) } func helloHandler(rw http.ResponseWriter, req *http.Request) { article := Article{ Title: "golang practice", Body: "<h1>hello golang</h1>", } if err := tpl.ExecuteTemplate(rw, "template.html", article); err != nil { log.Fatalln(err.Error()) } }
Body
をstringにしてます。 templateのエスケープしない処理部分をinit()
に逃がしました。
template側は
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{.Title}}</title> </head> <body> {{.Body|safehtml}} </body> </html>
.Body|safehtml
とすることでhtmlタグのエスケープを気にせず、うまいこと表示を実現してます。
この方法は以下の記事を参考にしました。感謝。
特にセキュリティ意識しなければどちらでも問題ないとは思います。
最初の方がイメージしやすいので、慣れたらtemplate.FuncMap
等使ってみると良いかもです。
jsonを返してみる
バックエンドはGo、フロントエンドはReactやVueを使いたい、そんなときGoはjsonを返すのがメインになると思います。
まずは超かんたんにhandlerを作成してみます。
func jsonResponseHandler(rw http.ResponseWriter, req *http.Request) { data := map[string]interface{}{ "message": "hello golang", "status": http.StatusOK, } // map to json bytes, err := json.Marshal(data) if err != nil { log.Fatal(err) } fmt.Fprint(rw, string(bytes)) } func main() { // http.Handle("/hello", http.HandlerFunc(helloHandler)) http.HandleFunc("/hello", helloHandler) http.HandleFunc("/dog", dogHandler) http.HandleFunc("/json", jsonResponseHandler) http.ListenAndServe(":3000", nil) }
該当箇所をピックアップしてます。requestは特に気にせず、決まったjsonを返す形です。
手順としては…
です。json.Marshal()
が今回の味噌。
func Marshal(v interface{}) ([]byte, error) { e := newEncodeState() err := e.marshal(v, encOpts{escapeHTML: true}) if err != nil { return nil, err } buf := append([]byte(nil), e.Bytes()...) encodeStatePool.Put(e) return buf, nil }
godocを見てみると、Marshalに渡すものは何でもokと(interface型はtypescriptで言うanyみたいなもん)。
深く見る必要はないので、返り値を確認するとbyteとerrorが返ってきてます。
何が返ってくるかはgodocを確認するか、エディタの拡張機能で定義元を確認するようにしてください。自分はvim-go
を使ってます。
json.Marshal()
を使うだけでjsonをbyte型に変換したものが得られるので、文字列に変換してやると見事にjsonを返すエンドポイントの完成ですb
structを使ったjsonを返してみる
次はmapではなくstructを使って返してみます。
DBからデータを抽出してstructにキャッシュし、それをjsonに変換してレスポンスを返す…みたいなことを想定してます。
type Product struct { Name string `json:"name"` Price int `json:"price"` Quantity int `json:"quantity"` } func productResponseHandler(rw http.ResponseWriter, req *http.Request) { // product := Product{"商品A", 100, 10} product := Product{ Name: "商品A", Price: 100, Quantity: 10, } // struct to json byte // bytes, err := json.Marshal(product)でもおk bytes, err := json.Marshal(&product) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) return } rw.Header().Set("Content-Type", "application/json") fmt.Fprint(rw, string(bytes)) }
また、追加部分だけ抜き出してます。
こう見ると、ほとんどmapのときと同じです。json.Marshal()
をしてやるだけ。structの場合ポインタを渡すことが多いので、&product
でわたしてます。
他にheader情報を付与したりhttp.Error()
で明示的にエラーが出るようにしてますが、mapのときと同じ構成でも問題なく動きます。
ポイントはstructの定義の際に、json指定をしてあげること。
type Product struct { Name string `json:"name"` Price int `json:"price"` Quantity int `json:"quantity"` }
これを指定しないと何が返ってくるかというと
ちゃんとjsonになってくれません。
structでレスポンスを返す場合は必ずjson指定をしましょう。
おわり
全体を通したコードがこちら
package main import ( "encoding/json" "fmt" "html/template" "log" "net/http" ) type Article struct { Title string Body string } type Product struct { Name string `json:"name"` Price int `json:"price"` Quantity int `json:"quantity"` } var tpl *template.Template func safeHTMLTemplate(text string) template.HTML { return template.HTML(text) } func init() { funcMap := template.FuncMap{ "safehtml": safeHTMLTemplate, } tpl = template.Must(template.New("").Funcs(funcMap).ParseFiles("template.html")) } func helloHandler(rw http.ResponseWriter, req *http.Request) { article := Article{ Title: "golang practice", Body: "<h1>hello golang</h1>", } if err := tpl.ExecuteTemplate(rw, "template.html", article); err != nil { log.Fatalln(err.Error()) } } func dogHandler(rw http.ResponseWriter, req *http.Request) { fmt.Fprintf(rw, "<h1>dogs</h1><h2>dog dog dog</h2>") } func jsonResponseHandler(rw http.ResponseWriter, req *http.Request) { data := map[string]interface{}{ "message": "hello golang", "status": http.StatusOK, } // map to json bytes, err := json.Marshal(data) if err != nil { log.Fatal(err) } fmt.Fprint(rw, string(bytes)) } func productResponseHandler(rw http.ResponseWriter, req *http.Request) { // product := Product{"商品A", 100, 10} product := Product{ Name: "商品A", Price: 100, Quantity: 10, } // struct to json byte bytes, err := json.Marshal(product) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) return } rw.Header().Set("Content-Type", "application/json") fmt.Fprint(rw, string(bytes)) } func main() { // http.Handle("/hello", http.HandlerFunc返す(helloHandler)) http.HandleFunc("/hello", helloHandler) http.HandleFunc("/dog", dogHandler) http.HandleFunc("/json", jsonResponseHandler) http.HandleFunc("/product", productResponseHandler) http.ListenAndServe(":3000", nil) }
次はもう少しhttp.Request
に関してまとめて、フレームワークを使った場合どうなるか、というのもまとめていければと思います。
ではでは。
【Docker】ローカルにredisをインストールしたくないときの対処法
どうもてぃです。
railsの完全ローカル環境を構築しないといけなくなったんですが、いかんせんインストールするものが多い。
題名の通りredisをインストールするのは良いんですが、他のプロジェクトでdockerを使っててdocker-compose upした際にポートがぶつかるのが面倒くさい。
そういった面倒臭さやインストールする煩わしさ、インストール後の設定の憂鬱さを解決する方法を伝授します。
環境
% lsb_release -a No LSB modules are available. Distributor ID: LinuxMint Description: Linux Mint 19.3 Tricia Release: 19.3 Codename: tricia
- Docker version 19.03.6, build 369ce74a3c
TL; DR
$ docker pull redis # requirepassはrails側で設定しているもの $ docker run --name redis-container -d -p 6379:6379 redis redis-server --appendonly yes --requirepass password
データを永続化させたいとき
今回はただの開発環境でrailsのsidekiq
のために必要であったため、特に永続化は気にしてません。
ですが、永続化させたくてどうしようもない方のために…
リファレンスを乗せときます\(^o^)/
dockerのリファレンスは神なのでぜひ見ましょうね…
冗談です。
以下のコマンドでたぶんいけます。
$ docker run --name redis-container -d -p 6379:6379 -v redis-data:/data redis redis-server --appendonly yes --requirepass password
おわりに
docker run オプションについては自分の過去記事を漁ってもらうか、安心と信頼のとても見やすいリファレンスを確認するとよいです。
redis以外にも入れたくないものがあればdockerで同じように対応してみるとdockerに慣れていけるんじゃないでしょうかね。
最後にdockerリファレンスのリンク貼っときますね。