Rails: проверка наличия parent_id в ассоциации has_many - PullRequest
21 голосов
/ 18 мая 2010

У меня есть проектный ресурс, у которого много задач. Я хочу убедиться, что у каждой задачи есть project_id, добавив validates_presence_of :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

Ответы [ 7 ]

17 голосов
/ 10 июня 2010

Ваш код работает:

  • Если вы проверяете_presence_of: project, то, пока проект существует, он будет проверяться.Но если ваш проект не сохранен, вы все равно можете сохранить задачу.
  • Если вы проверяете_presence_of: project_id, тогда должно быть целое число, указывающее сохраненное значение.доказывает суть.Если вы подтвердите: 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
    
15 голосов
/ 19 августа 2010

См. здесь для окончательного ответа:

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

Не так элегантно, если вы спросите меня ... Это должно прозрачно подтвердить.

3 голосов
/ 10 июня 2010

Может быть, я чего-то не понимаю, но похоже, что вы пытаетесь обмануть рельсы.Почему бы тебе просто так не сделать:

class Task < ActiveRecord::Base
  belongs_to :project
  validate_presence_of :project
end
2 голосов
/ 07 декабря 2010

Я думаю, у вас та же проблема, с которой я столкнулся. У меня есть две модели, Учетная запись и Пользователь, и при создании учетной записи первый пользователь создается с помощью @account.users.build. Модель User имеет проверку validates_presence_of :account.

Чтобы первый пользователь прошел проверку, я добавил следующий код в модель своей учетной записи:

  before_validation_on_create :initialize_users

  def initialize_users
    users.each { |u| u.account = self }
  end
2 голосов
/ 10 июня 2010

Взгляните на это:

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

Одна вещь, которую я сделал в прошлом, это добавление: validates_presence_of :parent_id, :on => :update. Не очень, но это помогает немного затянуть сеть.

1 голос
/ 20 января 2014

На самом деле вам нужны оба:

validates_presence_of project
validates_presence_of project_id

Таким образом, задача не будет сохранена ни в одном из следующих случаев, при условии, что у вас есть только 2 допустимых проекта в базе данных, т.е. идентификатор проекта 99 недействителен:

task.project_id = 99
task.save

task.project = Project.new
task.save

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 18 мая 2010

Ваш Project класс должен определить

accepts_nested_attributes_for :tasks

См. Форма вложенной модели на Railscasts для получения более подробной информации о том, как сделать форму.


EDIT:

В вашей форме должно быть что-то вроде этого:

_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 для динамического добавления / удаления полей.

...