I am using Ruby on Rails 3.2.2, and I would like to know what a general approach is when it should be checked if the user has the appropriate permissions to "read" the entries in the "list" of entries. That is, at this time I have the following:
class Article < ActiveRecord::Base def readable_by_user?(user)
Using the code above, I can perform authorization checks for a single article object:
@article.readable_by_user?(@current_user)
However, when I would like to do (usually in my index action controller) something like the following, getting exactly 10 objects
Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)
I still need to perform authorization for each object. So, what can I do to perform authorization checks in this “list” of entries (an array of Article objects) in a smart / performance way? That is, for example, should you load Article.all (perhaps sort them by the created data, limiting the SQL query to 10 records, ...), and then iterate over each of these objects to perform authorization checks? or should I do something else (perhaps with a SQL query trick, some Ruby on Rails tool, or something else)?
UPDATED after @ Matzi's answer
I tried to get articles read by the user "manually", for example, using the find_each method:
# Note: This method is intended to be used as a "scope" method # # Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10) # def self.readable_by_user(user, n = 10) readable_article_ids = [] Article.find_each(:batch_size => 1000) do |article| readable_article_ids << article.id if article.readable_by_user?(user) # Breaks the block when 10 articles have passed the readable authorization # check. break if readable_article_ids.size == n end where("articles.id IN (?)", readable_article_ids) end
At this time, the above code is the most “compromise” compromise I can think of, even if it has some error: it “limits” the number of restored objects to a given number of records with a given id (10 default records in the above example) ; in fact, it doesn’t “really” retrieve all the objects that the user reads, because when you try to extend the scope of ActiveRecord::Relation "where" / "with which the readable_by_user method is used (for example, when you also search for articles using title adding another sentence of the SQL query), it would limit the entries to those where("articles.id IN (?)", readable_article_ids) (that is, "limited" / "limited" the number of restored and readable objects to the first 10 and all others articles read by the user will be ignored when searching by title ). The solution to the problem that the readable_by_user method worked correctly with additional methods of the area was to break block in such a way as to load all readable articles, but this is not suitable for performance when there are a lot of records (maybe another the solution may be to store the entire id article read by the user somewhere, but I think this is not a simple / easy solution to solve the problem).
So, is there a way to do what I would like to do in execution and "really" correctly (perhaps by changing the above approach in general)?