I need to run sql query like
sql = 'SELECT * FROM users WHERE id != ' + self.id.to_s + ' AND id NOT IN (SELECT artner_id FROM encounters WHERE user_id = ' + self.id.to_s + ')'
sql += ' AND id NOT IN (SELECT user_id FROM encounters WHERE partner_id = ' + self.id.to_s + ' AND predisposition = ' + Encounter::Negative.to_s + ')'
sql += ' AND cfg_sex = ' + self.sex.to_s + ' AND cfg_country = ' + self.country.to_s + ' AND cfg_city = ' + self.city.to_s
sql += ' ORDER BY rand() LIMIT 1'
It can be executed by AR.find_by_sql, but the code before is bad readable. Are there any query builder, which can build that query?
For example, Kohana (it is PHP framework, I am php developer, but I want to change that kid-language to ruby/rails) have a query builder, which works like this:
$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
...
Query which was builded with query builder like a Kohana query builder is more readable and understandable.
Are there any gem to solve this problem?
Arel is a SQL abstraction that ActiveRecord uses to build SQL queries. Arel wraps each component of the SQL query language with Ruby objects and provides an expressive DSL for composing SQL queries. When using Arel, you're mainly interacting with tables ( Arel::Table ) and nodes ( Arel::Nodes::Node subclasses).
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.
ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code. When you need to make changes to the database, you'll write Ruby code, and then run "migrations" which makes the actual changes to the database.
Arel is a library that was introduced in Rails 3 for use in constructing SQL queries. Every time you pass a hash to where, it goes through Arel eventually. Rails exposes this with a public API that we can hook into when we need to build a more complex query.
You need the squeel gem. It extends AR with blocks and makes very complicated queries with ease.
Just few features:
# 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%'))
Note the using blocks: {...}
here aren't hashes. Also note the absence of symbols.
If you decide to pick it, read the section that starts with "This carries with it an important implication"
There's a ruby library that utilizes relational algebra. It is called ARel. If you are using Rails 3.x, then you already have.
ids = Partner.where(user_id: self.id).pluck(:partner_id) << self.id
users = User.where("id NOT IN #{ ids.join(',') }")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With