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

上記の回答に触発されて、仮想属性が設定されているときにフィールドが変更されていることを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 に答える
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 に答える
0

私は今あなたの問題を知っていると思います。_saveレコードで何も変更されていない場合、コールバックはトリガーされません。before_save親モデルで実際に何も変更せずに呼び出しているため、コールバックはトリガーされません。before_validationの代わりに使ってみてくださいbefore_save

于 2013-02-18T01:05:12.080 に答える