Rails 3: validates_presence_of ошибки проверки для значения по умолчанию и в связанной модели

У меня есть базовая настройка счета с моделями: Invoice, Item, LineItems.

# invoice.rb
class Invoice < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
  validates_presence_of :status

  before_save :default_values

  def default_values
    self.status = 'sent' unless self.status
  end
end

# item.rb
class Item < ActiveRecord::Base
  has_many :line_items
  validates_presence_of :name, :price
end

# line_item.rb
class LineItem < ActiveRecord::Base
  belongs_to :item
  belongs_to :invoice 
  before_save :default_values

  validates_presence_of :invoice_id
  validates :item_id, :presence => true
end

В модели есть еще кое-что, но я представил это только для простоты.

Я получаю следующие ошибки:

2 errors prohibited this invoice from being saved:
  Line items invoice can't be blank
  Status can't be blank

Итак две проблемы:

  1. Если я удалю validates :invoice_id, :presence => true, я больше не буду получать сообщение об ошибке Line items invoice can't be blank, но почему? Я хочу проверить invoice_id на line_items, ВСЕ line_items должны иметь invoice_id. Как я могу проверить invoice_id на line_items без получения ошибки?

  2. Почему я получаю сообщение об ошибке Status can't be blank, если я установил его как значение по умолчанию? Я, вероятно, могу настроить его на invoices_controller, но я думаю, что значение по умолчанию должно быть установлено в модели, верно? Как я могу проверить наличие статуса и по-прежнему иметь для него значение по умолчанию в модели?


person leonel    schedule 26.06.2012    source источник


Ответы (3)


Обе эти ошибки проверки возникают из-за того, что проверки вызываются перед сохранением (и до обратного вызова before_save).

Я предполагаю, что вы используете вложенную_форму для одновременного создания счета и его позиций. Если это так, вам не нужно validates :invoice_id, :presence => true для позиций — счет-фактура и позиции поступают одновременно, а счет-фактура еще не сохранен, поэтому у него нет идентификатора. . Если вы оставите проверку, вам нужно будет сначала создать и сохранить пустой счет-фактуру, а затем создать позиции, чтобы был доступен invoice_id. Если вы хотите убедиться, что invoice_id по-прежнему установлен после каких-либо изменений, вы можете применить это с помощью validates :invoice_id, :presence => true, :on => :update, это пропустит проверку при создании позиции (а invoice_id еще недоступен).

Вы сталкиваетесь с проблемами с validates :status, :presence => true по тем же причинам - значения, поступающие через запрос, проверяются, а значение «статус» отсутствует. Обратный вызов before_save запускается после проверки. Вы можете установить значение по умолчанию в обратном вызове before_validation или after_initialization, и значения будут там при выполнении проверок.

Дополнительные сведения см. в документации по обратным вызовам для Rails.

person Nate    schedule 26.06.2012

Начну с 2: перед сохранением выполняется только перед сохранением, то есть после того, как объект прошел проверку и вот-вот будет сохранен. Если проверка не пройдена - она ​​не будет выполнена.

что касается 1: Можете ли вы привести пример того, как вы пытаетесь создать счет?

person Amir    schedule 26.06.2012

Проблема 1

Попробуйте validates_associated, который проверяет, что связанные модели все действительны

Проблема 2

Как и в большинстве ответов, говорится, что before_save вызывается после проверки. Вам нужна магия after_initialize, которая запускается после вызова метода initialize объекта.

class Invoice < ActiveRecord::Base
  after_initialize :default_values
  validates :status, presence: true

private

  def default_values
    self.status ||= 'sent'
  end
end
person Dean Brundage    schedule 26.06.2012