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

How to insert custom value after validation in rails model

提问人:kael 提问时间:4/18/2015 更新时间:4/20/2015 访问量:684

问:

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

然而,问题在于它被强制转换为整数,如果为空,则强制为 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 语句中,但我不知道该怎么做。

等待无所不知的社区的想法和意见......

Ruby-on-Rails-3 活动记录

评论

0赞 steve klein 4/19/2015
你有没有看过用于原始插入的 stackoverflow.com/questions/12716797/ 和用于处理地理空间的 stackoverflow.com/questions/4995428/?

答:

0赞 kael 4/20/2015 #1

好的,我最终使用了 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

不漂亮,但有效。