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

时间:2015-04-18 15:03:03

标签: ruby-on-rails-3 activerecord

这很难找到相关信息。这一切的关键是我有一个Rails 3.2应用程序,它使用POINT类型的列访问MySQL数据库表。没有非本机代码,rails不知道如何解释这个,这很好,因为我只在内部数据库查询中使用它。

然而,问题是它被转换为整数,并且如果为空则强制为null。 MySQL不允许对该字段使用null,因为它上面有索引,并且整数无效,所以这实际上意味着我无法通过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(...)'放入它创建的insert语句中,但我不知道该怎么做。

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

1 个答案:

答案 0 :(得分:0)

好的,我最终使用steve klein评论中的第一个链接来插入原始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

不漂亮,但有效。