2012年9月11日火曜日

scope

AR の scope はとても良い。AREL によって表現力が高まってからは本当に使い勝手が良い。

scope は何が良いかというとビジネスロジック上重要な概念に名前を付けてパッケージ化できるところがよい。複雑な sql を書いた場合、join, where、group by, order by などに散らばった複数の sql の断片がセットになっていることが多い。

例えば以下の例を見る。


select u.id
  from users u
         left outer join user_activation ua
            on ua.user_id = u.id
         left outer join user_emils ue
            on ue.user_id = u.id
 where ua.activated_on is not null
    and ue.emails = ""
 order by u.id

これは、activateされたユーザの中から email をまだ登録していないものを抽出する、という意味になる。activate された、という条件が user_activation のjoin と 最初の where 句に散らばっている。email についても同様だ。

scope を使うと sql では文法の制限上バラバラに配置されていたものが意味のまとまりによって再配置することができる。

scope :activated, joins(:user_activations).where("ua.activated_on is not null")
scope :has_not_email, joins(:user_emails).where(:user_emails => { :email => "" })

クエリは以下のようにかける。

userss = User.activated.has_no_email.order(:id).select(:id)

非常に読みやすくなる。実際の開発ではこれよりもはるかに複雑な sql を書いているが、scope のおかげでかなり理解しやすい。sql ゴリゴリ書いての開発なんてぞっとする。

なお、order(:id) や select(:id) は scope に含めることはあまりしないし、別途 scope を定義することもあまりしない。

scope :order_by_id, order(:id)

のような、名前がそれほど意味を圧縮できない場合にはうまみがないし、そのような scope が乱立するとコードがごちゃごちゃしてくる。このあたりは単純に、同じものがくりかして出てくるかどうかで scope にするかどうか、適当にまとめたらよいと思う。

0 件のコメント:

コメントを投稿