2012-04-18 59 views
5

我有一個用戶模型與利潤字段。 Profit字段是DECIMAL(11,0)類型。我在表單上有一個蒙面輸入,允許用戶輸入類似$ 1,000的東西。我想格式化該值並刪除除了數字之外的所有內容,所以我將保存1000個。這是我到目前爲止:如何格式化值之前保存到數據庫在rails 3

class User < ActiveRecord::Base 
    before_save :format_values 

    private 

    def format_values 
    self.profit.to_s.delete!('^0-9') unless self.profit.nil? 
    end 
end 

但它保持0在數據庫中。看起來它將我的格式化函數轉換爲小數。

回答

7

試試這個:

def profit=(new_profit) 
    self[:profit] = new_profit.gsub(/[^0-9]/, '') 
end 
+1

/[^ 0-9] /與/ \ D/ – makaroni4 2012-04-18 17:57:07

+1

相同它只是模仿作者的RegExp。試着不要嚇到他) – jdoe 2012-04-18 17:59:59

+0

謝謝@jdoe我用你的建議,它的工作原理就像我想要的。 – 2012-04-18 23:26:02

0
def format_values 
    self.profit.to_d! 
    end 
0

我建議你寫的這個特定的實例變量@profit定製的setter:

class User 
    attr_accessor :profit 

    def profit= value  
    @profit = value.gsub(/\D/,'') 
    end 
end 

u = User.new 
u.profit = "$1,000" 
p u.profit # => "1000" 
+1

我想'u.profit'返回實例變量的值。這是你製造的一個陷阱! – jdoe 2012-04-18 18:02:50

+0

你是什麼意思? attr_accessor定義了兩個方法 - getter和setter,profit方法返回實例變量的值,這是正確的)哪裏有陷阱?) – makaroni4 2012-04-19 21:53:20

+1

你的'User'與'ActiveRecord :: Base'無關。如果它有事件,@ pofit變量與'profit'DB屬性無關。從'ActiveRecord :: Base'繼承你的'User'版本後,你應該用'self.profit ='替換'@profit ='。否則,你會掩蓋「利潤」屬性。 – jdoe 2012-04-20 05:33:47

0

我會建議使用一些精密導軌幫手。以下是一些代碼。

一般示例:

number_with_precision(111.2345, :precision => 1, :significant => true)  # => 100 

Rails代碼實例:

def profit=(new_profit) 
    number_with_precision(self[:profit], :precision => 1, :significant => true) 
end 
0
class User < ActiveRecord::Base 
    before_save :format_values 

    private 

    def format_values 
    self.profit = profit.to_s.gsub(/\D/,'') if profit 
    end 
end 
6

首先,這樣的:

def format_values 
    self.profit.to_s.delete!('^0-9') unless self.profit.nil? 
end 

是幾乎相同的,因爲這:

def format_values 
    return if(self.profit.nil?) 
    p = self.profit 
    s = p.to_s 
    s.delete!('^0-9') 
end 

所以沒有理由期待您的format_values方法產生任何影響任何在self.profit

你當然可以改變format_values到處理字符串分配給self.profit但不會幫助,因爲你的清理邏輯是在錯誤的地方,它會'$1,000'已經變成零後執行

當你給一個屬性賦值時,ActiveRecord會沿途應用一些類型轉換。當您嘗試將'$1,000'轉換爲數字時會發生什麼?當然你會得到零。如果您在控制檯中打轉轉,你可以看這種情況的發生:

> a = M.find(id) 
> puts a.some_number 
11 
> a.some_number = 'pancakes' 
=> "pancakes" 
> puts a.some_number 
0 
> a.some_number = '$1,000' 
=> "1,000" 
> puts a.some_number 
0 
> a.some_number = '1000' 
=> "1000" 
> puts a.some_number 
1000 

所以,你的數據清除必須發生之前的數據進入模型的實例,因爲一旦AR獲取其手中的價值,您的'$1,000'將變爲0,全部丟失。我會將邏輯放在控制器中,控制器的工作是在外部世界與模型和數據格式化之間進行調解,並且調整當然也算作調解。所以,你可以在你的控制器是這樣的:

def some_controller 
    fix_numbers_in(:profit) 
    # assign from params as usual... 
end 

private 

def fix_numbers_in(*which) 
    which.select { |p| params.has_key?(p) }.each do |p| 
     params[p] = params[p].gsub(/\D/, '') # Or whatever works for you 
    end 
end 

那麼一切都將是清潔的ActiveRecord得到它的骯髒的小手之前,您的數據和把事情搞得一團糟。

您可以通過覆蓋模型中的profit=方法來做類似的事情,但這並不是模型的工作。

+0

我知道我可以在控制器中做到這一點,但我希望在保存模型本身之前自動化該過程,因爲我稱之爲來自不同的地方。有任何想法嗎? – 2012-04-18 22:53:13

+0

感謝您提供豐富的答案,並在錯誤的地方抓住to_s方法。 – 2012-04-18 22:54:39

+0

@TamikSoziev:你可以提供你自己的'profit ='方法。 – 2012-04-18 22:56:45

相關問題