2012-05-17 75 views
0

我想創建一個嵌套的子孫記錄。小孩屬於父母和孫子。孩子不會驗證孫子的身份,因爲它還沒有被保存。嵌套記錄無法驗證,因爲它的嵌套belongs_to不保存

我正在使用Rails 2.3.11,Formtastic,InheritedResources和Haml,以及其他一切似乎正常工作 - 例如,在父窗體中正確填充孫子的驗證錯誤,並且無效值被記住並且呈現給用戶。父模型甚至不會嘗試更新,除非一切正常,就像它應該那樣。

我的代碼是這樣的事情,雖然在不同的問題域:

class Project < ActiveRecord::Base 
    has_many :meetings, :dependent => :destroy 
    accepts_nested_attributes_for :meetings 
end 

class Meeting < ActiveRecord::Base 
    belongs_to :project 
    belongs_to :task 
    accepts_nested_attributes_for :task 
    validates_presence_of :task_id, :project_id 
end 

class Task < ActiveRecord::Base 
    has_many :meetings, :dependent => :destroy 
end 

工程總已經存在,並且可能已經有了,我們不希望看到會議。任務可能通過其他會議屬於其他項目,但在這種情況下,任務和會議總是新的。

在控制器中,我只在新的動作

@project.meetings.build 

建立一個空白記錄並保存數據是這樣的:

@project.update_attributes(params[:project]) 

,並在視圖

- semantic_form_for @project do |f| 
    - f.semantic_fields_for :meetings do |m| 
    - next unless m.object.new_record? 
    = m.semantic_errors :task_id 
    - m.object.build_task unless i.object.task 
    - m.semantic_fields_for :task do |t| 
     - f.inputs do 
     = t.input :task_field 
     = m.input :meeting_field 

當我嘗試保存表單時,出現「任務不能爲空」的驗證錯誤。那麼,當然,該任務還沒有保存,我想驗證,我沒有一個ID。

是否有一種簡單而優雅的方式來確保孫子記錄(Task)在子記錄之前生成?

我已經試過這樣的事情在會議模式:

before_validation_on_create do |meeting| 
    meeting.task.save if meeting.task.valid? 
end 

這似乎保存任務,但會議仍然沒有得到正確的ID。同樣的錯誤,但任務記錄被創建。

我也試過這樣:

before_validation_on_create do |meeting| 
    new_task = meeting.task.save if meeting.task.valid? 
    meeting.task = new_task 
end 

其中有提高的ActiveRecord :: RecordNotFound的奇怪行爲「無法與ID找到工作= XX與ID =會議」 - 這是我的排序得到,但似乎像一個紅色的鯡魚。

我也嘗試添加:inverse_of所有的關係和驗證:任務,而不是:task_id。後者奇怪地失敗了,但似乎沒有給出任何錯誤信息。

我在這裏的實際目標是創建多個Task,每個Task都有一個關於先前選擇的項目的初始會議......所以我可以採取另一種方法處理我的問題 - 我可以在控制器中做一些簡單而醜陋的事情,或者在項目的after_create中創建第一個會議。但是這非常漂亮,所以接近工作。事實上,我得到適當的驗證錯誤:task_field和:meeting_field意味着我在正確的軌道上。

我看到問題是什麼,但沒有如何解決它:我懷疑我錯過了一些明顯的東西。

謝謝!

回答

1

嗯,我找到了一個解決方案,基於其中一個類似的問題,但缺點是「rails 2.3似乎並不擅長這一點。」我想我可以用比我見過的其他答案更簡潔的方式來回答問題。

你所做的是你跳過驗證:task_id,但只有當任務是有效的!大多數我見過使用PROC其他的答案,但我認爲它使用委託,這樣更具可讀性:

delegate :valid?, :to => :task, :prefix => true, :allow_nil => true 
validates_presence_of :task_id, :unless => :task_valid? 

我也有水線下隱藏着另一個問題 - 的情況下,「項目」實際上是我想要保護的一種特殊類型的記錄,它具有(故意)僅僅針對這個特殊記錄失敗的驗證,並且我還設置了只讀?爲特殊記錄爲真。

雖然我實際上並不是更改那個特殊記錄,但它仍然需要驗證並且不能只讀來通過它更新孩子。出於某種原因,我沒有看到該驗證的錯誤消息。爲了解決這個問題,我對該項目進行了驗證,只適用於:on =>:create,並且我只讀取了只讀?事情。

但一般的解決方案是「如果對象本身有效,則不驗證未建立的belongs_to對象的存在」。 NIL永遠不會有效,因此如果你只有一個object_id,驗證仍然有效。

(請不要投下真誠的問題,除非你有答案或鏈接,我知道這個問題已被別人以其他方式提出,我讀了很多其他問題,似乎是完全相同的問題,我沒有找到解決方案。)