0

Given the following functional snippet I'm having trouble reducing the database queries:

class User < ApplicationRecord
  belongs_to :account

  def self.do_something
    self.find_each do |user|
      puts "#{self.new.account.name}:#{user.name} did something"
    end
  end
end

class Account < ApplicationRecord
  has_many :users
end

a = Account.first
puts 'starting'
a.users.do_something

Account Load (0.4ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]

starting

Account Load (0.3ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]

Test:User did something

Account Load (0.3ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]

Test:User did something

Account Load (0.3ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]

Test:User did something

Account Load (0.3ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]

Test:User did something

You can see that the Account model is being fetched from the database per user!

I was hoping to use something like self.account in the Singleton method to reference the original account, but the relationship obviously doesn't exist by default which is why I'm currently using self.new.account.

Is there anywhere else I can fetch the original Account model saved in a from inside self.do_something? I can obviously pass the account in a parameter, but that seems tedious especially if I may add arguments later...

ted
  • 26
  • 2

1 Answers1

0

Inside your find_each loop, you should be able to use user.account.

Outside that loop, I don't believe there's a documented / supported / won't-disappear-without-warning way to find the object. Depending on your Rails version, something like self.current_scope.proxy_association.owner might give you the answer you need... but do prefer user.account if at all possible: the more you use private APIs, the harder future upgrades can be.


Alternatively, consider using association extensions to define your do_something method inside the has_many association only -- if it's not suited to be called as User.do_something or User.where(name: "Bob").do_something (because those don't have an associated account), maybe it shouldn't be a top-level method after all.

matthewd
  • 4,332
  • 15
  • 21