简体   繁体   中英

N+1 issue for custom method in rails

in my rails app I have a User model with a method called price_tier :

def price_tier
  Spree::PriceTier.by_code[read_attribute(:price_tier)]
end

However, when I have a collection of @users and call the price_tier one by one, it will load PriceTier query for every instance, which causes a N+1 issue.

includes is not working here since it's not an association.

@users.map { |user| user.price_tier }

Is there any way to modify the code which fixing the N+1 issue?

You really should setup the relationship between the models directly, eg user has_one :price_tier . This will make the code here a breeze.

If you don't do this, you're jumping through hoops for something that should be straightforward. You could maybe use something like the following, though it will still be far less effient than a direct relationship:

tiers = Spree::PriceTier.where(code: @users.pluck(:price_tier))
                        .each_with_object({}) { |tier, hash| hash[tier[code]] = tier }

@users.map { |user| tiers[user.price_tier] }

NB the above assumes removing the instance method :price_tier and using the attribute.

I'm not sure it's really worth including the above - you collect the users' price_tier, hit the db (only once, rather than for every user) for the tiers, iterate through them all to create a hash for fast access, then iterate through the users to map these. That's a lot of work for something that's solved easily by setting up a relationship.

Hope that helps, and really hope the tone comes across OK in the above - basically mean you could do something like the above, though the real advice would be: please don't, setup a relationship and work with the conventional approach here :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM