SQL で 300 個の空白を出力する
小ネタです。昔々のメモが見つかったので、紙を捨てる前にこちらに転記しておく。間違っているかもしれない。
select LPAD(' ', 300, ' ') from dual;
select CAST(' ' AS CHAR(300)) from dual;
こちらはCHAR型に変換しているので、2000バイトまで。
シェルスクリプトで $0 使うときの注意
これも同じメモに書いてあった小ネタ。
/Users/username/test.sh というファイル名のスクリプト中に
echo $0
とあった場合、$0 は起動時のパスになるので、
% ./test.sh ./test.sh % % /Users/username/test.sh /Users/username/test.sh % % ~/test.sh /Users/username/test.sh %
といった具合で、同じ環境でも起動の仕方で出力が変わる。$0 の値からパスを解析してゴニュゴニョしようとするとバグになるので注意。
Rails で十分に活用されていなくてもったいない ActiveRecord::Relation のメソッド TOP 10
2013年12月2日更新: 参照されることが多いので Rails 4 の情報を訳注として追記しました。また、Rails 4 に関する情報は、 WEB+DB PRESS Vol.73 が非常に参考になるので、一読をおすすめします。
この文章は Mitch Crowe 氏のブログより 2012年4月14日の記事を翻訳したものです。
The 10 Most Underused ActiveRecord::Relation Methods
http://blog.mitchcrowe.com/blog/2012/04/14/10-most-underused-activerecord-relation-methods/
昨日は ActiveRecord::Relation のコードに膝まで浸かって、使われているのをこれまで全然見たことがない面白いナゲットを思い出させてくれた。この記事で、十分に活用されていない Relation クラスのメソッドのトップ10をリストにしたので、楽しんでもらいたい。
10位 ブロック付きの first_or_create
first_or_create はとてもなじみ深い。
Book.where(:title => 'Tale of Two Cities').first_or_create
そして、名前通りのことをやってくれる。だが、特定の属性を持つレコードを find するとか、それらの属性を持つレコードを create して、さらに追加で属性を設定したくなることが頻繁にあると思う。これを簡潔にやるには first_or_create にブロックを与えればいい。
Book.where(:title => 'Tale of Two Cities').first_or_create do |book| book.author = 'Charles Dickens' book.published_year = 1859 end
9位 first_or_initialize
このレコードをまだ保存したくない場合は、 first_or_initialize が使える。
Book.where(:title => 'Tale of Two Cities').first_or_initialize
8位 scoped
あるクラスの持つすべてのレコードを表した ActiveRecord::Relation がほしいことがある。そんなときは scoped メソッドを使えば簡単に生成できる。(訳注: Rails 4 では、 scoped が非推奨になり、 all が Array から ActiveRecord::Relation のオブジェクトを返すようになりました。Rails 4 では scoped から all に変更してください。)
def search(query) if query.blank? scoped else q = "%#{query}%" where("title like ? or author like ?", q, q) end end
7位 none ( Rails 4 のみ)
同じように、オブジェクトを含まない ActiveRecord::Relation がほしいことがある。空の Array を返すことが、大抵それほどよくないのは、 API の利用者が Relation オブジェクトを期待しているからだ。代わりに none を使えばいい。
def filter(filter_name) case filter_name when :all scoped when :published where(:published => true) when :unpublished where(:published => false) else none end end
注意:最先端を行く人は今すぐ none を使いたくなっていることだと思う。これは、 Rails 3 ではなく、 Rails 4 で利用できる。だが、Rails 4 を待つまでの間も簡単に書くことができる。 この Stack Overflow のスレッドをチェックしてほしい。
6位 find_each
数千レコードをイレテートさせたくなっ場合、each を使いたくはないだろう。
each は1 つのクエリを実行して、全レコードを取得し、それらすべてをメモリ上にインスタンス化してしまう。メモリを十分に確保しているならいい。確保してなければ、これは Rails アプリをフリーズさせる素敵な方法になる。find_each は、そうではなく、レコードをバッチ処理で find して(デフォルトは1000件)、一度に yield する。その結果、同時に全レコード分のメモリを確保する必要がなくなる。
find_each は yield されるレコードの順序を指定できないので注意だ。指定してもただ単に無視される。
Book.where(:published => true).find_each do |book| puts "Do something with #{book.title} here!" end
5位 to_sql と explain
ActiveRecord は素晴らしいが、思った通りのクエリをいつも生成してくれるとは限らない。コンソールに飛んで、組み立てた Relation で この 2 つの命令を実行してみよう。賢いクエリにマップされているか確認して、そうなってなかったら愛情込めて作ったインデックスを使うようにしよう。
Library.joins(:book).to_sql # => SQL query for you database. Libray.joins(:book).explain # => Database explain for the query.
4位 find_by(Rails 4 のみ)
Rails で書いたコードは次のような行で散らかったものになりやすい。
Book.where(:title => 'Three Day Road', :author => 'Joseph Boyden').first
代わりに、 find_by というショートカットメソッドが使える。
Book.find_by(:title => 'Three Day Road', :author => 'Joseph Boyden')
これは上と同じものが実行される。
注意:最先端を行く人は今すぐ find_by を使いたくなっていることだと思う。これは Rails 3 ではなく、 Rails 4 で利用できる。
3位 scoping
scope メソッドを特定の Relation として使える。Rails のドキュメントにある次の例を検討してみよう。
Comment.where(:post_id => 1).scoping do Comment.first # SELECT * FROM comments WHERE post_id = 1 end
これはまったくもって使いやすい。
2位 pluck
特定のレコードのカラムで配列にしたいことがないだろうか?私はこういうにを本当にたくさん見てきた。
published_book_titles = Book.published.select(:title).map(&:title)
さらに悪い場合だとこうだ。
published_book_titles = Book.published.map(&:title)
代わりに pluck を使おう。
published_book_titles = Book.published.pluck(:title)
(訳注: Rails 3 では、pluck の引数に指定できるシンボルは 1 つでしたが、 Rails 4 ではシンボルの配列を指定することで、属性を複数指定することができます。select で複数の属性を指定した場合と違い、2次元配列を返します。3 系でも比較的最近のバージョンで使えるはずです。)
1位 merge
僕はこの宝石なしには生きられない。しかし奇妙なことに、これはソース中にドキュメントされていないし、今まで見たガイドでも言及がない。これを使うと、結合( JOIN )ができて、結合されたモデルに対して名前付きスコープでフィルタできる。(訳注: 私見ですが、4.0.0 では merge が意図と違う動作をしないかよく確認した方がよいと思います。*1 いくつか修正が入っている4.0.1 以降でも試してみてください。)
class Account < ActiveRecord::Base # ... # Returns all the accounts that have unread messages. def self.with_unread_messages joins(:messages).merge( Message.unread ) end end
- 作者: 設樂洋爾,白土慧,はまちや2,大和田純,松田明,後藤大輔,ひろせまさあき,小林篤,近藤宇智朗,まかまか般若波羅蜜,Mr. O,川添貴生,重国和宏,柳澤建太郎,奥野幹也,佐藤鉄平,後藤秀宣,mala,中島聡,堤智代,森田創,A-Listers,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2013/02/23
- メディア: 大型本
- 購入: 12人 クリック: 131回
- この商品を含むブログ (7件) を見る