Reputation: 20640
I have two models
class Contract < ActiveRecord::Base
has_many :transactions
end
class Transaction < ActiveRecord::Base
belongs_to :contract
after_create :mark_contract_as_live
def mark_contract_as_live
k = self.contract
if !k.is_live
k.update_attributes(:is_live => true)
end
end
end
is_live is a boolean field in the Contract model. A contract is defaulted to not live (is_live => false) when it created. When the first transaction is recorded it is marked as live (is_live => true). With the solution, I have above, it means that every transaction creation requires calling the database to check whether contract is live. Is there an alternative to this?
If contract has thousands of transactions, that means this will be called thousands of times although it is only relevant to the very first transaction.
In a general sense, what is an elegant way to implement callbacks. This seems messy?
Upvotes: 4
Views: 1622
Reputation: 27493
class Contract < ActiveRecord::Base
has_many :transactions
def mark_as_live
update(is_live: true) unless is_live?
end
end
class Transaction < ActiveRecord::Base
belongs_to :contract
after_create :mark_contract_as_live
private
def mark_contract_as_live
contract.mark_as_live
end
end
It is the Contract
class responsibility to care if a contract should be marked as live or not. The Transaction
class should not handle this. So I created a mark_as_live
in the Contract
class and call it in the Transaction
after_create
callback.
I would prefer to use a guard clause in the mark_as_live
method like so:
def mark_as_live
return if is_live?
update(is_live: true)
end
But because it is a very short method, it probably does not worth it.
Note also that ActiveRecord
adds methods like xxx?
for boolean field. A question mark at the end of the method conveys more clearly what you want to say.
Finally, but this is a question of taste, I dislike prefixing my boolean attributes with is_xxx
. I don't use RSpec
and may be wrong but I think that it adds some predicate matchers like be_xxx
for the xxx
attribute and it may go weird with the is_xxx
attributes. Because a lot of people are using RSpec
, it may become a bit of a convention.
If contract has thousands of transactions, that means this will be called thousands of times although it is only relevant to the very first transaction.
The Contract
instance will be still loaded if you create a transaction like so: contract.transactions.create(transaction_params)
. So the call to is_live?
will come at no cost, you don't have to worry.
Upvotes: 5