Reputation: 35
How can I get the same result, but like posts method is a simple association?
I want to do this: "user.posts.active". Is the best solution to define :finder_sql ?
class User < ActiveRecord::Base
has_many :created_posts, class_name: Post.name, foreign_key: :creator_id
has_many :updated_posts, class_name: Post.name, foreign_key: :updater_id
def posts
(created_posts + updated_posts).flatten.uniq
end
end
Upvotes: 1
Views: 63
Reputation: 33954
Rather than load both sets of posts and then uniqing them in Ruby, you can make that a little more efficient by having SQL only give you the unique list.
class User < ActiveRecord::Base
def posts
Post.where(["creator_id = ? OR updater_id = ?", self.id, self.id])
end
...
end
The reason this is more efficient is because it issues a single DB query with a single set of response rows, the duplicates are never returned to begin with, and ActiveRecord then only instantiates Ruby objects for that set of rows.
By way of comparison, the approach in your original question issues two DB queries, each of which creates an array of User
objects, then combines those two arrays, then removes duplicates. The extra object initialization, then the combining of arrays, then the iterations over the combined array needed to remove duplicates - all combined together - is where the bulk of the overhead takes place.
As with all optimization of this sort, if you're dealing with a very small dataset the difference in performance is probably negligible, however the single query, single set of responses approach is just plain smart in this case.
On a side note...
With the relationships as defined, if two users update the same post, one after the other, won't only the most recent user have their id assigned to the updater_id
? Is that what you intend?
Depending on the design of your app it may be better to record updates on their own, so that all users who have edited a given post will have that post in their list of updated_posts
.
Upvotes: 3