2012-05-11 37 views
4

それはAR.find_by_sqlによって実行することができますが、コードは前読める悪いです。 そのクエリをビルドできるクエリビルダーはありますか?RailsのSQLクエリビルダ...またはActiveRecordのクエリビルダ

$sql = DB::select('*')->from('users'); 
$sql->where('id', 'NOT_IN', DB::expr('SELECT partner_id FROM encounters WHERE user_id = '.$user->id)); 
$sql->where('id', 'NOT_IN', DB::expr('SELECT user_id FROM encounters WHERE partner_id = '.$user->id.' AND predisposition = '.Encounter::Negative)); 
.... 
etc 
... 

例えば、Kohanaのは(それがPHPのフレームワークです、私はPHP開発者ですが、私は/レールルビーすること子供に言語を変更したい)このように動作しますクエリビルダを、持っていますKohanaクエリービルダーのようなクエリービルダーで構築されたクエリーは、読みやすく分かりやすくなっています。

この問題を解決する宝石はありますか?

答えて

4

をチェックしてください。 はブロックを持つ ARを拡張し、非常に複雑なクエリを簡単に作成します。

ただ、いくつかの機能:

# not_in == cool!) 
Product.where{id.not_in LineItem.select{product_id}} 
# SELECT "products".* FROM "products" WHERE "products"."id" NOT IN 
# (SELECT "line_items"."product_id" FROM "line_items") 

# outer joins on pure Ruby: 
LineItem.joins{product.outer} 
# LineItem Load (0.0ms) SELECT "line_items".* FROM "line_items" 
# LEFT OUTER JOIN "products" ON "products"."id" = "line_items"."product_id" 

# calcs, aliasing: 
Product.select{[avg(price).as(middle)]} 
# SELECT avg("products"."price") AS middle FROM "products" 

# comparison 
Product.where{id != 100500} 
Product.where{price<10} 

# logical OR 
Product.where{(price<10) | (title.like '%rails%')} 
# SELECT "products".* FROM "products" WHERE (("products"."price" < 10 OR 
# "products"."title" LIKE '%rails%')) 

# xxx_any feature (also available xxx_all) 
Product.where{title.like_any %w[%ruby% %rails%]} 
# SELECT "products".* FROM "products" WHERE (("products"."title" LIKE '%ruby%' OR 
# "products"."title" LIKE '%rails%'))  

を使用してブロックを注意:ここで{...}はハッシュではありません。また、記号がないことにも注意してください。あなたは

3

関係代数を利用するRubyライブラリがあります。それはARelと呼ばれます。 Rails 3.xを使用している場合、既に持っています。

ids = Partner.where(user_id: self.id).pluck(:partner_id) << self.id 
users = User.where("id NOT IN #{ ids.join(',') }") 
+0

が、それはのようなクエリを構築するために、クエリでデシベル式を貼り付けることができ、「これはそれで重要な意味を運ぶ」で始まるセクションを読んで、それを選ぶことにした場合

「のユーザーSELECT * FROM WHERE ID != '+ self.id.to_s +' AND id NOT IN(SELECT artner_id WHERE user_id = '+ self.id.to_s +'に遭遇しました)? –

+0

@Zhirayr答えを編集しました – gmile

+0

なぜこの場合には左結合しませんか? –

3

ここでは、レールARELの用語に同じキャストがキャストされています。かなり複雑ではありません。一般的に複雑なクエリです。

User.where("id = ? AND " 
      "id NOT IN (SELECT artner_id FROM encounters WHERE user_id = ?) AND " + 
      "id NOT IN (SELECT user_id FROM encounters WHERE partner_id = ? AND predisposition = ?) AND " + 
      "cfg_sex = ? AND cfg_country = ? AND cfg_city = ?)", 
      self.id, self.id, self.id, Encounter::Negative, 
      self.sex, self.country, self.city).order(" rand() ").limit(1) 

(私はこれをテストしていませんでしたので、それがのがそれであっタイプミスすることができ可能です。)

私はカップルの事をお勧めしたい:あなたは彼らができる複雑なWHERE句を持っている場合

を一緒に鎖を張って、ARELはそれらを一般にきれいに戻します。これにより、モデルクラスでスコープを使用し、それらを連鎖させることができます。

User.is_of_sex(user.sex).in_city_state_country(user.city, user.state, user.country) 

など:

User < ActiveRecord::Base 
    self.def in_city_state_country(city, state, country) 
    where("cfg_sex = ? AND cfg_country = ? AND cfg_city = ?", city, state, country) 
    end 
    self.def is_of_sex(sex) 
    where("cfg_sex = ?", sex) 
    end 
end 

その後、クエリのこれらの部分をこのように書き換えることができます:たとえば、あなたはこれを

を行うことができます。

クエリを小さな部分に分割すると、特定の部分をrspecで簡単にテストすることもできます。モジュール化され、保守可能なコードが多くなります。詳細については

、あなたがsqueel宝石を必要とRails Guide - Active Record Query Interface