Reputation: 9886
I have an accounts model, where I would like the balance
to be readonly, but it can be updated via private methods.
Currently
class Account < ActiveRecord::Base
def deposit(amount)
# do some stuff and then
update_balance(amount)
end
private
def update_balance(amount)
self.balance += amount
end
end
However, this is still possible:
account = Account.first
account.balance += 5
account.save
I would like for the above to give an error, but still be able to do:
account.balance #=> 0
account.deposit(5)
account.balance #=> 5
Upvotes: 3
Views: 2209
Reputation: 15954
You may define a private setter for the attribute:
class Account < ActiveRecord::Base
private
def balance=(the_balance)
write_attribute(:balance, the_balance)
end
end
Then, you are not allowed to call it outside your Account
class:
Account.new(balance: 1234)
# => ActiveRecord::UnknownAttributeError: unknown attribute 'balance' for 'Account'
Account.new.balance = 1234
# => NoMethodError: private method `balance=' called for <Account ...>
Upvotes: 3
Reputation: 1526
ActiveRecord
not only the rails gem. This is a common-used pattern that means mirror-like representation of your DB in your object. So all data-access methods in your models can be defined automatically with ruby metaprogramming mechanisms.
Maybe it's better to keep your logic clear and convenient and write class AccountManager
that will works on top of Account
and can provide you such isolation that you need:
class AccountManager
def initialize(account)
@account = account
end
def deposit(amount)
# do some stuff and then
update_balance(amount)
end
private
def update_balance(amount)
@account.balance += amount
end
end
Upvotes: 1