I was implementing my first HABTM relationship and have run into an issue with my query.
I am looking to validate my approach and to see if I have found a bug in the AREL (or some other part of Rails) code.
I have the following models
class Item < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_and_belongs_to_many :regions
end
class Region < ActiveRecord::Base
has_ancestry
has_and_belongs_to_many :items
end
I have the associated items_regions table:
class CreateItemsRegionsTable < ActiveRecord::Migration
def self.up
create_table :items_regions, :id => false do |t|
t.references :item, :null => false
t.references :region, :null => false
end
add_index(:items_regions, [:item_id, :region_id], :unique => true)
end
def self.down
drop_table :items_regions
end
end
My goal is to create a scope/query is follows:
Find all items in a region (and its subregions)
The ancestory gem provides a method to retrieve descendant categories for Region as an array. In this case,
ruby-1.9.2-p180 :167 > a = Region.find(4)
=> #<Region id: 4, name: "All", created_at: "2011-04-12 01:14:00", updated_at: "2011-04-12 01:14:00", ancestry: nil, cached_slug: "all">
ruby-1.9.2-p180 :168 > region_list = a.subtree_ids
=> [1, 2, 3, 4]
If there is only one element in the array, the following works
items = Item.joins(:regions).where(["region_id = ?", [1]])
The sql generated is
"SELECT `items`.* FROM `items` INNER JOIN `items_regions` ON `items_regions`.`item_id` = `items`.`id` INNER JOIN `regions` ON `regions`.`id` = `items_regions`.`region_id` WHERE (region_id = 1)"
However, if there are multiple items in the array and I try to use IN
Item.joins(:regions).where(["region_id IN ?", [1,2,3,4]])
ActiveRecord::StatementInvalid: Mysql::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1,2,3,4)' at line 1: SELECT `items`.* FROM `items` INNER JOIN `items_regions` ON `items_regions`.`item_id` = `items`.`id` INNER JOIN `regions` ON `regions`.`id` = `items_regions`.`region_id` WHERE (region_id IN 1,2,3,4)
The sql generated has an error at the end
"SELECT `items`.* FROM `items` INNER JOIN `items_regions` ON `items_regions`.`item_id` = `items`.`id` INNER JOIN `regions` ON `regions`.`id` = `items_regions`.`region_id` WHERE (region_id IN 1,2,3,4)"
the last part of the generated code should be
(region_id IN (“1,2,3,4”))
If I edit the sql manually and run it, I get what I expect.
So, two questions:
- Is my approach for the single value case correct?
- Is the sql generation a bug or have I configured things incorrectly?
Thanks
Alan
Should work in all cases, whether or not you specify one value or multiple.
The reason your original query doesn’t work is that you actually need to specify valid SQL. So alternatively you can do