我有一个城市模型和一个wood_production模型。一个城市有一个wood_production,wood_production存储该城市的木材数量(列数量)。
现在,我在城市模型中有一个虚拟属性,如:
has_one :wood_production
delegate :amount, :to => :wood_production, :prefix => true, :allow_nil => true
def wood
self.wood_production_amount
end
因此,wood实际上来自wood_production模型,名为amount(通过委托)列。
现在,我想在不使用中间wood_production模型的情况下通过城市减少木材。理想情况下,我希望能够做到:
city.decrement(:wood)
或至少
city.wood -= ..
如果我现在尝试,则不保存新的木材值(在self.save之后)。我有什么想法可以正确保存它吗?
编辑:这是我现在尝试的代码:
has_one :wood_production, :autosave => true
delegate :amount, :to => :wood_production, :prefix => true, :allow_nil => true
def wood
self.wood_production_amount
end
def wood= amt
wood_production_amount = amt
end
现在,如果我这样做:
u = User.first
c = u.cities.first
c.wood -= 1000
我得到了(这确实是正确的)
=> 7432.778424219838
但是当我尝试保存时:
1.9.2p290 :006 > c.save
(0.1ms) BEGIN
(0.1ms) COMMIT
=> true
答案 0 :(得分:1)
您可能想要使用
accepts_nested_attributes_for :wood_production
或
has_one :wood_production, :autosave => true
答案 1 :(得分:1)
对于初学者,您可以使用别名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