ActiveRecordでOR文を作るときのエラー対処
少し複雑なSQLのOR文をActiveRecordで作るときにはすこし億劫になりますね。
ArgumentError: Relation passed to #or must be structurally compatible. Incompatible values: [:joins, :references]
とエラーが出てしまったのでいろいろ調べてみました。
今回のエラーはRails5.2の以下のコードで ArgumentError が発生しています。
rails/query_methods.rb at c81a7fcf76663e6d189792d6eed57b1162199635 · rails/rails · GitHub
structurally_incompatible_values_for_or が何なのかと見てみると
rails/query_methods.rb at c81a7fcf76663e6d189792d6eed57b1162199635 · rails/rails · GitHub
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having, :unscope, :references] def structurally_incompatible_values_for_or(other) STRUCTURAL_OR_METHODS.reject do |method| get_value(method) == other.get_value(method) end end
Relation::VALUE_METHODS が 以下で登録されているのですが、
rails/relation.rb at ac1efe7a947ba04b276a7109f1a86e559a6ab683 · rails/rails · GitHub
[:includes, :eager_load, :preload, :select, :group, :order, :joins, :left_joins, :left_outer_joins, :references, :extending, :unscope, :limit, :offset, :lock, :readonly, :reordering, :reverse_order, :distinct, :create_with, :where, :having, :from]
ここから [:extending, :where, :having, :unscope, :references] を省いた項目が一致してることをチェックしてるので
[:includes, :eager_load, :preload, :select, :group, :order, :joins, :left_joins, :left_outer_joins, :limit, :offset, :lock, :readonly, :reordering, :reverse_order, :distinct, :create_with, :from]
の項目が一致してないと ArgumentError になるということですね。
これを個別に対応していくのは大変なのですね。。
これらの項目を設定するメソッドはいろいろ用意されてはいますが、
ActiveRecord::QueryMethods#methods: extending_values group_values includes_values= left_joins_values left_outer_joins_values= lock_value offset_value= preload_values readonly_value= reordering_value reverse_order_value= set_value eager_load_values extending_values= group_values= joins_values left_joins_values= limit_value lock_value= order_values preload_values= references_values reordering_value= select_values unscope_values eager_load_values= get_value includes_values joins_values= left_outer_joins_values limit_value= offset_value order_values= readonly_value references_values= reverse_order_value select_values= unscope_values=
a の オブジェクトから b のオブジェクトに移すみたいなことは項目数から考えても面倒ですね。
b.joins(a.joins_values)
項目を並べてget_value と set_value で移すこともできますが、、、
[:includes, :eager_load, :preload, :select, :group, :order, :joins, :left_joins, :left_outer_joins, :limit, :offset, :lock, :readonly, :reordering, :reverse_order, :distinct, :create_with, :from].each do |method| b.set_value(a.get_value(method)) end
流石に面倒そうです。
User. joins(:accounts). group(:id). having('count(accounts.id) > 2'). whrere(created_at: Time.zone.today.all_day)
このSQLにORを付けたいのですが、
当日と5日前に追加されたユーザを調べたいとします。
today = Time.zone.today relation = User. joins(:accounts). group(:id). having('count(accounts.id) > 2') relation.where(created_at: today.all_day).or(scope.whrere(created_at: today.days_ago(5).all_day))
このようにローカル変数にor前のRelationを渡してしまってwhereをつくればいいということですね。 少し面倒ですが、これで大丈夫そうです。
スコープを使ったケースを見てみます。
scope :hogehoge, -> { where(created_at: Time.zone.today.all_day) }
このようなscopeがあるとします。まだ条件は当日のみです。
User. joins(:accounts). references(:accounts). having('count(accounts.id) > 2'). group(:id). extending(Pagination). unscoped. hogehoge
先程の処理にhogehogeを追加してみました。 hogehogeのなかでOR文を作ってみます。
scope :hogehoge, -> { today = Time.zone.today where(created_at: today.all_day).or(where(created_at: today.days_ago(5).all_day)) }
ここではローカル変数なしに設定できました。
スコープではない場合は一旦変数に入れないといけないというのは不便ではあります。
これ自体が面倒な場合は String で直接SQLを記載するのがいいかもしれないです。
今回のケースはDateTime型で日付に対する条件になるので BETWEENが使われます。
day1 = today.all_day day2 = today.days_ago(5).all_day where('(users.created_at BETWEEN ? AND ?) OR (users.created_at BETWEEN ? AND ?)', day1.first, day1.last, day2.first, day2.last)
このような感じなります。
? に 設定する値がnilだった場合はこれだと面倒になったりするので
ケースによって使い方を選択してもいい気がします。
以下、参考にしたサイトです。
Unicode エンコードの競合 というファイル名になってしまう
20180419_プロダクションレディマイクロサービス.txt
というテキストファイルをDropboxのディレクトリに作っていたのですが、
20180419_プロダクションレディマイクロサービス (Unicode エンコードの競合).txt
という名前に変換されてしまっていました。 何なのかと思い、調べてみると
リンクされている別のパソコンで同期されないファイルがある場合 – Dropbox のヘルプ
ここの中に ユニコード エンコード問題 という項目があり、 Unicode Encoding Conflict とファイル名につくとありますがこれの日本語バージョンのようです。 とりあえず日本語を使うのをやめると解消されていました。 困ったものですね。。
Nodeのバージョンが10.0.0に
Nodeが早くも10.0.0です。 パフォーマンス改善も著しく注目も高いですね。 以下、CHANGELOGの内容です。
ちょうどNode学園の30時限目がありお邪魔してきました。
Nodeの改善に取り組んできた内容や今回の改善点、今後の展望?のようなことが聞けて為になりました。 HTTP GET のサンプルコードは async await書くことでコード量もスッキリしてとても良さそうです。 ローカルのNodeのバージョンも10.0.0を入れてみて楽しんでみます。
tmux が 2.7 にバージョンが上がっていたので brew で アップデートする。
⋊> ~ brew info tmux 21:47:47 tmux: stable 2.7 (bottled), HEAD Terminal multiplexer https://tmux.github.io/ /usr/local/Cellar/tmux/2.3_2 (10 files, 651.9KB) Poured from bottle on 2017-01-04 at 10:50:53 /usr/local/Cellar/tmux/2.5 (10 files, 660.3KB) Poured from bottle on 2017-09-19 at 00:14:09 /usr/local/Cellar/tmux/2.6 (10 files, 688.6KB) * Poured from bottle on 2018-02-11 at 15:02:02 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/tmux.rb ==> Dependencies Build: pkg-config ✔ Required: libevent ✔ Optional: utf8proc ✘ ==> Options --with-utf8proc Build with utf8proc support --HEAD Install HEAD version ==> Caveats Example configuration has been installed to: /usr/local/opt/tmux/share/tmux Bash completion has been installed to: /usr/local/etc/bash_completion.d
tmuxの2.7が既に出ていたのでバージョンアップしてみる。
⋊> ~ brew update tmux 21:47:59 Error: This command updates brew itself, and does not take formula names. Use 'brew upgrade tmux' instead. ⋊> ~ brew upgrade tmux 22:03:53 Updating Homebrew... ==> Auto-updated Homebrew! Updated Homebrew from 760a4601 to 27ec9dae. Updated 2 taps (homebrew/core, caskroom/cask). ==> New Formulae angle-grinder libde265 petsc ==> Updated Formulae ansible ✔ aws-shell dartsim exim git-annex jenkins-job-builder libre moc osquery picard-tools scrcpy tgui vtk libuv ✔ awscli dcd faas-cli git-fixup jetty librem mongo-orchestration osrm-backend pipenv scw thefuck watson node ✔ baresip dehydrated ffmbc gitlab-runner joplin libsass mpd ott ppsspp sdl2_gfx tika webp nvm ✔ basex diamond ffmpeg gmt jruby libtensorflow mpv packer pqiv sfcgal tile38 wireshark perl ✔ bdw-gc dnscrypt-proxy ffmpeg2theora gmt@4 json-fortran libwps mpw paket presto sfk tippecanoe wp-cli ruby-build ✔ bedops docfx ffmpegthumbnailer gollum juju liquibase mruby pam-u2f primesieve shogun tokei wpcli-completion vim ✔ bento4 docker-compose ffms2 gpgme jump logtalk nano pam_yubico pspg shyaml travis xmrig abcmidi bettercap docker-compose-completion field3d grafana jvgrep makeself nco pandoc puzzles silk twarc xonsh acpica bluepill dockviz flann grib-api kallisto mame ncview pandoc-citeproc pypy3 siril txr xrootd adplug bzt dscanner flow gws knot-resolver math-comp netcdf parallel qcli skaffold uftp yaz annie caffe dvm fluent-bit hadolint kubernetes-helm maxwell nexus pcl qemu skafos unpaper ykpers apache-drill cake dynare fn haskell-stack libbi meson nfdump pdal quex snakemake unrar youtube-dl apktool cayley elasticsearch@2.4 fobis hdf5 libdill mg nomad percona-server r snapcraft urh zanata-client arangodb cgal elasticsearch@5.6 folly heroku libebml mgba octave percona-server-mongodb radare2 sphinx-doc utf8proc armadillo checkbashisms emscripten fq hugo libetonyek mighttpd2 odpi percona-toolkit rmlint sratoolkit vagrant-completion artifactory cockroach encfs freeciv ice libfaketime mikutter opencv php robot-framework subversion valabind aspectj convox erlang freeling inspircd libmatio minidlna opencv@2 php@5.6 rocksdb swimat varnish@4 atari800 coq erlang@18 freeradius-server instead libmatroska mkl-dnn openfortivpn php@7.0 rom-tools tee-clc vault aubio corsixth etcd get-flash-videos iozone libmwaw mkvtoolnix openimageio php@7.1 rtf2latex2e telegraf vim@7.4 audacious cpanminus etsh gifski jenkins libraw mlt openrtsp pianobar scale2x texmath visp ==> Upgrading 1 outdated package, with result: tmux 2.6 -> 2.7 ==> Upgrading tmux ==> Downloading https://homebrew.bintray.com/bottles/tmux-2.7.high_sierra.bottle.tar.gz ######################################################################## 100.0% ==> Pouring tmux-2.7.high_sierra.bottle.tar.gz ==> Caveats Example configuration has been installed to: /usr/local/opt/tmux/share/tmux Bash completion has been installed to: /usr/local/etc/bash_completion.d ==> Summary 🍺 /usr/local/Cellar/tmux/2.7: 10 files, 700.7KB
以前痛い目に合ってたので念のためなくなっているもしくは名前が変更されているFormulaeがないことを確認しておいたほうがいい。
今回の2.7での変更点はパフォーマンス改善などが行われている以下のURLで確認できる。
https://raw.githubusercontent.com/tmux/tmux/2.7/CHANGES
尚、以下の一文
* Pass PWD to new panes as a hint to shells, as well as calling chdir().
が少しに気になっていてペインにディレクトリ階層を遅れたりしないのかなと思ったのだけどどうやってやったらいいのか。 そもそもそういうことでは無いってことなのか、調べてもよくわからなかったので、詳しく知りたいところ。。
brew で MySQL8.0をインストールする
MySQL8.0がリリースされましたね。
MySQL8.0の機能
MySQL :: MySQL 8.0: Up to 2x Faster
新機能と以下が上げられています。
- Document Store
- Transactional Data Dictionary
- SQL Roles
- utf8mb4 character set が Default に
- 共通テーブル式の追加
- Window関数の追加
- 不可視化インディックスの追加
- 降順インディックスでのパフォーマンス改善?
機能改善として以下が上げられています。
- JSONサポートが追加 JSON_TABLE() 関数 など
- 最大2倍高速化し、新しいベンチマーク180万回のクエリ/秒を記録
- MySQLのデフォルトのTLS / SSLライブラリとしてのOpenSSL
- 30倍高速のクエリを使用したパフォーマンス・スキーマ
- 100倍高速のクエリを含む情報スキーマ
- GISは、地理学および空間参照系(SRS)をサポートするように拡張
- レプリケーションとInnoDBクラスタの改善
Role設定ができることや、不可視化インディックスなど興味深いですね。
文字コードに関してはデフォルト設定が日本語には少し優しくない状態ですが、 以前よりは改善されてます。
以前からこの問題に関しては かみぽわーる さんが詳しく取り上げてくれていますね。
デフォルトの collationが utf8mb4_0900_ai_ci になってます。
utf8mb4_bin にしておけば概ね大丈夫ですね。
「MySQL」と「MySQL」を区別したくない場合は utf8mb4_0900_as_cs
私が扱っているサイトでは utf8mb4_bin 一択です。
以下のスライドで collation に関して詳しく書かれているので参考にされたい方は見て下さい。
www.slideshare.net
brew で インストール
かなり高速化されていると謳っているので Macで早速試してみたい方はbrewからインストールしてみてください。 brew optionsを見てみると
⋊> brew options mysql --with-debug Build with debug support --with-embedded Build the embedded server --with-local-infile Build with local infile loading support --with-memcached Build with InnoDB Memcached plugin --with-test Build with unit tests --devel Install development version 8.0.4-rc
になっているので
⋊> brew install mysql --devel
で8.0.4-rcがインストール可能です。 よいMySQLライフを!