Для начала вы можете использовать псевдоним wood_production_amount
:
class City < ActiveRecord::Base
has_one :wood_production, :autosave => true
delegate :amount, :to => :wood_production, :prefix => true, :allow_nil => true
alias_method :wood, :wood_production_amount
alias_method :wood=, :wood_production_amount=
# ...
end
Это дает вам city.wood
и city.wood = n
, а поскольку Ruby является магией, вы автоматически получаете +=
, -=
и т. Д.бесплатно.Очень удобно.
Если вы хотите быть в состоянии сделать city.decrement(:wood)
(в дополнение к city.wood += n
), вам понадобится немного больше волшебства.
def decrement name, amt=1
# make sure it's an attribute we can set
unless respond_to? "#{name}="
raise ArgumentError, "Invalid attribute name for decrement"
end
# call the method by name to get the current value, then
# subtract amt from it
new_amt = send( name ) - amt
# set the new amount
send "#{name}=", new_amt
end
# Usage:
some_city = City.find(...)
some_city.wood
# => 90
some_city.decrement :wood
# => 89
some_city.decrement :wood, 80
# => 9
Кстати, этоможет быть разумнее сначала реализовать increment
, потому что это общий случай для decrement
:
def increment name, amt=1
check_argument name, :increment
new_amt = send( name ) + amt
send "#{name}=", new_amt
end
def decrement name, amt=1
check_argument name, :decrement
increment name, -amt
end
private
def check_argument name, meth
# make sure it's an attribute we can set
unless respond_to? "#{name}="
raise ArgumentError, "Invalid attribute name for #{meth}"
end
end