Reputation: 9331
I have code something like this.
@deliveries = User.find_uniq_deliveries(...)
.
.
.
(many conditions added using 'named_scope' )
@deliveries.sort do |a,b|
.
.
end
The main problem is this is fetching lots of results and giving Oracle exception that more than 1000 elements are not allowed in 'in' statement. So I tried using find_each to fetch in batches
deliveries_list = []
@deliveries.find_each(:batch_size=999) do |delivery|
deliveries_list.push(delivery)
end
@deliveries = deliveries_list
But this gives the exception
undefined method `find_each' for []:Array
As you can see am quite new to rails ( coming from java) and rails totally don't make sense to me. What can I do to prevent Oracle SQL error but fetch data
EDIT :
def find_uniq_deliveries(category,date,view)
dels = []
sent_deliveries.send("for_#{category}s").send("with_#{category}_status", view).for_date_range(date).collect(&:workflow_item).uniq.each do |m|
dels << m.deliveries.first unless m.deliveries.empty?
end
dels.compact
end
Upvotes: 2
Views: 9893
Reputation: 9331
After lot of research for a week and learning about named_scopes by checking its source code. I understood what the problem was. The @deliveries
is an object of class ActiveRecord::NamedScope::Scope
. This class do not have find_each method. So I wrote a new named_scope for limit and offset in Delivery
model file as follows :
named_scope :limit_and_offset, lambda { |lim,off| { :limit => lim, :offset=>off } }
After this , I called it in a loop passing offset and limit , for ex. first loop has offset=0, limit=999 , second loop has offset=999, limit=999 . I will add all the results into an emptry array. This loop continues till the result size is less than the limit value . This is working exactly the way I wanted , in batches.
set = 1
total_deliveries = []
set_limit=999
original_condition = @deliveries
loop do
offset = (set-1) * set_limit
temp_condition = original_condition.limit_and_offset(set_limit,offset)
temp_deliveries = temp_condition.find(:all)
total_deliveries+= temp_deliveries
set += 1
break if temp_deliveries.size < set_limit
end
@deliveries = total_deliveries.sort do |a, b|
Upvotes: 1
Reputation: 672
find_each must be called on an Active Record Query result.
You are returning an array from your find_uniq_deliveries so find_each is not supported.
You would need to rewrite your query to put the find_each call before your .collect(&:workflow_item).
See also the Active Record Query Interface for methods that are chainable:
http://guides.rubyonrails.org/active_record_querying.html
The .collect method will result in an array of values so you can't put find_each after that.
EDIT: Here is a quick example of how to refactor your code to use find_each
The basic recipe is:
Build up an Active Record Query prior to calling any non-query methods such as collect.
As part of that query, you will use find_each to iterate over your result set in a way that will dynamically fetch batches of results from the database.
Save the non Active Record calls such as collect for last. You can return an array of results, but just know that you will not be able to call any other AR methods such as named scopes with this Array.
Here is an example find_uniq_deliveries that uses find_each and takes in a query:
def find_uniq_deliveries(query,category,date,view)
dels = []
query.send("for_#{category}s").send("with_#{category}_status", view).for_date_range(date).find_each do |delivery|
# do something with your delivery object and save result
result = process_delivery(delivery)
dels << result
end
dels.compact
end
And you can call it with any Delivery query like so:
query = Delivery.some_named_scope.some_other_scope
find_uniq_deliveries(query,category,date,view)
Upvotes: 4