Rails: Model fails to save cached column .counts

淺唱寂寞╮ 提交于 2019-12-12 03:35:53

问题


Ok, this has me wildly stumped. I have a model PhoneNumbers which has an integer column sent_messages_count. I use background tasks to use this column as a counter cache, however, this column's inaccuracies appears to be more fundamental.

Here's what I'd like to do:

phone_number.sent_messages_count = phone_number.sent_messages.count

Note that I'm setting the table column to the count of an association. Underscore vs. period.

See my console session... (I've done some clean-up to make it more terse).

# Find the phone number
[1] pry(main)> pn = PhoneNumber.find 38
  PhoneNumber Load (1.0ms)  SELECT  "phone_numbers".* FROM "phone_numbers" WHERE "phone_numbers"."id" = $1 LIMIT 1  [["id", 38]]
=> #<PhoneNumber:0x007f97902f6d70
 id: 38,
 updated_at: Thu, 07 Apr 2016 12:34:17 CDT -05:00,
 sent_messages_count: 12>

# Change the field to a new value
[2] pry(main)> pn.sent_messages_count = 100000
=> 100000

# Save it! It succeeds!
[3] pry(main)> pn.save
   (0.2ms)  BEGIN
  SQL (1.0ms)  UPDATE "phone_numbers" SET "sent_messages_count" = $1, "updated_at" = $2 WHERE "phone_numbers"."id" = $3  [["sent_messages_count", 100000], ["updated_at", "2016-04-07 17:37:41.826069"], ["id", 38]]
   (14.2ms)  COMMIT
=> true

# Reload it, and the saved value persists
[4] pry(main)> pn = PhoneNumber.find 38
  PhoneNumber Load (6.2ms)  SELECT  "phone_numbers".* FROM "phone_numbers" WHERE "phone_numbers"."id" = $1 LIMIT 1  [["id", 38]]
=> #<PhoneNumber:0x007f9790dc47e8
 id: 38,
 updated_at: Thu, 07 Apr 2016 12:37:41 CDT -05:00,
 sent_messages_count: 100000>

# Now, let's get the association count. It's 49.
[5] pry(main)> pn.sent_messages.count
   (1.6ms)  SELECT COUNT(*) FROM "messages" WHERE "messages"."from_id" = $1  [["from_id", 38]]
=> 49

# Setting column to association count
[6] pry(main)> pn.sent_messages_count = pn.sent_messages.count
   (0.6ms)  SELECT COUNT(*) FROM "messages" WHERE "messages"."from_id" = $1  [["from_id", 38]]
=> 49

# Look, the attribute has the counted value
[7] pry(main)> pn.sent_messages_count
=> 49

# And the in-memory instance had that value (I know, it's redundant)
[8] pry(main)> pn
=> #<PhoneNumber:0x007f9790dc47e8
 id: 38,
 updated_at: Thu, 07 Apr 2016 12:37:41 CDT -05:00,
 sent_messages_count: 49>

# Yep, we've changed!
[9] pry(main)> pn.changed?
=> true

# And we're valid!
[10] pry(main)> pn.valid?
  PhoneNumber Exists (0.8ms)  SELECT  1 AS one FROM "phone_numbers" WHERE ("phone_numbers"."number" = 'REDACTED' AND "phone_numbers"."id" != 38 AND "phone_numbers"."account_id" = 2) LIMIT 1
=> true

# And we're saving! ... but why is only updated_at changing?
[11] pry(main)> pn.save
   (0.2ms)  BEGIN
  SQL (0.7ms)  UPDATE "phone_numbers" SET "updated_at" = $1 WHERE "phone_numbers"."id" = $2  [["updated_at", "2016-04-07 17:39:07.200473"], ["id", 38]]
   (5.8ms)  COMMIT
=> true

# But our in-memory pn thinks it's 49
[12] pry(main)> pn
=> #<PhoneNumber:0x007f9790dc47e8
 id: 38,
 updated_at: Thu, 07 Apr 2016 12:39:07 CDT -05:00, 
 sent_messages_count: 49>

# But reloading makes me terribly sad. :(
[13] pry(main)> pn = PhoneNumber.find 38
  PhoneNumber Load (6.1ms)  SELECT  "phone_numbers".* FROM "phone_numbers" WHERE "phone_numbers"."id" = $1 LIMIT 1  [["id", 38]]
=> #<PhoneNumber:0x007f97912dc820
 id: 38,
 updated_at: Thu, 07 Apr 2016 12:39:07 CDT -05:00,
 sent_messages_count: 100000>

What's unclear to me is why setting the attribute to a calculated integer, instead of a literal integer is causing the column to not be saved.

Wildness and sadness. Anyone able to help me out?

Update

Including both the model and my schema. I'm omitting some class methods so this doesn't become the longest question ever.

models/phone_number.rb

include ActionView::Helpers::NumberHelper

class PhoneNumber < ActiveRecord::Base
  has_many :callable_phone_numbers
  has_many :students,
           through: :callable_phone_numbers,
           source: :callable,
           source_type: 'Student', inverse_of: :phone_numbers
  has_many :teachers,
           through: :callable_phone_numbers,
           source: :callable,
           source_type: 'Teacher'
  belongs_to :account
  has_many :sent_messages,
           class_name: 'Message',
           foreign_key: 'from_id',
           inverse_of: :from_phone_number
  has_many :received_messages,
           class_name: 'Message',
           foreign_key: 'to_id',
           inverse_of: :to_phone_number

  phony_normalize :number, default_country_code: 'US'
  validates_plausible_phone :number, presence: true
  validates :label, presence: true
  validates :account_id, presence: true
  validates :number, uniqueness: { scope: :account_id, message: "should only happen once per account" }, unless: :skip_uniqueness_validation
  attr_accessor :skip_uniqueness_validation

  # ... a bunch of scopes ...

  def messages
    Message.where("from_id = ? OR to_id = ?", id, id)
  end

  # ... some other class methods ...

  def most_recent_sent_message
    sent_messages.order("created_at DESC").take
  end

  def most_recent_received_message
    received_messages.order("created_at DESC").take
  end

  def update_caches!
    self.last_sent_message_at = self.most_recent_sent_message.try(:created_at)
    self.last_received_message_at = self.most_recent_received_message.try(:created_at)
    self.sent_messages_count = self.sent_messages.count
    self.received_messages_count = self.received_messages.count
    self.save
  end
end

schema.rb

  create_table "phone_numbers", force: :cascade do |t|
    t.string   "number"
    t.datetime "created_at",                              null: false
    t.datetime "updated_at",                              null: false
    t.string   "label"
    t.boolean  "assigned"
    t.integer  "account_id"
    t.integer  "sent_messages_count"
    t.integer  "received_messages_count"
    t.datetime "last_sent_message_at"
    t.datetime "last_received_message_at"
    t.string   "carrier_name"
    t.string   "carrier_type"
    t.datetime "carrier_updated_at"
    t.string   "home_language",            default: "en"
    t.boolean  "disconnected"
  end

来源:https://stackoverflow.com/questions/36483809/rails-model-fails-to-save-cached-column-counts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!