2012-03-13 14 views
10

Quindi ho un modulo in cui gli utenti possono inserire un prezzo. Sto provando a fare un before_validation che normalizza i dati, tagliando $ se l'utente lo mette.Convertire l'input dell'utente nel numero intero

before_validation do 
unless self.price.blank? then self.price= self.price.to_s.gsub(/\D/, '').to_i end 
end 

Se gli input dell'utente $ 50 Questo codice mi sta dando 0. Se gli ingressi di utenti 50 $ questo codice mi dà 50. Credo che dal momento che il tipo di dati è intero che Rails è in esecuzione .to_i prima del mio before_validation e ritaglio tutto dopo il $. Questo stesso codice funziona bene se il tipo di dati è una stringa.

Chiunque ha una soluzione che mi consente di mantenere il tipo di dati intero?

risposta

20

Un modo è quello di ignorare il meccanismo sul modello che fissa il prezzo, in questo modo:

def price=(val) 
    write_attribute :price, val.to_s.gsub(/\D/, '').to_i 
end 

Così, quando lo fai @model.price = whatever, andrà a questo metodo al posto dello scrittore attributo di rotaie di default. Quindi è possibile convertire il numero e utilizzare write_attribute per eseguire la scrittura effettiva (è necessario farlo in questo modo perché lo standard price= è ora questo metodo!).

Mi piace questo metodo, ma per fare un riferimento un altro modo per farlo è nel controller prima di assegnarlo al modello. Il parametro si presenta come una stringa, ma il modello sta convertendo quella stringa in un numero, quindi lavora direttamente con il parametro. Qualcosa di simile a questo (basta adattarlo al codice di controllo):

def create 
    @model = Model.new(params[:model]) 
    @model.price = params[:model][:price].gsub(/\D/, '').to_i 
    @model.save 
end 

Per entrambe le soluzioni, rimuovere tale before_validation.

+0

Grazie. Ho sempre pensato che l'uso di before_validation sia piuttosto goffo. Questo è decisamente più elegante. –

3

che definirei un attributo virtuale e fare il mio manipolazione ci consente di formattare e modificare sia il getter e setter a volontà:

class Model < ActiveRecord::Base 

    def foo_price=(price) 
    self.price = price... #=> Mods to string here 
    end 

    def foo_price 
    "$#{price}" 
    end 

È inoltre potrebbe desiderare di notare che:

"$50.00".gsub(/\D/, '').to_i #=> 5000 
+0

Grazie, ci provo anche io. Ho dato un'altra risposta perché ho provato prima il suo commento. Inoltre, grazie per il rilevamento .00, aggiornerò la mia espressione regolare. – Robert

+0

Np. Ho suggerito questo approccio perché non sono un fan della logica aggiuntiva nel controller e c'è chiarezza dato che non si sta sovrascrivendo un campo che a prima vista dovrebbe corrispondere al campo db e suppongo che una stringa non sia il tipo di dati corretto:) – offbyjuan

+0

Vorrei creare una classe di presentatore aggiuntiva per la logica di formattazione qui –

0

mio soluction colum prezzo di decimali

t.decimal :price, precision: 12, scale: 6 

# app/concern/sanitize_fields.rb 
    module SanitizeFields 
     extend ActiveSupport::Concern 

     def clear_decimal(field) 
     return (field.to_s.gsub(/[^\d]/, '').to_d/100.to_d) unless field.blank? 

     end 

     def clear_integer(field) 
     field.to_s.strip.gsub(/[^\d]/, '') unless field.blank? 
     end 

     # module ClassMethods 
     # def filter(filtering_params) 
     #  results = self.where(nil) 
     #  filtering_params.each do |key, value| 
     #  results = results.public_send(key, value) if value.present? 
     #  end 
     #  results 
     # end 
     # 
     # #use 
     # #def index 
     # # @products = Product.filter(params.slice(:status, :location, :starts_with)) 
     # #end 
     # 
     # end 

    end 

#app/controllers/products_controller.rb 

include SanitizeFields 

params[:product][:price] = clear_decimal(params[:product][:price]) 
Problemi correlati