Finding elements in array of hashes
I'm trying to build a model of products which has many components. Some components are optional and depend on the choice the user is making to enable them or not. I have two models, one is configuration and the other is elements (of that configuration).
At the beginning I bring all the elements of the array, and then create another array of those which will be shown by default. But when I write the following code it gives me an error despite both objects being arrays of hashes.
So I bring my first array of all elements:
irb(main):252:0* @all = Configuration.find(1).elements
=> [#<Element id: 1, name: "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 2, name: "elem2", quantity: 2, position: 2, subposition: 1, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 3, name: "elem3", quantity: 3, position: 2, subposition: 2, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 4, name: "elem4", quantity: 4, position: 3, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>]
Then I filter to be only those that have a subposition nil or 1
irb(main):253:0> @default = @all.where(:subposition=>nil).concat(@all.where(:subposition=>1))
=> [#<Element id: 1, name:开发者_运维知识库 "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 4, name: "elem4", quantity: 4, position: 3, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 2, name: "elem2", quantity: 2, position: 2, subposition: 1, created_at: nil, updated_at: nil, configuration_id: 1>]
So far so good, as you can see, Elem3 is not being shown in @default as it doesn't meet the requiements.
The problem comes when I try to play with the arrays as I need to perform certain operations.
irb(main):257:0> @all.where(:position =>1)
=> [#<Element id: 1, name: "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>]
But the same operation in @default will fail,
irb(main):258:0> @default.where(:position =>1)
NoMethodError: undefined method `where' for #<Array:0x2641660>
Now, they're both arrays of hashes and look the same, why is the same method failing in the second case?
Thanks a lot for your help!
Throughout your code, @all
is an ActiveRecord::Relation
, not an array. This lets you perform the standard .where
call (among others). When you assigned to @default
, you used .concat
which evaluated the query and assigned an actual array to @default
.
You might try a different approach in your second code block. Maybe something like this:
@default = @all.where("subposition is null or subposition = ?", 1)
Well, your problem is that concat transforms a collection into an array.
I'd replace:
irb(main):253:0> @default = @all.where(:subposition=>nil).concat(@all.where(:subposition=>1))
by:
@default = @all.where("subposition = '1' OR subposition = nil") #I'm unsure of the nil in the statement, I nerver remember, try NULL if it fails
This way, you make only one db query and you keep an ActiveRecord collection.
Thus, you'll be able to chain other where conditions on it.
精彩评论