Невозможно вернуть ошибки, созданные на модели

Я использую gem Responders, но я не могу показать ошибки, которые я создаю на своих моделях, используя erros.add(:base, 'Error message'),

На моем контроллере, перед respond_with @appОтладил @app объект и есть ошибки @app.errors.any? возвращается true

На мой взгляд, когда я проверяю flash а также @app объекты, ни один не имеет ошибки

Контроллер приложений

# app_controllers.rb
def destroy
  @app = current_company.apps.find(params[:id])
  @app.destroy
  respond_with @app
end

Модель приложения

# app.rb

before_destroy :destroy_on_riak

# ...

def destroy_on_riak
  # SOME CODE HERE
rescue Exception => e
  errors.add(:base, I18n.t("models.app.could_not_destroy", :message => e.message))
  return false
end

Вид приложения

# apps.html.haml
-flash.each do |name, msg|
  %div{:class => "flash #{name}"}
    =content_tag :p, msg if msg.is_a?(String)

Это объект @app перед @app.destroy

"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={}>"

Это объект @app после @app.destroy

"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={:base=>[\"Não foi possível excluir a aplicação: undefined method `get_or_new' for #<App:0x00000004f824c0>\"]}>"

Я удалил то, что внутри @base= для простоты.

4 ответа

Jefflunt правильно, когда один звонит #valid? очищает массив ошибок: см. https://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activemodel/lib/active_model/validations.rb#L333

Валидаторы на 100% определяют валидность вашего объекта, а не когда вы сами добавляете ошибки для дальнейшего использования.

Пока ActiveRecord переопределяет #valid?все еще звонит super: https://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activerecord/lib/active_record/validations.rb#L58

Если вы хотите добавить ошибки и сохранить их, я рекомендую что-то вроде этого:

def failures
  @failures ||= []
end

validate :copy_failures_to_errors

def copy_failures_to_errors
  @failures.each { |f| errors.add(*f) }
end

Затем измените ваш rescue:

def destroy_on_riak
  # SOME CODE HERE
rescue Exception => e
  failures.push([:base, I18n.t("models.app.could_not_destroy", :message => e.message)])
  return false
end

Я знаю, что это кажется запутанным, и я знаю, что есть даже примеры онлайн, где люди используют или рекомендуют errors.add(:base, ...), но это не безопасный способ хранить и извлекать ошибки на потом.


Кроме того, просто рекомендация, но я советую вам спасти StandardError и не Exception если вы абсолютно не должны. Ошибки памяти и тому подобное Exceptions, но каждая нормальная ошибка, которую вы когда-либо хотели бы спасти, должна наследоваться от StandardError, Просто к вашему сведению.

Я дам вам несколько советов:

Подсказка 1

Ваша форма может звонить valid? на @app объект. valid? метод очищает errors массив на экземпляре.

Неправильно использовать errors массив / конструкция вне контекста валидации. Но это МХО.

Подсказка 2

Согласно гему Responders (который я никогда не использовал в прошлом), ваша локаль должна иметь правильную конфигурацию. Пример:

flash:
  actions:
    create:
      notice: "{resource_name} was successfully created"
    update:
      notice: "{resource_name} was successfully updated"
    destroy:
      notice: "{resource_name} was successfully destroyed"
      alert: "{resource_name} could not be destroyed"

Является ли?

Тайна, кажется, заключается либо в том, что (а) вы не вызываете правильный метод, либо (б) .errors хеш не содержит того, что вы думаете, что он содержит.

Неправильный метод?

В вашем контроллере вы звоните @app.destroy, но метод, который добавляет ошибки называется destroy_on_riak

Вы уверены, что не хотите печатать это?

# app_controllers.rb
def destroy
  @app = current_company.apps.find(params[:id])
  @app.destroy_on_riak    # <= The offending line?
  respond_with @app
end

Или есть before_destroy обратный вызов отсутствует в вашем примере кода, который в свою очередь вызывает destroy_on_riak? Из включенного кода я нигде не вижу, чтобы destroy_on_riak метод когда-либо вызывается, так что это всего лишь предположение.

Неожиданное содержание .errors хэш?

Если это не проблема, то когда @app.errors.any? возвращается trueзатем в этой точке кода выведите содержимое @app.errors в ваш журнал, чтобы вы могли видеть, что не так.

Я должен согласиться с @p.mastinopoulos по этому вопросу. Это действительно должно быть обработано с помощью встроенных проверок. Похоже, вам нужно создать собственный валидатор.

http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html

Попробуйте заменить ваш before_destroy с validate:

validate :destroy_on_riak, on: :destroy

Еще не пробовал, но если это не сработает, вы можете рассмотреть возможность создания собственного валидатора, на который есть ссылки в документации.

Другие вопросы по тегам