简体   繁体   中英

Rails - counter_cache for total sum

I have Transactions table which is the M:M table between Users and Products .

class Transaction
  belongs_to :user
  belongs_to :product, counter_cache: :transactions_count
end

Inside Transaction table, I have quantity column.

While inside Products, I have transactions_count which stores how many times this product has been purchased.

But that counter cache only count the number of rows . Is there a way to count the sum of quantity ?

I know I can use something like after_save :update_count , but is there a Rails convention that when followed will automate this task?

Thanks

I've personally found counter_cache to be very unreliable (giving negative values etc), and tend to shy away until it's improved

Something you may be interested in:


Alias Column

We wanted to do something similar (pull from join model) , and found a reliable way was to use an SQL Alias Column:

#app/models/user.rb
has_many :transactions
has_many :products, -> { select("#{User.table_name}.*, SUM(#{Transaction.table_name}.quantity) AS total") }, through: :transactions, dependent: :destroy

This may need some work, but will help#


ActiveRecord Association Extension

After discovering the .delegate method, I wanted to see if we could implement something similar for join models. 2 weeks later, we had it working:

#app/models/message.rb
Class Message < ActiveRecord::Base
   has_many :image_messages
   has_many :images, through: :image_messages, extend: ImageCaption
end

#app/models/concerns/image_caption.rb
module ImageCaption

    #Load
    def load
        captions.each do |caption|
            proxy_association.target << caption
        end
    end

    #Private
    private

    #Captions
    def captions
        return_array = []
        through_collection.each_with_index do |through,i|
            associate = through.send(reflection_name)
            associate.assign_attributes({caption: items[i]}) if items[i].present?
            return_array.concat Array.new(1).fill( associate )
        end
        return_array
    end

    #######################
    #      Variables      #
    #######################

    #Association
    def reflection_name
        proxy_association.source_reflection.name
    end

    #Foreign Key
    def through_source_key
        proxy_association.reflection.source_reflection.foreign_key
    end

    #Primary Key
    def through_primary_key
        proxy_association.reflection.through_reflection.active_record_primary_key
    end

    #Through Name
    def through_name
        proxy_association.reflection.through_reflection.name
    end

    #Through
    def through_collection
        proxy_association.owner.send through_name
    end

    #Captions
    def items
        through_collection.map(&:caption)
    end

    #Target
    def target_collection
        #load_target
        proxy_association.target
    end

end

This basically concatenates attributes from our join model ( image_messages ) to the parent object ( image ). You could use it to sum up your quantity in your proxy_association through collection, appending to each product the user has

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