我有以下两个模型:
# app/models/customer.rb
class Customer < ActiveRecord::Base
has_paper_trail
serialize :mail_opt_out, Set
before_create :generate_token
has_many :wallets
has_many :tickets, through: :wallets
...
# We have a special seeded customer with id -1 that we don't want changing
def readonly?
persisted? && id < 0
end
end
# app/models/ticket.rb
class Ticket < ActiveRecord::Base
include SparkCast
has_paper_trail
belongs_to :price
belongs_to :basket
belongs_to :occurrence
has_one :event, through: :occurrence
has_one :wallet, through: :basket
has_one :basket_type, through: :basket
has_one :customer, through: :basket
delegate :id, to: :customer, allow_nil: true
...
def admit
ensure_can_admit
self.state = 'admitted'
self.save!
end
cast_on :admit, room: :admittance
def as_cast
{
id: id,
customer_id: customer_id
}
end
end
相关的关联有点复杂,但是是客户 -> 钱包 -> 篮子 -> 门票。
当我调用admit
属于我们客户的 ID 为 -1(只读)的票证实例时,我得到了一个ActiveRecord::ReadOnlyRecord
异常。
我对造成这种情况的原因感到困惑,因为机票和客户都没有任何before_update
回调。如果我改变
has_one :customer, through: :basket
至
delegate :customer, to: :basket
那么一切都很好。似乎有些东西要么试图更新客户,要么至少检查它是否是只读的。
我已经使用 逐步完成了保存过程byebug
,但找不到任何有用的东西。
什么可能会检查关联模型是否是只读的,我该如何解决这个问题?在这里使用委托是最好的选择吗?
编辑添加:
还包括我之前省略的 SparkCast。从我的票证模型中删除该cast_on
方法正在解决问题。
# app/models/concerns/spark_cast.rb
module SparkCast
extend ActiveSupport::Concern
module ClassMethods
def cast_on(*args)
# Options are the last argument.
options = args.pop
room = options[:room]
args.each do |operation|
class_eval do
begin
alias_method "#{operation}_without_cast", operation
define_method operation do |*args|
cast_hash = as_cast
...
send("#{operation}_without_cast", *args)
cast(room, operation, cast_hash)
end
rescue NameError => e
raise "#{e.name} has not been defined yet. Include cast_on after method definition"
end
end
end
end
end
end
回溯:
- activerecord (4.1.0) lib/active_record/persistence.rb:481:in `create_or_update'
- activerecord (4.1.0) lib/active_record/callbacks.rb:302:in `block in create_or_update'
- activesupport (4.1.0) lib/active_support/callbacks.rb:113:in `call'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:86:in `run_callbacks'
- activerecord (4.1.0) lib/active_record/callbacks.rb:302:in `create_or_update'
- activerecord (4.1.0) lib/active_record/persistence.rb:103:in `save'
- activerecord (4.1.0) lib/active_record/validations.rb:51:in `save'
- activerecord (4.1.0) lib/active_record/attribute_methods/dirty.rb:21:in `save'
- activerecord (4.1.0) lib/active_record/transactions.rb:268:in `block (2 levels) in save'
- activerecord (4.1.0) lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
- activerecord (4.1.0) lib/active_record/connection_adapters/abstract/database_statements.rb:209:in `transaction'
- activerecord (4.1.0) lib/active_record/transactions.rb:208:in `transaction'
- activerecord (4.1.0) lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
- activerecord (4.1.0) lib/active_record/transactions.rb:268:in `block in save'
- activerecord (4.1.0) lib/active_record/transactions.rb:283:in `rollback_active_record_state!'
- activerecord (4.1.0) lib/active_record/transactions.rb:267:in `save'
- activerecord (4.1.0) lib/active_record/autosave_association.rb:393:in `save_has_one_association'
- activerecord (4.1.0) lib/active_record/autosave_association.rb:188:in `block in add_autosave_association_callbacks'
- activesupport (4.1.0) lib/active_support/callbacks.rb:424:in `block in make_lambda'
- activesupport (4.1.0) lib/active_support/callbacks.rb:221:in `block in halting_and_conditional'
- activesupport (4.1.0) lib/active_support/callbacks.rb:86:in `run_callbacks'
- activerecord (4.1.0) lib/active_record/callbacks.rb:310:in `update_record'
- activerecord (4.1.0) lib/active_record/timestamp.rb:70:in `update_record'
- activerecord (4.1.0) lib/active_record/persistence.rb:482:in `create_or_update'
- activerecord (4.1.0) lib/active_record/callbacks.rb:302:in `block in create_or_update'
- activesupport (4.1.0) lib/active_support/callbacks.rb:113:in `call'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:166:in `block in halting'
- activesupport (4.1.0) lib/active_support/callbacks.rb:86:in `run_callbacks'
- activerecord (4.1.0) lib/active_record/callbacks.rb:302:in `create_or_update'
- activerecord (4.1.0) lib/active_record/persistence.rb:125:in `save!'
- activerecord (4.1.0) lib/active_record/validations.rb:57:in `save!'
- activerecord (4.1.0) lib/active_record/attribute_methods/dirty.rb:29:in `save!'
- activerecord (4.1.0) lib/active_record/transactions.rb:273:in `block in save!'
- activerecord (4.1.0) lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
- activerecord (4.1.0) lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
- activerecord (4.1.0) lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
- activerecord (4.1.0) lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
- activerecord (4.1.0) lib/active_record/transactions.rb:208:in `transaction'
- activerecord (4.1.0) lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
- activerecord (4.1.0) lib/active_record/transactions.rb:273:in `save!'
- () home/hayden/development/SparkSeat/api/app/models/ticket.rb:79:in `admit'