I’d like to convert this method to a scope in rails so I could call something like Batch.all_completed and it would return all batches that met the criteria in the method:
def all_completed?
articles.with_status('Completed').count >= project.articles_per_week
end
The class definition of the batch that this will be run on is this:
class Batch < ActiveRecord::Base
has_many :articles
belongs_to :project
Is there a way to do this simply? with_status is a named scope, and articles_per_week is a method not a field. Here is the SQL output from the left side:
SELECT "articles".* FROM "articles" join jobs on jobs.article_id = articles.id join statuses on statuses.id = jobs.status_id WHERE ("articles".batch_id = XXX) AND (statuses.description = 'Completed')
Thanks!
[Edit 2]
Given that articles_per_week is not a field but a method, you’ll have to give up scope chainability – scopes boiled down are just AREL that generates a SQL statement, and there’s no way to bridge the gap between the instance method and the database. At this point, things actually get easier and you can just make the whole thing a class method, with a call to #reject at the end to drop the ones that don’t meet the count criteria:
And, you still get minimal DB hits with this (2). But, as noted calling #reject converts your output to a basic Array of objects rather than a chainable ActiveRecord collection.
Not sure why I had to convert article count to an integer, but so it was.
I’ve left my previous versions in, as I think they provide good additional info for other scenarios.
[Edit 1]
Here’s a version you can put as a scope on Batch, so that it’s chainable to other scopes.
I noted in testing this that it can have an impact on some of the standard ActiveRecord methods. For instance #size doesn’t work because on ActiveRecord that is translated into a SELECT COUNT(*), and that won’t work here due to the missing projects.articles_per_week in the selected fields.
[Original]
My first answer here.
I’m not sure if this qualifies for your request of “simply”, but it accomplishes the task in one SQL statement.
This assumes Rails 3 and the following model setups:
Incidentally, here’s my test data. The structure above correctly pulled batches 1 and 2 and ignored batch 3.