如何在 rails 模型中验证后插入自定义值

How to insert custom value after validation in rails model

这方面的资料实在是太难找了。这一切的症结在于我有一个 Rails 3.2 应用程序可以访问 MySQL 数据库 table,其中有一列类型为 POINT。没有非本地代码,rails 不知道如何解释这个,这很好,因为我只在内部数据库查询中使用它。

然而,问题是它被强制转换为整数,如果为空则强制为 null。 MySQL 不允许此字段为空,因为它上面有一个索引,并且整数是无效的,所以这实际上意味着我无法通过 rails.

创建新记录

我一直在寻找一种在插入数据库之前更改值的方法,但我的 rails 灯还不够亮,无法将其关闭。到目前为止,我已经尝试了以下方法:

...
after_validation :set_geopoint_blank
def set_geopoint_blank
  raw_write_attribute(:geopoint, '') if geopoint.blank?
  #this results in NULL value in INSERT statement
end

---------------------------

#thing_controller.rb
...
def create
  @thing = Thing.new
  @thing.geopoint = 'GeomFromText("POINT(' + lat + ' ' + lng + ')")'
  @thing.save
  # This also results in NULL and an error
end

---------------------------

#thing_controller.rb
...
def create
  @thing = Thing.new
  @thing.geopoint = '1'
  @thing.save
  # This results in `1` being inserted, but fails because that's invalid spatial data.
end

对我来说,理想的情况是能够强制 rails 将字符串 'GeomFromText(...)' 放入它创建的插入语句中,但我不知道该怎么做。

等待全知社区的想法和意见....

好的,我最终使用了 steve klein 评论中的第一个 link 来插入原始 sql。这是我的代码最后的样子:

def create
  # Create a Thing instance and assign it the POSTed values
  @thing = Thing.new
  @thing.assign_attributes(params[:thing], :as => :admin)

  # Check to see if all the passed values are valid
  if @thing.valid?
    # If so, start a DB transaction
    ActiveRecord::Base.transaction do
      # Insert the minimum data, plus the geopoint
      sql = 'INSERT INTO `things`
             (`thing_name`,`thing_location`,`geopoint`)
             values (
                "tmp_insert",
                "tmp_location",
                GeomFromText("POINT(' + params[:thing][:lat].to_f.to_s + ' ' + params[:thing][:lng].to_f.to_s + ')")
             )'
      id = ActiveRecord::Base.connection.insert(sql)

      # Then load in the newly-created Thing instance and update it's values with the passed values
      @real_thing = Thing.find(id)
      @real_thing.update_attributes(b, :as => :admin)
    end

    # Notify the user of success
    flash[:message] = { :header => 'Thing successfully created!' }
    redirect_to edit_admin_thing_path(@real_thing)
  else
    # If passed values not valid, alert and re-render form
    flash[:error] = { :header => 'Oops! You\'ve got some errors:', :body => @thing.errors.full_messages.join("</p><p>").html_safe }
    render 'admin/things/new'
  end 
end

不漂亮,但很管用。