I have two models, let's say:
Post:
blog_id: integer
external_id: integer
Comment:
blog_id: integer
external_reference_id: integer
And have some items in my db:
Post.create external_id: 10, title: "Test 1", blog_id: 1
Post.create external_id: 10, title: "Test 2", blog_id: 2
Post.create external_id: 10, title: "Test 3", blog_id: 3
Comment.create external_reference_id: 10, title: "Comment 1.1", blog_id: 1
Comment.create external_reference_id: 10, title: "Comment 1.2", blog_id: 1
Comment.create external_reference_id: 10, title: "Comment 2.1", blog_id: 2
Comment.create external_reference_id: 10, title: "Comment 2.2", blog_id: 2
I need to relate post and comments using the external_
reference, that is:
class Post < ActiveRecord::Base
has_many :comments, foreign_key: :external_reference_id, primary_key: :external_id
end
class Comments < ActiveRecord::Base
belongs_to :post, foreign_key: :external_reference_id, primary_key: :external_id
end
What I need is to "scope" the relation between the two on blog_id to be the same.
By this I mean a scenario where I have different blogs on different server/databases, and I'm collecting all the data in a master server. I cannot preserve the original ID, so I store the id as external_id. This means that the Post with external_id: 1
and blog_id: 4
will have all the Comments that have external_reference_id: 1
and blog_id: 4
.
I may have lot of comments with the same external_id
but only that with the same blog_id really matches.
Surfing the internet, I found a couple of hint, the most popular opinions are something like this:
class Post < ActiveRecord::Base
has_many :comments, -> (object){ where("comments.blog_id = #{object.blog_id}") }, foreign_key: :external_reference_id, primary_key: :external_id
end
This solution correctly generate the query when doing Post.first.comments
:
SELECT COUNT(*) FROM "comments" WHERE "comments"."external_reference_id" = ? AND (comments.blog_id = 1) [["external_reference_id", 10]]
But it fails miserably when trying something more esoteric like Post.joins(:comments).count
giving:
NoMethodError: undefined method `blog_id' for #<ActiveRecord::Associations::JoinDependency::JoinAssociation
So far my solution is then:
class Post < ActiveRecord::Base
has_many :comments, -> (object){ where(object.respond_to?(:blog_id) ? "comments.blog_id = #{object.blog_id}" : 'comments.blog_id = posts.blog_id') }, foreign_key: :external_reference_id, primary_key: :external_id
end
Which works fine, but looks a little bit over-complicated in my opinion. Is there a better way to achieve this?