Как перехватить / устранить исключение ActiveRecord: RecordInvalid, вызванное сохранением встроенной ассоциации - PullRequest
4 голосов
/ 24 марта 2011

Я надеюсь получить помощь в решении проблемы, которую, я уверен, многие из вас могли бы избежать во сне.

У меня есть две модели отношений habtm. Пакет может иметь много местоположений, и местоположение может иметь много пакетов. Если моя модель местоположения не проходит проверку (например, из-за пустого адреса местоположения), я получаю исключение anctive Active: RecordInvalid. Я понимаю, что получаю эту ошибку, потому что когда я вызываю package.save, rails автоматически вызывает save! на месте ассоциации.

Я не уверен, как избежать ошибки или хотя бы спасти ошибку. Есть ли у кого-нибудь из вас полезные советы, как решить проблему, так и лучшие практики Rails?

Вот код: '

def create
    @pacakge = current_user.package.build(params[:package])
    package_location
    if @package.save
      flash[:success] = "Package created!"
      redirect_to root_path
    else        
      render 'pages/home'
    end
  end

  def package_location
    gps_processing if !session[:gps_aware]
    @package.locations.build(:address => session[:address])
  end

  def gps_processing
    session[:address] = [params[:story][:street_address], params[:story][:city], params[:story][:state], params[:story][:country]].compact.join(', ')
  end

class Package< ActiveRecord::Base

  belongs_to :user
  has_and_belongs_to_many :locations

  validates         :content,   :presence   => true, 
                    :length     => {:maximum => 140}
  validates      :user_id,    :presence => true

  default_scope :order => 'package.created_at DESC'

end

class Location < ActiveRecord::Base

  attr_accessible :lng, :lat, :address

  validates     :lng,       :presence   => true
  validates     :lat,       :presence   => true
  validates     :address,   :presence   => true

  geocoded_by :full_street_address, :latitude => :lat, :longitude => :lng  

  before_validation :geocode

  has_and_belongs_to_many :packages

  def full_street_address
    address
  end
end

` Заранее спасибо за помощь!

Ответы [ 3 ]

13 голосов
/ 12 октября 2014

Выбранный ответ не является точным.В соответствии с документацией здесь существует простой способ поймать спасение этого исключения:

begin
  complex_operation_that_calls_save!_internally
rescue ActiveRecord::RecordInvalid => invalid
  puts invalid.record.errors
end

Вы можете получить доступ к переменной экземпляра сообщения об ошибках и получить связанное поле и сообщение об ошибке.

2 голосов
/ 25 марта 2011

Парочка идей из головы:

Использование @package.save! и спасательный блок:

def create
  @package = current_user.package.build(params[:package])
  package_location
  @package.save!
  flash[:success] = "Package created!"
  redirect_to root_path
rescue      
  render 'pages/home'
end

Использование validates_associated в вашей модели пакета,и сохраняйте, только если он действителен:

def create
  @package = current_user.package.build(params[:package])
  package_location

  # You might be able to just use if(@package.save), but I'm not positive.
  if(@package.valid?)
    @package.save!
    flash[:success] = "Package created!"
    redirect_to root_path
  else      
    render 'pages/home'
  end
end

И я уверен, что есть еще несколько способов, как вы работаете в Ruby ...

Надеюсь, это поможет!

0 голосов
/ 27 марта 2011

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

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

  def create
    @package= current_user.package.build(params[:package])
    if package_location && @package.save
        flash[:success] = "Package created!"
        redirect_to root_path
      else
        render 'pages/home'
    end
  end

 def package_location
   gps_processing if !session[:gps_aware]
   location = @package.locations.build(:address => session[:address])
   if !location.valid?
     @package.errors.add(:address, "You have entered an invalid address") 
     return false
   else
      return true
   end
 end

 def gps_processing
   session[:address] = [params[:story][:street_address], params[:story][:city], 
          params[:story][:state], params[:story][:country]].compact.join(', ')
 end
...