如何捕获/解决ActiveRecord:保存构建的关联时导致的RecordInvalid异常

时间:2011-03-24 16:46:54

标签: ruby-on-rails ruby-on-rails-3 associations google-geocoder

我希望得到一些帮助来解决一个问题,我相信很多人在睡梦中可以避免这些问题。

我有两个关系模式。一个包可以有很多位置,一个位置可以有很多包。如果我的位置模型验证失败(例如,由于位置地址为空),我会得到anActiveRecord: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 个答案:

答案 0 :(得分:12)

所选答案不准确。根据文档here,有一个简单的方法来捕获救援这个例外:

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

您可以访问错误的消息实例变量,并获取相关的字段和错误消息。

答案 1 :(得分:2)

我的头脑中有几个想法:

使用@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工作......

希望有所帮助!

答案 2 :(得分:0)

这是我用来解决问题的代码,同时向用户提供有关保存失败原因的良好反馈。请原谅我不雅的红宝石代码。

仍然存在一个小问题。 。 。如果包和位置都验证失败,则重新加载时仅显示位置错误消息。如果用户然后更正位置错误但不纠正包错误,则会显示包错误消息。我正在研究如何在第一次重新加载时显示所有错误

  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