如何防止Ruby on Rails Active记录从数据库中获取默认模型值?

时间:2014-11-21 13:20:15

标签: ruby-on-rails ruby rails-activerecord firebird

我正在开发一个RoR应用程序,Firebird及其SQL引擎,但我不明白为什么ActiveRecord(AR)不断查询数据库的默认值!

这是表DDL:

CREATE TABLE GLOBAL_SETTINGS
(
  SKEY varchar(64) NOT NULL,
  SVALUE varchar(256) NOT NULL,
  OBS blob sub_type 1,
  IS_SYSTEM "BOOLEAN" DEFAULT 1 NOT NULL,
  CREATED_AT timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
  UPDATED_AT timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
  CONSTRAINT PK_GLOBAL_SETTINGS_SKEY PRIMARY KEY (SKEY)
);

以下是创建此表的迁移:(create_global_settings.rb

class CreateGlobalSettings < ActiveRecord::Migration
  def up
    create_table :global_settings, :id => false do |t|
      t.string :skey, :null => false, :limit => 64
      t.string :svalue, :null  => false, :limit => 256
      t.text :obs
      t.boolean :is_system, :null  => false, :default => true
      t.timestamps :null  => false
    end

    # defaults on timestamp columns
    execute("alter table GLOBAL_SETTINGS alter column CREATED_AT set default     CURRENT_TIMESTAMP;")
    execute("alter table GLOBAL_SETTINGS alter column UPDATED_AT set default     CURRENT_TIMESTAMP;")    

    # our custom PK naming
    execute("alter table GLOBAL_SETTINGS add constraint PK_GLOBAL_SETTINGS_SKEY primary     key (SKEY)")    
  end

  def down
    drop_table :global_settings
  end
end

这是我的模型:( global_Settings.rb

class GlobalSettings < ActiveRecord::Base
  #model validations!
  validates :skey, presence: true
  validates :skey, uniqueness: { case_sensitive: false, message: 'Global setting key     allready exists!'}

  validates :svalue, presence: true        
end

没有定义任何视图或测试或帮助器!

如果我这样做在rails控制台中:

gs = GlobalSettings.new(skey: 'testKey', svalue: 'testValue')
D, [2014-11-21T13:11:18.547669 #7215] DEBUG -- :    (192.2ms)  SELECT CAST(1 AS SMALLINT)   FROM RDB$DATABASE
D, [2014-11-21T13:11:18.564272 #7215] DEBUG -- :    (16.3ms)  SELECT CAST(CURRENT_TIMESTAMP   AS TIMESTAMP) FROM RDB$DATABASE
D, [2014-11-21T13:11:18.580900 #7215] DEBUG -- :    (16.4ms)  SELECT CAST(CURRENT_TIMESTAMP AS TIMESTAMP) FROM RDB$DATABASE
#<GlobalSettings skey: "testKey", svalue: "testValue", obs: nil, is_system: true,   created_at: nil, updated_at: nil>
gs.save
D, [2014-11-21T13:11:24.403986 #7215] DEBUG -- :   GlobalSettings Exists (13.2ms)  SELECT    1 AS one FROM "GLOBAL_SETTINGS"  WHERE LOWER("GLOBAL_SETTINGS"."SKEY") = LOWER(?) ROWS 1,   testKey
D, [2014-11-21T13:11:24.543674 #7215] DEBUG -- :   SQL (89.4ms)  INSERT INTO   "GLOBAL_SETTINGS" ("CREATED_AT", "SKEY", "SVALUE", "UPDATED_AT") VALUES (?, ?, ?, ?), 2014-  11-21 13:11:24, testKey, testValue, 2014-11-21 13:11:24
true

正如您所看到的,AR似乎正在尝试获取我的模型/表的默认值,在这种情况下,这是不需要的,因为它要查询数据库3次,而且它应该只是在做插入,并让SQL引擎处理其余的事情。 我如何防止这种情况发生?

有没有办法阻止AR获取列的默认值?

另一个问题,在GlobalSetting模型的新方法中,我只使用列sKey:sValue:,为什么活动记录会将所有其他列放入插入?

1 个答案:

答案 0 :(得分:0)

AFAIK:new只创建一个模型对象,它接受一个哈希作为一个参数,其中键是你的表属性。它此时不会查询数据库。一旦调用save方法,它首先调用有效?检查对象是否通过了已定义的验证的方法。除了您在此处定义的唯一性验证外,它独立于数据库模式。唯一性验证查询数据库以检查此类值是否已存在。一旦您的对象通过了所有验证,它就会调用查询将数据插入到您的数据库中。如果数据违反了数据库级别的某些条件,则会引发异常。因此,当查询在数据库级别运行时,您无法从rails控制它。如果数据库中有默认值,则会分配它们。绕过它们的唯一方法是将一些其他值显式传递给相应的属性。 并且根据t.timestamps的行为,是的,每当您在创建新记录时修改该记录和created_at列时,rails将自动更新updated_at列。