这是我在这里的第一个问题,所以希望它会成功。我到处寻找类似问题的人,但到目前为止还没找到任何东西。我确信它很简单但我现在看不到它!
我正在尝试在rails 3.2.11中保存模型的嵌套属性,但该操作仅在创建嵌套对象时有效,但在更新时无效
以下是我使用
的2个模型的代码class Property < ActiveRecord::Base
has_many :opening_times
accepts_nested_attributes_for :opening_times, :allow_destroy => true
attr_accessible :opening_times_attributes
...
class OpeningTime < ActiveRecord::Base
belongs_to :property
attr_accessible :start_date, :end_date
attr_accessible :day, :start_time, :end_time
attr_writer :day, :start_time, :end_time
before_save :set_dates
...
def set_dates
day = Date.parse(@day)
start_time = Time.parse(@start_time)
end_time = Time.parse(@end_time)
start_date = "#{day.day}/#{day.month}/#{day.year} #{start_time.hour}:#{start_time.min}"
self.start_date = DateTime.parse(start_date)
end_date = "#{day.day}/#{day.month}/#{day.year} #{end_time.hour}:#{end_time.min}"
self.end_date = DateTime.parse(end_date)
end
因此,当我尝试使用rails控制台创建一个属性的开放时间时,它可以工作:
1.9.3p125 :006 > p = Property.find(9)
1.9.3p125 :006 > p.opening_times_attributes = [{"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30", "_destroy"=>"false"}]
=> [{"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30", "_destroy"=>"false"}]
1.9.3p125 :007 > p.save!
(0.1ms) begin transaction
Suburb Load (0.2ms) SELECT "suburbs".* FROM "suburbs" WHERE "suburbs"."name" = 'BARREN GROUNDS' LIMIT 1
SQL (0.6ms) INSERT INTO "opening_times" ("end_date", "property_id", "start_date") VALUES (?, ?, ?) [["end_date", Wed, 27 Feb 2013 12:30:00 UTC +00:00], ["property_id", 9], ["start_date", Wed, 27 Feb 2013 11:30:00 UTC +00:00]]
(2.8ms) commit transaction
=> true
但是当我尝试更新现有的嵌套对象(在哈希中传递id)时,它什么都不做
1.9.3p125 :037 > p.opening_times
=> [#<OpeningTime id: 12, property_id: 9, start_date: "2013-02-27 11:00:00", end_date: "2013-02-27 13:00:00">]
1.9.3p125 :038 > p.opening_times_attributes = [{"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30", "_destroy"=>"false", "id"=>12}]
=> [{"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30", "_destroy"=>"false", "id"=>12}]
1.9.3p125 :039 > p.save!
(0.1ms) begin transaction
Suburb Load (0.2ms) SELECT "suburbs".* FROM "suburbs" WHERE "suburbs"."name" = 'BARREN GROUNDS' LIMIT 1
(0.1ms) commit transaction
=> true
1.9.3p125 :040 > exit
根据我到目前为止所读到的内容(即http://archives.ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes),这应该适用于两种操作。
对我做错了什么的想法?
谢谢!
[编辑]
基于@jvnill的建议,似乎在更新时没有调用before_save回调。我添加了一个解决方法,在任何字段更新后显式调用set_dates然后它可以工作。
def day=(day)
@day = day
set_dates unless (@day.blank? || @start_time.blank? || @end_time.blank?)
end
def start_time=(start_time)
@start_time = start_time
set_dates unless (@day.blank? || @start_time.blank? || @end_time.blank?)
end
def end_time=(end_time)
@end_time = end_time
set_dates unless (@day.blank? || @start_time.blank? || @end_time.blank?)
end
它并没有完全解决问题,因为现在验证无法无缝地工作,似乎我不得不手动完成AR应该做的工作。
答案 0 :(得分:1)
我会检查您是否可以在不使用嵌套属性的情况下更新您的子模型。您的验证或回调代码可能会停止更新,并且您的nested_attributes
电话没有任何问题。
那么,这有用吗?
> o = p.opening_times.first
> o.update_attributes({"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30"})
如果没有,请禁用验证和回调,并查看nested_attributes是否正确通过。
修改强>
好的,所以看起来问题在于嵌套属性调用。如果你试试这会怎么样?
> p.update_attributes(opening_times_attributes: [{"day"=>"27/02/2013", "start_time"=>"11:30", "end_time"=>"12:30", "_destroy"=>"false", "id"=>12} ])
注意,我正在调用update_attributes
而不是设置opening_times_attributes
编辑2:
如果您可以通过嵌套属性销毁记录,我怀疑某些东西拒绝您对子模型的更改。你检查过验证错误了吗?您是否尝试仅更新1个属性?
答案 1 :(得分:0)
我想我现在知道你的问题。当记录中没有任何更改时,不会触发_save
回调。因为您在没有真正改变父模型的任何内容的情况下调用before_save
,所以不会触发回调。尝试使用before_validation
代替before_save
。
答案 2 :(得分:0)
受上面答案的启发,我意识到你必须明确告诉AR在设置某个虚拟属性时字段正在改变,否则永远不会调用before_save回调。
这不是很好,但我找到的问题是调用{attr} _will_change!每当设置虚拟属性时:
def day=(val)
unless val == self.day
start_date_will_change!
end_date_will_change!
end
@day = val
end
def start_time=(val)
start_date_will_change! unless val == self.start_time
@start_time = val
end
def end_time=(val)
end_date_will_change! unless val == self.end_time
@end_time = val
end
感谢所有人的回复!