rails validate 做在 ActiveRecord::Base


#1

我搞定了抓出db schema null 設成 false 的欄位(null_false_columns= [“id”,“name”])
下一步找不到方法丟入 validates_presence_of 內
想偷懶不要每個model 加入validate
我搞錯了什麼嗎?

class ActiveRecord::Base
validates_presence_of *self.null_false_columns

def null_false_columns
columns_of_obj = self.class.connection.columns self.class.table_name
columns = columns_of_obj.map do |i|
i.name if i.null!=true
end.compact
end


#3

class CreateEmployees < ActiveRecord::Migration
def up
create_table :employees do |t|
t.integer :ou_id,null: false
t.string :uid,null: false
t.string :name,null: false
t.integer :arrive_date,null: false,default: 99991231
t.integer :leave_date,null: false, default: 99991231
t.string :id_number,null: false
t.integer :department_id

  t.timestamps
end
add_index :employees,[:ou_id,:uid],unique: true 

end
def down
drop_table :employees
end

class Employee < ActiveRecord::Base
validates_presence_of :ou_id, :uid, :name, :arrive_date, :leave_date, :id_number
end

以上是可以執行的migrate 及model
我目前的想法是,migrate 都設定了欄位是否為null了
那我可以從db 撈出 :ou_id, :uid, :name, :arrive_date, :leave_date, :id_number 不可為null的欄位
直接把validate 做在ActiveRecord::Base 內
那以後的model 預設都有基本的validate 不用特別寫
我現在最大的問題是,我撈出來的東西,怎麼丟回 validate 後面


#4

我後來終於看懂你在做啥了 … 你覆蓋別人家的父代做啥 Orz" …

validates_presence_of()

https://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_presence_of

這種做法是宣告時並且呼叫,所以你是針對 ActiveRecord::Base 去呼叫這方法
而 validate 類似 before / after 系列都是一個 stack,該 stack 應該不會被繼承才是(因為是個變數 … )
所以你這樣搞應該沒辦法完成才是 Orz"

包括 include / extend 應該都無法這樣完成,因執行那個 methods 的同時是在塞一個變數而非定義些啥鬼
Orz" 這算是 Ruby 好用的原罪唄,玩的人不知道在做啥之類的,間單的來說我寫個類似的 code 給你參考

class Parent
  def self.reg_action(sym)
    @@action ||= {}
    @@action[self] ||= []
    @@action[self] << sym
    
    puts "reg : #{self} : #{sym}"
  end
  def save
    @@action ||= {}
    @@action[self.class] ||= []
    @@action[self.class].each do |sym|
      puts "save call #{self.class} : #{sym}"
    end
  end
end

class Item < Parent
  reg_action :hihi
  reg_action(:hoho)
end
#宣告時執行兩次reg

class Product < Parent
  reg_action :yooo
  reg_action(:nono)
end
#宣告時執行兩次reg too

Item.new.save
Product.new.save
#使用 reg 項目

所以概念如果像是這個,你根本沒機會覆蓋不是?我會建議你用 initialize 的方式完成唄?類似…

[Item , Product].each do |klass|
  #maybe 在這把 column 找出來
  klass.reg_action(:kooo) #塞入註冊
end

你會得到相同的效果才是,but 這邊有趣的一直都是…你一開始就會浪費很多連線在檢查 column 是否可為 nil 這件事情上面?,且我預估你會遇到些奇怪的問題就是了|||


#5

因為我想偷懶,不想寫null: false 的 validate


#6

我知道你想偷懶且我知道你想做啥,不過當有人 SQL injection 成功你的 DB 且修改你的 table 可接受 null 時,同時你的 Rails 的檢查就失效了哩 … 雖然這有點困難達成,我想形容的是你的 Rails 核心不應該依照另外一個東西來建立他的過濾規則,就類似 RDBMS 不應該參照你的 Rails code 才知道是否可吃 null 是一樣的意思

這一直都是雙重保護,而非二擇一的項目就是,且有例外時反而會造成你自己的困擾唄