22

我有一个包含许多任务的项目资源。project_id我想通过添加validates_presence_of :project_id到任务模型来确保每个任务都有一个。

但是,在创建带有任务的新项目时,在记录保存之前 project_id 将不可用,因此我无法使用validates_presence_of :project_id.

所以我的问题是,如何验证任务模型中是否存在 project_id?我想确保每个任务都有一个父级。

...

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
4

7 回答 7

18

您的代码有效:

  • 如果你 validates_presence_of :project,那么只要项目在那里,它就会验证。但如果您的项目未保存,您仍然可以保存任务。
  • 如果您 validates_presence_of :project_id,则整数必须存在,表示已保存的值。

这是证明这一点的rSpec。如果您验证 :project_id,则无法在不保存项目的情况下保存任务。

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
于 2010-06-10T19:57:20.540 回答
15

请参阅此处以获得明确的答案:

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

如果你问我不是那么优雅......它应该透明地验证。

于 2010-08-19T11:40:15.410 回答
3

也许我不明白什么,但看起来你正在试图欺骗 Rails。你为什么不这样做:

class Task < ActiveRecord::Base
  belongs_to :project
  validate_presence_of :project
end
于 2010-06-09T22:20:25.210 回答
2

看看这个:

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

我过去做过的一件事是添加:validates_presence_of :parent_id, :on => :update. 不是很好,但它有助于收紧网络。

于 2010-06-10T08:24:18.680 回答
2

我想你和我处理的问题一样。我有两个模型,帐户和用户,当创建帐户时,第一个用户是通过@account.users.build. User 模型有一个validates_presence_of :account验证。

为了让第一个用户通过验证,我在我的 Account 模型中添加了以下代码:

  before_validation_on_create :initialize_users

  def initialize_users
    users.each { |u| u.account = self }
  end
于 2010-12-06T22:30:27.113 回答
1

实际上,您需要两者:

validates_presence_of project
validates_presence_of project_id

这样,假设您在数据库中只有 2 个有效项目,即项目 id 99 无效,则在以下任何一种情况下都不会保存任务:

task.project_id = 99
task.save

task.project = Project.new
task.save

我希望这对某人有帮助。

于 2014-01-20T08:12:18.380 回答
0

您的Project班级必须定义

accepts_nested_attributes_for :tasks

有关如何制作表单的更多详细信息,请参阅Railscasts 上的嵌套模型表单。


编辑:

在你的表格中,你应该有这样的东西:

_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_fields并且link_to_remove_fields是在 application_helper 中定义的用于动态添加/删除字段的方法。

于 2010-05-18T19:12:16.173 回答