disable `Call 'to_a' inside block ...` warning
Yaroslav-F opened this issue · comments
Hello,
I'm using distribute_reads { ... }
to force AR to use read replica.
I use .reload
to ensure queries go to read replica and result is still an AR relation, not an Array. The issue is that I can't get rid of these warnings:
[distribute_reads] Call `to_a` inside block to execute query on replica
Would it make sense to suppress these warnings when .reload
or .load
is used?
Hope it makes sense.
Thanks
Hey @Yaroslav-F, not sure I follow what you're trying to do. Can you give an example?
Hi @ankane ! Sure, so here's an example query:
irb(main):008:0> admin_users = distribute_reads { AdminUser.where(email: 'test@test.com') }
[Readreplica] SQL (0.4ms) SHOW SLAVE STATUS
[distribute_reads] Call `to_a` inside block to execute query on replica
[MasterNode] AdminUser Load (1.3ms) SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`email` = 'test@test.com'
I can see a warning from the gem saying that I need to use to_a
to avoid lazy loading. Fair enough!
Adding to_a
obviously fixes the warning and makes the request go to read replica, perfect.
irb(main):009:0> admin_users = distribute_reads { AdminUser.where(email: 'test@test.com').to_a }
[Readreplica] SQL (0.3ms) SHOW SLAVE STATUS
[Readreplica] AdminUser Load (0.4ms) SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`email` = 'test@test.com'
However the problem is that now admin_users
is an array object, not ActiveRecord::Relation. So, if I need to execute some queries on this object later - it will obviously break:
irb(main):007:0> admin_users.group(:email).count
NoMethodError: undefined method `group' for #<Array:0x007fbf4fdbdd80>
Fixing this issue is a piece of cake, I just need to call .load
or .reload
instead of .to_a
on the query. It will do pretty much the same thing but return an ActiveRecord::Relation
, which is perfect.
So here we go:
irb(main):008:0> admin_users = distribute_reads { AdminUser.where(email: 'test@test.com').load }
[Readreplica] SQL (0.3ms) SHOW SLAVE STATUS
[Readreplica] AdminUser Load (0.4ms) SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`email` = 'test@test.com'
[distribute_reads] Call `to_a` inside block to execute query on replica
irb(main):009:0> admin_users.group(:email).count
[2018-11-13 14:25:16] [Readreplica] (0.5ms) SELECT COUNT(*) AS count_all, `admin_users`.`email` AS admin_users_email FROM `admin_users` WHERE `admin_users`.`email` = 'test@test.com' GROUP BY `admin_users`.`email`
=> {"test@test.com"=>1}
Nice, it works, but there's this warning from distribute_reads telling me to call to_a
even though .load
did the job perfectly.
This gets worse when running test suite and getting tons of these warnings everywhere.
So the question is - can this warning be disabled when .load
or .reload
is used?
Hope it makes sense, but should you have any questions - please don't hesitate to ask.
Thanks!
Hey @Yaroslav-F, do you have DistributeReads.by_default = true
or nested distribute_reads
blocks in your last example? If not, the last query (count
) should go to the primary.
The short answer is it can't be disabled by design. In your case, you'd want to do:
users_relation = AdminUser.where(email: "test@test.com")
admin_users = distribute_reads { users_relation.to_a }
count = distribute_reads { users_relation.group(:email).count }
or
users_relation = AdminUser.where(email: "test@test.com")
distribute_reads do
admin_users = users_relation.to_a
count = users_relation.group(:email).count
end
ah, the sneaky by_default
, my bad, never mind
Thanks!