I have this sql query which I'm trying to convert to an ActiveRecord query:
SELECT DISTINCT name FROM `languages`
LEFT OUTER JOIN `items` ON `items`.`language` = `languages.id`
AND (`items`.`version_id` = '1.0')
WHERE `languages`.`id` != 'en';
What I am trying to do is get all languages which are not present in the items table where items.version_id
is for example, '1.0'. So lets say for simplicity, the languages table contains English, French and German and the items has a single row with version '1.0' and language 'en', I should then get French and German back with the above query.
(I'm no database expert so if some has a better query than the one above, I'm all ears).
I have the following models:
# item.rb
class Item < ApplicationRecord
belongs_to :language
belongs_to :version
end
# language.rb
class Language < ApplicationRecord
has_many :items
end
# version.rb
class Version < ApplicationRecord
has_many :items
end
I've tried a few different approaches which haven't worked out, for example on the console:
Language.left_joins(:items).where(items: {version_id: '1.0'})
.where.not(languages: {id: Item.distinct.pluck(:language_id)})
This generates the following two queries which results in an empty set:
SELECT DISTINCT `items`.`language_id` FROM `items`
=> Language Exists (0.5ms) SELECT 1 AS one FROM `languages`
LEFT OUTER JOIN `items` ON `items`.`language_id` = `languages`.`id`
WHERE `items`.`version_id` = '1.0'
AND (`languages`.`id` != 'en') LIMIT 1
Note how the order of WHERE
and AND
are swapped.
So I'm clearly not structuring the query right and would love to know how to approach it the rails way. Is it also possible to reduce the querys down to one database query?
I'm new to Rails and still learning about scopes etc, so I bundled everything into a single ActiveRecord query.