2010-05-18 31 views
20

Tôi có tài nguyên dự án có nhiều tác vụ. Tôi muốn đảm bảo rằng mọi công việc đều có project_id bằng cách thêm validates_presence_of :project_id vào mô hình nhiệm vụ.Đường ray: xác thực sự hiện diện của parent_id trong liên kết has_many

Tuy nhiên, khi tạo dự án mới có tác vụ, project_id sẽ không khả dụng cho đến khi bản ghi được lưu, do đó tôi không thể sử dụng validates_presence_of :project_id.

Vì vậy, câu hỏi của tôi là, làm cách nào để xác thực sự hiện diện của project_id trong mô hình nhiệm vụ? Tôi muốn đảm bảo mọi công việc đều có cha mẹ.

...

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

Câu hỏi này không hợp lý với tôi. Bạn muốn một nhiệm vụ thuộc về một dự án mà không có dự án bắt đầu bằng ... làm thế nào để có thể nhận được một id cho một cái gì đó không tồn tại? – porkeypop

+3

Bạn có tạo công việc thông qua biểu mẫu lồng nhau khi bạn tạo dự án không? –

Trả lời

17

Mã của bạn hoạt động:

  • Nếu bạn validates_presence_of: dự án, sau đó miễn là dự án là có, nó sẽ xác nhận. Nhưng nếu dự án của bạn chưa được lưu, bạn vẫn có thể lưu nhiệm vụ.
  • Nếu bạn validates_presence_of: project_id, thì số nguyên phải ở đó, cho biết giá trị đã lưu.

Đây là rSpec chứng minh điểm. Nếu bạn xác thực: project_id, bạn không thể lưu tác vụ mà không lưu Dự án.

class Task < ActiveRecord::Base 
    belongs_to :project 
end 

/specs/model_specs/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

Tôi muốn đánh dấu câu trả lời của bạn là đúng nhưng dấu kiểm đã biến mất:/ – deb

+0

Cảm ơn deb! Có lẽ nó sẽ sớm quay lại. –

0

lớp Project bạn phải xác định

accepts_nested_attributes_for :tasks 

Xem Nested Model Form on Railscasts để biết thêm chi tiết về làm thế nào để làm cho biểu mẫu.


EDIT:

Ở dạng của bạn, bạn nên có một cái gì đó như thế này:

_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 %> 

link_to_add_fieldslink_to_remove_fields là các phương thức được định nghĩa trong application_helper để thêm/xóa các trường động.

+0

Câu hỏi đặt ra là làm thế nào để thực hiện project_id bắt buộc cho các nhiệm vụ. – deb

+0

Tôi đã đăng một ví dụ về mã để giúp làm rõ. cảm ơn! – deb

+0

hmn - câu hỏi hay. Vì vậy, khi chúng được lưu cùng nhau nó không tạo ra các dự án đầu tiên, sau đó các nhiệm vụ? – digitalWestie

3

Có lẽ tôi không hiểu điều gì đó, nhưng có vẻ như bạn đang cố gắng lừa gạt đường ray. Tại sao bạn không chỉ cần làm như thế này:

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

Đây là một câu hỏi cũ: Nhưng, lý do bạn không thể thực hiện xác nhận liên kết đơn giản là vì tác vụ là: fields_for ... chúng được lồng trong biểu mẫu: project. Khi lưu, project_id sẽ không có sẵn để xác thực và việc xác thực sẽ thất bại. Bạn có thể kiểm tra điều này bằng cách loại bỏ xác thực cho: project. Các: inverse_of đảm bảo các hiệp hội là trong tact lúc lưu. https://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations – hellion

2

Hãy xem này:

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

Một điều tôi đã làm trong quá khứ là thêm: validates_presence_of :parent_id, :on => :update. Không tuyệt vời nhưng nó giúp thắt chặt lưới một chút.

+0

Tuyệt vời! Công việc này như một cái duyên vậy. – molf

+0

Điều này hoàn toàn bỏ qua hành động tạo. Không tốt. Sử dụng: inverse_of để đảm bảo đối tượng cha của bạn được liên kết khi lưu trong các trường lồng nhau. https://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations – hellion

15

Xem here cho câu trả lời dứt khoát:

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 

Không phải như vậy tao nhã nếu bạn hỏi tôi ... Nó minh bạch nên xác nhận.

+0

cảm ơn tôi sẽ xem xét "inverse_of" – deb

2

Tôi nghĩ bạn đang gặp vấn đề tương tự mà tôi đã giải quyết. Tôi có hai mô hình, Tài khoản và Người dùng và khi tài khoản được tạo, người dùng đầu tiên được tạo thông qua một số @account.users.build. Mô hình Người dùng có xác thực validates_presence_of :account.

Để thực hiện đầu tiên xác nhận người sử dụng vượt qua, tôi đã thêm đoạn mã sau vào mô hình Tài khoản của tôi:

before_validation_on_create :initialize_users 

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

Trong thực tế bạn cần cả hai:

validates_presence_of project 
validates_presence_of project_id 

Bằng cách đó nhiệm vụ sẽ không được lưu trong một trong các trường hợp sau giả định rằng bạn chỉ có 2 dự án hợp lệ trong cơ sở dữ liệu, tức là dự án id 99 không hợp lệ:

task.project_id = 99 
task.save 

task.project = Project.new 
task.save 

Tôi hy vọng điều này là giúp đỡ cho một ai đó.

Các vấn đề liên quan