gitのリポジトリの中で、issueのURLを開くコマンドを作成した
いちいちgitを開けるのが面倒くさいってパターンです。
#!/usr/bin/env ruby require 'open-uri' url = "https://github.com/foo/bar/issues/#{ARGV.first}" system "open #{url}"
ファイル名をbin/issue
で登録する。
bin/issue 10
これで開きます。
もう少しいい書き方がありそう。
面倒くさいので、ターミナルからブラウザを開く行動までやっていきたいですね。
rubyでrakeの外部コマンドが失敗した時のエラーハンドリング
webpackerを使用していて、webpacker install
って出ているのに、installは失敗していた。
これはムカつくからpullreq出してやろうと思ったら、すでにあった。
さすがだ。
んで、実際のエラーハンドリング方法が思いつかなったので、これは参考になりました。
run './bin/yarn add webpack webpack-merge path-complete-extname babel-loader babel-core babel-preset-env coffee-loader coffee-script compression-webpack-plugin rails-erb-loader glob' unless $?.success? puts set_color 'Failed to install webpack!', :red exit $?.exitstatus end
$?
はprocessの実行結果がいます。
これを見て、成功したかどうかを判定して、エラー内容を記述していました。
芸がこまかい。
そして、$?
自体初めて知りました。
スレッドで最後の実行結果が入っているのですね。
$?
自体がUNIXの実行結果の可否を調べるものなので、それと同じ動きをしていたってことですね。
% cat foo =>cat: foo: No such file or directory % echo $? =>1
この辺はUNIX/Linux使いで、シェルとか作ってる人は分かるのでしょうが、自分は使ってないので、思いつかなかったので、これをきっかけに覚えておく。
以上です。
nvmでnodeをインストールしているのに、deployしたら「/usr/bin/env: node: No such file or directory」が出る場合
rails5からはcontrollerテスト書くぐらいなら、requestテストを書くのがいいっぽい
controllerテストいらねみたいな流れだったけど、requestテスト書けって話だったのか。
Rails 3 と 4 において、controller spec の assigns は慣用されてきました。 今回の RSpec 3.5 はマイナーリリースであり、私たちは SemVer に準拠する以上、 既存の controller spec を壊さないようにしています。 既存の Rails アプリケーションで assigns を多用しているものについては、 rails-controller-testing gem を Gemfile に追加することで assigns と assert_template を復活させることができます。 RSpec はこの gem とシームレスに連携するため、controller spec は問題なく動作し続けるはずです。
これから新しく作成する Rails アプリケーションについては、 rails-controller-testing gem を追加するのはおすすめしません。 Rails チームや RSpec コアチームとしては、代わりに request spec を書くことを推奨します。 Request spec は一つのコントローラーアクションにフォーカスしますが、 controller spec とは違い、ルーターやミドルウェアスタック、Rack リクエストやレスポンスも関与します。 これによって、より現実に近い環境でテストを実行し、controller spec で発生しがちな多くの問題を避けることができます。
今までもassings
を使用していたcontrolelrテストだと、下記を入れれば今まで通り使用できます。
これを使うぐらいなら、requestテストを書けって流れみたいだ。
なお、requestテストはcontrollerテストよりも早くなっているらしいので、早速試した。
Rails 5 では、request spec が Rails 4までの request spec や controller spec よりもかなり高速になっています。 これは Rails チームの Eileen Uchitelle1 のおかげです。
rails5のrequest
Finished in 0.33271 seconds (files took 5.43 seconds to load) 1 example, 0 failures
controller
Finished in 0.277 seconds (files took 11 seconds to load) 1 example, 0 failures
controllerの方がまだ早いかな・・・
流れ的には、requestテストの方がリアルなデータが取れるので、そっちを使えってことなので、今後はrequestテストを書いていく。
rails5ではrender methodをいたるところで使えるようになっている
rails5にアップデートするときに変更されていて、手を加えて変更したので、備忘録として書いておきます。
rails4.2時代のrenderのやり方
下記のように、requestを強引に擬似るような形でやっていました。
class Renderer def renderer controller = ApplicationController.new controller.request = ActionDispatch::TestRequest.new ViewRenderer.new(Rails.root.join('app', 'views'), {}, controller) end end class ViewRenderer < ActionView::Base include Rails.application.routes.url_helpers include ApplicationHelper def default_url_options { host: Rails.application.routes.default_url_options[:host] } end end Renderer.new.render
こういうやり方ではなく、ActionController::Renderer
というクラスメソッドが作られました。
コントローラのアクションの外部で任意のテンプレートでレンダリングするActionController::Rendererを追加。 (Pull Request)
rails/rendering.rb at master · rails/rails · GitHub
ということで、下記のようにすることでrenderをいたるところで呼べるようになりました。
ApplicationController.renderer.render partial: 'topics/image', locals: { url: url, host_name: host_name }
以上です。
vueのオブジェクトの並び順について
jsonで値を渡しているのに、並び順が違う!って状態に陥りました。
なんでだ?って思うと、どうもObject.keys()
の並び順に整理されるようですね。
オブジェクトを反復処理するとき、順序は Object.keys() の列挙順のキーに基づいており、全ての JavaScript エンジンの実装で一貫性が保証されていません。
ということで、ソートした状態にするには、 methodを使ってやるしかないようです。
以上です。
mysqlのorder by fieldで指定のID順に並べる
どういった時に使うんだよwwwって思いましたが、使う感じになりました。
select * from icons where id in(4, 5, 6) order by field(id, 5, 4, 6) => mysql> select * from icons where id in(4, 5, 6) order by field(id, 5, 4, 6); +----+------------------+-----------------+--------------------+-----------------+---------------------+---------------------+---------------------+ | id | icon_category_id | image_file_name | image_content_type | image_file_size | image_updated_at | created_at | updated_at | +----+------------------+-----------------+--------------------+-----------------+---------------------+---------------------+---------------------+ | 5 | 1 | 1f606.png | image/png | 2277 | 2017-03-13 15:09:17 | 2017-03-13 15:09:17 | 2017-03-19 00:50:29 | | 4 | 1 | 1f601.png | image/png | 2235 | 2017-03-13 15:09:17 | 2017-03-13 15:09:17 | 2017-03-19 00:50:29 | | 6 | 1 | 1f605.png | image/png | 2685 | 2017-03-13 15:09:17 | 2017-03-13 15:09:17 | 2017-03-19 00:50:29 | +----+------------------+-----------------+--------------------+-----------------+---------------------+---------------------+---------------------+
確かに順番通りに返ってくる。
https://dev.mysql.com/doc/refman/5.6/ja/string-functions.html#function_field
FIELD(str,str1,str2,str3,…)
str1、str2、str3、… リスト内で str のインデックス (位置) を返します。str が見つからない場合は、0 を返します。
FIELD() へのすべての引数が文字列の場合は、すべての引数が文字列として比較されます。すべての引数が数値の場合は、数字として比較されます。それ以外の場合は、引数が倍精度として比較されます。
NULL ではどの値との等価比較にも失敗するため、str が NULL である場合は、戻り値が 0 になります。FIELD() は ELT() の補数です。
FIELD関数を使用しているってことなのね。
railsで使う場合
ids = [5, 4, 6] Icon.where(id: ids).order("field(id, #{ids.join(',')})")
orderの中で文字列展開をして、使用しているってことですね。
rails5からはキチンとしたmethodがあるようです。
以上です。
参考
railsで複合uniqueのvalidationをつけてやる
複合uniqueなんて、使うことあるのか?って思っていたけど、必要になりました。
忘れないために書いておきます。
まずは、migrationの書き方からです。
class CreateReactions < ActiveRecord::Migration def change create_table :reactions do |t| t.references :icon, index: true, foreign_key: true, null: false t.integer :reactionable_id, null: false t.string :reactionable_type, null: false t.string :user_cookie_value, null: false t.timestamps null: false end add_index :reactions, [:reactionable_id, :reactionable_type] add_index :reactions,←ここから [:user_cookie_value, :icon_id, :reactionable_id, :reactionable_type], unique: true, name: :index_reactions_on_uniq_cookie_and_ids end end
そして、rails側
class Reaction < ActiveRecord::Base belongs_to :icon belongs_to :reactionable, polymorphic: true validates_uniqueness_of :reactionable_id, scope: [:icon_id, :user_cookie_value, :reactionable_type]←scopeで判定する end
scopeで値を絞ります。
参考
ActiveRecord::Validations::ClassMethods
以上です。
es2015の分割代入は、rubyのキーワード引数のイメージ
わかりづれー!ってなっていました。
{}
←これ何?って感じで意味不明に陥りやすかったです。
function foo({x, y}) { return x + y } console.log(foo({x: 1, y: 2})); =>3
x, yのvalueが代入されている。
これってrubyのキーワード引数と同じっぽく感じる。
def foo(x:, y:) x + y end foo(x: 1, y: 2) =>3
それだけです。
新しい記法は慣れるのに時間がかかる。
なおかつ、それをほとんど使用しない身としては、とても覚えづらいけど、似た様なものと関連付ければ覚えやすくもなる。
has_manyのhas_manyのcountで効率よくパフォーマンスを出す
counter_cacheはできるだけ使いたくないんですよ。
無駄なカラムを持ちたくないということで、頑張りました。
対策としては、最初で全てのcountを手にするのが一番いいですね。
countは重たいので、先に何とかして値を入手したい・・・。
今回のサンプルでは、Blogがあって、Commentをたくさん持っていて、さらにCommentに対して複数のReactionをつけれるようなものです。 それのgroup化したReactionの数が欲しいという状況でした。
サンプル
class Blog < ActiveRecord::Base has_many :comments, dependent: :destroy has_many :comment_reactions, through: :comments def comment_reactions_count_map comment_reactions.group(:comment_id, :reaction_id).count←これが今回の肝 => {[1, 1]=>7, [1, 315]=>1, [1, 332]=>1, [1, 708]=>1, [1, 825]=>1, [1, 864]=>1, [1, 1038]=>1, [1, 1044]=>1, [1, 1182]=>1, [1, 1229]=>1, [1, 1288]=>1, [2, 57]=>1, [2, 82]=>1, [2, 220]=>1, end end
class Comment < ActiveRecord::Base belongs_to :blog has_many :comment_reactions has_many :reactions, through: :comment_reactions end
class CommentReaction < ActiveRecord::Base belongs_to :comment belongs_to :reaction end
class Reaction < ActiveRecord::Base has_many :comment_reactions has_many :comments, through: :comment_reactions end
controller側
def show @blog = Blog.find(params[:id]) @count_map = @blog.comment_reactions_count_map←これでIDをセットする。 end
view側はこんな感じになりますね。
サンプルなんで、適当です。
show.html.slim
= render partial: "blog/comments", collection: @blog.comments.includes(:reactions), as: :comment
_blog/comments.html.slim
- if comment.reactions.present? - comment.reactions.group(:id).each do |reaction| = image_tag reaction.image.url = @count_map[[comment.id, reaction.id]]←これでcountの値をもらう
こんな感じでどうでしょうか。
パフォーマンスはexplainでコツコツ攻略するのも大事ですが、可能ならば、sqlのクエリを減らすのがいいですね。