2011-10-15 17 views
5

Perché ricevo un nil can't be coerced into BigDecimal quando si tenta di eseguire un calcolo: Ecco il codice:Ruby on Rails nullo non può essere costretto a BigDecimal

modello/drink.rb

class Drink < ActiveRecord::Base 
    belongs_to :menu 
    before_save :total_amount 

def total_amount 
    self.total_amount = self.price * self.quantity 
end 

modello/menu.rb

class Menu < ActiveRecord::Base 
    has_many :drinks, :dependent => :destroy 
    accepts_nested_attributes_for :drinks, :allow_destroy => true 
    #Validations 

end 

* Drink è la (nidificato) modello e Menu bambino la p arent modello Quando si tenta di creare una nuova bevanda la visualizzazione del browser seguente messaggio di errore nil can't be coerced into BigDecimal app/models/drink.rb:7:in 'total-amount' app/controllers/menus_controller.rb:47:in 'create' app/controllers/menus_controller.rb:46:in 'create'

app/db/migrazione

class CreateDrinks < ActiveRecord::Migration 
    def change 
    create_table :drinks do |t| 
     t.string :name 
     t.decimal :quantity,:precision => 8, :scale => 2 
     t.decimal :price, :precision => 8, :scale => 2 
     t.decimal :vat, :precision => 8, :scale => 2 
     t.references :menu 

     t.timestamps 
    end 
    add_index :drinks, :menu_id 
    end 
end 

controllori/drinks_controller.rb

class DrinksController < ApplicationController 
     # GET /drinks 
     # GET /drinks.json 
     def index 
     @drinks = Drink.all 

     respond_to do |format| 
      format.html # index.html.erb 
      format.json { render :json => @drinks } 
     end 
     end 

     # GET /drinks/1 
     # GET /drinks/1.json 
     def show 
     @drink = Drink.find(params[:id]) 

     respond_to do |format| 
      format.html # show.html.erb 
      format.json { render :json => @drink } 
     end 
     end 

     # GET /drinks/new 
     # GET /drinks/new.json 
     def new 
     @drink = Drink.new 

     respond_to do |format| 
      format.html # new.html.erb 
      format.json { render :json => @drink } 
     end 
     end 

     # GET /drinks/1/edit 
     def edit 
     @drink = Drink.find(params[:id]) 
     end 

     # POST /drinks 
     # POST /drinks.json 
     def create 
     @article = Drink.new(params[:drink]) 

     respond_to do |format| 
      if @drink.save 
      format.html { redirect_to @drink, :notice => 'Drink was successfully created.' } 
      format.json { render :json => @drink, :status => :created, :location => @article } 
      else 
      format.html { render :action => "new" } 
      format.json { render :json => @drink.errors, :status => :unprocessable_entity } 
      end 
     end 
     end 

     # PUT /drinks/1 
     # PUT /drinks/1.json 
     def update 
     @drink = Drink.find(params[:id]) 

     respond_to do |format| 
      if @drink.update_attributes(params[:drink]) 
      format.html { redirect_to @drink, :notice => 'Drink was successfully updated.' } 
      format.json { head :ok } 
      else 
      format.html { render :action => "edit" } 
      format.json { render :json => @drink.errors, :status => :unprocessable_entity } 
      end 
     end 
     end 

     # DELETE /drinks/1 
     # DELETE /drinks/1.json 
     def destroy 
     @drink = Drink.find(params[:id]) 
     @drink.destroy 

     respond_to do |format| 
      format.html { redirect_to drinks_url } 
      format.json { head :ok } 
     end 
     end 
    end 

prega può Qualcuno mi dice cosa c'è che non va nel codice?

+0

Quali valori si ottengono per 'prezzo' e' quantità' in 'total_amount'? Fai un "Logger.debug" # {self.price} # {self.quantità} "' come prima riga in 'total_amount'. –

+0

ecco cosa ottengo con 'Logger.debug ...' come prima riga nel metodo total_amount' metodo non definito 'debug' per Logger: Class' – blawzoo

risposta

15

Se si desidera nil essere valutato come 0.0 allora si può fare qualcosa di simile:

def total_amount 
    self.total_amount = self.price.to_s.to_d * self.quantity.to_s.to_d 
end 

o esplicitamente verificare la presenza di zero

def total_amount 
    if self.price && self.quantity 
    self.total_amount = self.price * self.quantity 
    else 
    self.total_amount = "0.0".to_d 
    end 
end 

Il problema è davvero che i campi dei record aren' Imposta come ti aspetti che siano. È necessario utilizzare le convalide per assicurarsi che i campi price e quantity siano impostati?

class Drink 
    validates :price, :presence => true  # Don't forget add DB validations, too :) 
    validates :quantity, :presence => true 
end 

In questo modo si garantisce di non ottenere un valore nullo quando si chiama #total_amount.

+0

Grazie mille Wizard of Ogz la tua risposta ha funzionato perfettamente – blawzoo

+0

La tua soluzione mi aiuta a invocare il metodo total_amount anche nelle viste. È possibile visualizzare il problema al seguente collegamento: http://stackoverflow.com/questions/7774638/ruby-on-rails-calculation – blawzoo

2

Non si sta impostando il valore quantity in qualsiasi punto in modo che sia nil e nil non possa essere forzato in un numero per la moltiplicazione.

Presumibilmente vostro price è un decimal(n,2) (per alcuni n) nel database in modo self.price è rappresentato in Ruby come un oggetto BigDecimal; è per questo che stai ricevendo lamentele per non essere in grado di costringere a BigDecimal.

È possibile ottenere un errore simile di irb come questo:

>> 11 * nil 
TypeError: nil can't be coerced into Fixnum 
    from (irb):7:in `*' 

tuo self.price è impostato però. Se non fosse stato, allora si otterrebbe uno di questi:

NoMethodError: undefined method `*' for nil:NilClass 

si potrebbe desiderare di aggiungere

validates_presence_of :quantity, :price 

(o eventuali convalide più severe) al modello se si sta richiedendo che essi siano impostato.

+0

Mi dispiace, ma Non capisco il problema? È un problema di migrazione? Sono un novizio quindi per favore sii specifico perché certe cose possono sembrare molto astratte per me. – blawzoo

+0

@blawzoo: Perché aspettarsi che 'self.quantity' sia impostato su qualsiasi cosa Forse dovresti includere il codice del controller che costruisce i tuoi oggetti. Da qualche parte stai costruendo un Drink ma non gli dici quale sia la "quantità", quindi la quantità è "nulla". –

+0

Ho messo il controller e la migrazione delle bevande. Perché non riesco a raggiungere la quantità (che è un attributo definito di bevanda) nel metodo total_amount – blawzoo