好的,这让我非常难过。我有一个模型PhoneNumbers
,它有一个整数列sent_messages_count
。我使用后台任务将此列用作计数器缓存,但是,此列的不准确性似乎更为基础。
以下是我想做的事情:
phone_number.sent_messages_count = phone_number.sent_messages.count
请注意,我将表列设置为关联计数。下划线与期间。
请参阅我的控制台会话...(我已经做了一些清理工作以使其更简洁)。
# 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>
对我来说不清楚的原因是为什么将属性设置为计算的整数,而不是文字整数导致不保存列。< / p> 狂野和悲伤。有人能帮帮我吗?
更新
包括模型和我的架构。我省略了一些课程方法,所以这不会成为有史以来最长的问题。
模型/ 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