2010-05-18 7 views
20

Ich habe eine Projektressource, die viele Aufgaben hat. Ich möchte sicherstellen, dass jede Aufgabe eine project_id durch Hinzufügen validates_presence_of :project_id zum Aufgabenmodell hat.Rails: validieren Präsenz der Parent-ID in has_many Zuordnung

Wenn jedoch ein neues Projekt mit Aufgaben erstellt wird, ist die Projekt-ID erst verfügbar, wenn der Datensatz gespeichert wird. Daher kann ich validates_presence_of :project_id nicht verwenden.

Also meine Frage ist, wie validiere ich Präsenz von Project_id im Aufgabenmodell? Ich möchte sicherstellen, dass jede Aufgabe einen Elternteil hat.

...

class Project < ActiveRecord::Base 

    has_many :tasks, :dependent => :destroy 
    accepts_nested_attributes_for :tasks, :allow_destroy => true 

...

class Task < ActiveRecord::Base 

belongs_to :project 
validates_presence_of :project_id 
+0

Diese Frage macht mir nicht viel Sinn. Sie möchten, dass eine Aufgabe zu einem Projekt gehört, ohne ein Projekt zu beginnen ... Wie ist es möglich, eine ID für etwas zu bekommen, das nicht existiert? – porkeypop

+3

Erstellen Sie Aufgaben über ein verschachteltes Formular, wenn Sie das Projekt erstellen? –

Antwort

17

Ihr Code funktioniert:

  • Wenn Sie validates_presence_of: Projekt, dann solange das Projekt gibt, wird es bestätigen. Wenn Ihr Projekt jedoch nicht gespeichert ist, können Sie die Aufgabe speichern.
  • Wenn Sie validate_presence_of: project_id bestätigen, muss die Ganzzahl dort sein und einen gespeicherten Wert anzeigen.

Hier ist rSpec, die den Punkt beweist. Wenn Sie validate: project_id, können Sie eine Aufgabe nicht speichern, ohne das Projekt zu speichern.

class Task < ActiveRecord::Base 
    belongs_to :project 
end 

/specs/modell_spez/task_spec.rb

require File.dirname(__FILE__) + '/../spec_helper' 

describe Task do 

    before(:each) do 
    @project = Project.new 
    end 

    it "should require a project_id, not just a project object" do 
    task = Task.new 
    task.project = @project 
    Task.instance_eval("validates_presence_of :project_id") 
    task.valid?.should == false 
    end 

    it "should not be valid without a project" do 
    task = Task.new 
    task.project = @project 
    Task.instance_eval("validates_presence_of :project") 
    task.valid?.should == false 
    task.save.should == false 
    end 

end 
+0

Ich möchte Ihre Antwort als richtig markieren, aber das Häkchen ist weg:/ – deb

+0

Dank deb! Vielleicht kommt es bald zurück. –

0

Ihre Project Klasse muss

accepts_nested_attributes_for :tasks 

Nested Model Form on Railscasts für weitere Details, wie sehen definieren die Form zu machen.


EDIT:

In dem Formular sollten Sie etwas wie dieses:

_form.html.erb

<% form_for @project do |f| %> 
    # project fields... 
    <% f.fields_for :tasks do |builder| %> 
     <%= render 'task_fields', :f => builder %> 
    <% end %> 
    <p><%= link_to_add_fields "Add task", f, :tasks %></p> 
    <%= f.submit %> 
<% end %> 

_task_fields.html.erb

<%= f.label :name, "Task name:" %> 
<%= f.text_field :name %> 
# task fields... 
<%= link_to_remove_fields "Delete task", f, :tasks %> 

und link_to_remove_fields sind in application_helper definierte Methoden zum dynamischen Hinzufügen/Löschen von Feldern.

+0

Die Frage ist, wie man project_id für Aufgaben obligatorisch macht. – deb

+0

Ich habe ein Beispiel für den Code zur Klärung veröffentlicht. danke! – deb

+0

hmn - gute Frage. Wenn sie also zusammen gespeichert werden, erstellt sie nicht zuerst Projekte, dann die Aufgaben? – digitalWestie

3

Vielleicht verstehe ich etwas nicht, aber es sieht so aus, als ob Sie versuchen, Schienen zu betrügen. Warum gehst du nicht einfach so tun:

class Task < ActiveRecord::Base 
    belongs_to :project 
    validate_presence_of :project 
end 
+0

Dies ist eine super alte Frage: Aber der Grund, warum Sie nicht eine einfache Zuordnung Validierung tun können, ist, weil die Aufgabe ist: fields_for ... sie sind in der: project Form verschachtelt. Beim Speichern ist die project_id noch nicht für die Validierung verfügbar und die Validierung schlägt fehl. Sie können dies testen, indem Sie einfach die Validierung für: projekt entfernen. Das: inverse_of stellt sicher, dass die Verknüpfung beim Speichern intakt ist. https://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations – hellion

2

Werfen Sie einen Blick auf diese:

https://rails.lighthouseapp.com/projects/8994/tickets/2815-nested-models-build-should-directly-assign-the-parent

Eine Sache, die ich in der Vergangenheit getan haben, ist hinzuzufügen: validates_presence_of :parent_id, :on => :update. Nicht großartig, aber es hilft, das Netz ein wenig zu straffen.

+0

Fantastisch! Das funktioniert wie ein Zauber. – molf

+0

Dies vernachlässigt vollständig die Erstellung Aktion. Nicht gut. Verwenden Sie: inverse_of, um sicherzustellen, dass Ihr übergeordnetes Objekt beim Speichern in verschachtelten Feldern verknüpft ist. https://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations – hellion

15

here für die endgültige Antwort Siehe:

class Project < ActiveRecord::Base 

    has_many :tasks, :dependent => :destroy, :inverse_of => :project 
    accepts_nested_attributes_for :tasks, :allow_destroy => true 

class Task < ActiveRecord::Base 

belongs_to :project 
validates_presence_of :project 

Nicht so elegant, wenn Sie mich fragen ... Es sollte transparent validieren.

+0

danke ich werde in "inverse_of" schauen – deb

2

Ich denke, Sie haben das gleiche Problem, das ich behandelt habe. Ich habe zwei Modelle, Konto und Benutzer, und wenn das Konto erstellt wird, wird der erste Benutzer über eine @account.users.build erstellt. Das Benutzermodell hat eine validates_presence_of :account Validierung.

Um den ersten Benutzerpass Validierung zu machen, habe ich den folgenden Code ein Modell zu meinem Konto:

before_validation_on_create :initialize_users 

    def initialize_users 
    users.each { |u| u.account = self } 
    end 
1

In Wirklichkeit müssen Sie beides:

validates_presence_of project 
validates_presence_of project_id 

diese Weise wird die Aufgabe nicht gespeichert werden In beiden folgenden Fällen vorausgesetzt, dass nur 2 gültige Projekte in der Datenbank vorhanden sind, dh die Projekt-ID 99 ist ungültig:

task.project_id = 99 
task.save 

task.project = Project.new 
task.save 

Ich hoffe, das hilft jemandem.