Rails:验证 has_many 关联中是否存在parent_id

发布于 2024-09-02 07:50:53 字数 596 浏览 1 评论 0原文

我有一个包含许多任务的项目资源。我想通过将 validates_presence_of :project_id 添加到任务模型来确保每个任务都有一个 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

I have a projects resource that has many tasks. I want to ensure that every task has a project_id by adding validates_presence_of :project_id to the tasks model.

However, when creating a new project with tasks, the project_id won't be available until the record saves, therefore I can't use validates_presence_of :project_id.

So my question is, how do I validate presence of project_id in the task model? I want to ensure every task has a parent.

...

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

瑾兮 2024-09-09 07:50:53

您的代码有效:

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

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

class Task < ActiveRecord::Base
  belongs_to :project
end

/规格/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

Your code works:

  • If you validates_presence_of :project, then as long as the project is there, it will validate. But if your project is unsaved, you could still save the task.
  • If you validates_presence_of :project_id, then the integer must be there, indicating a saved value.

Here's rSpec that proves the point. If you validate :project_id, you can't save a task without saving the Project.

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
丢了幸福的猪 2024-09-09 07:50:53

请参阅 这里给出了明确的答案:

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

如果你问我的话,就不那么优雅了......它应该透明地验证。

See here for the definitive answer :

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

Not so elegant if you ask me... It should transparently validate.

多像笑话 2024-09-09 07:50:53

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

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

Maybe I don't understand something, but it looks like you are trying to cheat rails. Why don't you just do like this:

class Task < ActiveRecord::Base
  belongs_to :project
  validate_presence_of :project
end
懵少女 2024-09-09 07:50:53

看看这个:

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

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

Take a look at this:

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

One thing I have done in the past is add: validates_presence_of :parent_id, :on => :update. Not great but it helps tighten the net a little.

温柔女人霸气范 2024-09-09 07:50:53

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

为了使第一个用户通过验证,我将以下代码添加到我的帐户模型中:

  before_validation_on_create :initialize_users

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

I think you're having the same issue I dealt with. I have two models, Account and User, and when the account is created the first user is created through a @account.users.build. The User model has a validates_presence_of :account validation.

To make the first user pass validation, I added the following code to my Account model:

  before_validation_on_create :initialize_users

  def initialize_users
    users.each { |u| u.account = self }
  end
你在看孤独的风景 2024-09-09 07:50:53

实际上,您两者都需要:

validates_presence_of project
validates_presence_of project_id

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

task.project_id = 99
task.save

task.project = Project.new
task.save

我希望这对某人有帮助。

In reality you need both:

validates_presence_of project
validates_presence_of project_id

That way the task will not be saved in either of the following cases assuming that you have only 2 valid projects in the database, i.e. project id 99 is invalid:

task.project_id = 99
task.save

task.project = Project.new
task.save

I hope this is of help to someone.

橘味果▽酱 2024-09-09 07:50:53

您的 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_fieldslink_to_remove_fields< /code> 是 application_helper 中定义的用于动态添加/删除字段的方法。

Your Project class must define

accepts_nested_attributes_for :tasks

See Nested Model Form on Railscasts for more details on how to make the form.


EDIT:

In your form you should have something like this:

_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 and link_to_remove_fields are methods defined in application_helper to add/delete fields dynamically.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文