2011-10-15 12 views
5

¿Por qué recibo nil can't be coerced into BigDecimal cuando trato de realizar un cálculo: Aquí está el código:Ruby on Rails nula no puede ser obligado a BigDecimal

modelo

/drink.rb

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

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

modelo/menu.rb

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

end 

* bebida es el (anidada) modelo del niño y menú de la p enviaban modelo Cuando intento crear una nueva bebida de la pantalla del navegador siguiente mensaje de error 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/migración

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 

controladores/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 

Por favor, puede ¿alguien me dice qué le pasa al código?

+0

¿Qué valores obtienes por 'price' y' quantity' en 'total_amount'? Haga un 'Logger.debug" # {self.price} # {self.quantity} "' como la primera línea en 'total_amount'. –

+0

esto es lo que obtengo con 'Logger.debug ...' como la primera línea en el método total_amount' método no definido 'debug' para Logger: Class' – blawzoo

Respuesta

15

Si quieren nula a ser evaluados como 0.0 a continuación, puede hacer algo como esto:

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

o explícitamente comprobar la nula

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 

El problema es realmente que sus campos de registro aren' t configurado como usted espera que lo sean. ¿Necesita usar validaciones para asegurarse de que los campos price y quantity estén configurados?

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

De esta manera, asegúrese de no obtener un valor nulo al llamar a #total_amount.

+0

Muchas gracias Wizard of Ogz su respuesta funcionó perfectamente – blawzoo

+0

Su solución me ayuda a invocar el método total_amount en las vistas también. Puede ver el problema en el siguiente enlace: http://stackoverflow.com/questions/7774638/ruby-on-rails-calculation – blawzoo

2

No está configurando el valor quantity en cualquier lugar, por lo que es nil y nil no se puede forzar en un número para la multiplicación.

Es de suponer que su price es una decimal(n,2) (por alguna n) en la base de datos para self.price está representado en Ruby como un objeto BigDecimal; es por eso que recibes quejas por no poder coaccionar a BigDecimal.

, usted puede obtener un error similar de irb así:

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

Su self.price se establece sin embargo. Si no fuera entonces se obtendría uno de estos:

NoMethodError: undefined method `*' for nil:NilClass 

Es posible que desee añadir

validates_presence_of :quantity, :price 

(o posibles validaciones estrictas) a su modelo si está exigiendo que puedan conjunto.

+0

Lo siento, pero ¿No entiendo el problema? ¿Es un problema de migración? Soy un novato, así que por favor sé específico porque ciertas cosas pueden sonar muy abstractas para mí. – blawzoo

+0

@blawzoo: ¿Por qué esperas que 'self.quantity' se establezca en cualquier cosa? ¿Alguna vez deberías incluir el código del controlador que construye tus objetos? En algún lugar estás construyendo una bebida pero no le dices cuál es la cantidad, entonces la cantidad es cero. –

+0

He puesto el controlador de bebidas y la migración. ¿Por qué no puedo alcanzar la cantidad (que es un atributo definido de bebida) en el método total_amount? – blawzoo