1

这是我在这里的第一个问题,所以希望它能解决。我已经四处寻找类似问题的人,但到目前为止还没有找到任何东西。我确定这很简单,但我现在看不到它!

我正在尝试在 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 应该做的工作。

4

3 回答 3

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 个属性?

于 2013-02-18T00:58:30.227 回答
1

受上述答案的启发,我意识到您必须明确告诉 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

感谢大家的回复!

于 2013-02-18T11:53:42.487 回答
0

我想我现在知道你的问题了。当_save记录中没有任何更改时,不会触发回调。由于您在before_save没有真正更改父模型上的任何内容的情况下调用,因此不会触发回调。尝试使用before_validation而不是before_save.

于 2013-02-18T01:05:12.080 回答