validate :check_product_stock
def check_product_stock
@thisproduct = product.id
@productbeingchecked = Product.find_by_id(@thisproduct)
@stocknumber = @productbeingchecked.stock_number
if producto.en_stock == 0
raise "El Producto no tiene stock suficiente para completar la venta"
#errors.add :venta, "Producto con pedos de stock"
return false
end
true
end
end
i need to be able to validate on creation of a model (sale), if it's association (product), hasn't reached zero in a product.column called stock_number.
i think i need to rewrite the entire thing but now with validate :check_product_stock then built a method from scratch that checks if product hasn't reached zero and it it has it should throw a flash notice and stay in the same place (sales/new)
class Venta < ActiveRecord::Base
hobo_model # Don't put anything above this
belongs_to :cliente, :accessible => true
belongs_to :producto, :accessible => true
belongs_to :marca, :accessible => true
belongs_to :vendedor
belongs_to :instalador
has_many :devolucions
fields do
numero_de_serie :string
precio_de_venta :integer
precio_de_instalacion :integer, :default => "0"
forma_de_pago enum_string(:contado, :tarjeta)
status enum_string(:activa, :cancelada)
timestamps
end
validates_presence_of :cliente, :precio_de_venta, :vendedor, :precio_de_instalacion
validate_on_create :check_product_stock
after_save :descontar_precio_de_instalacion_si_el_instalador_es_a_destajo
#def stock_error
#flash[:notice] = "Producto con pedos de stock"
# redirect_to :controller => :venta, :action => :stock_error
#errors.add_to_base("Producto con pedos de stock")
# end
def check_product_stock
if producto.en_stock == 0
raise "El Producto no tiene stock suficiente para completar la venta"
#errors.add :venta, "Producto con pedos de stock"
return false
end
true
end
#def check_product_stock
# if producto.en_stock == 0
# errors.add :producto, "El Producto no tiene stock suficiente para completar la venta"
# return false
# end
# true # guards against returning nil which is interpreted as false.
#end
def descontar_precio_de_instalacion_si_el_instalador_es_a_destajo
@este_instalador_id = instalador.id
@instalador = Instalador.find_by_id(@este_instalador_id)
if @instalador.a_destajo?
@last_venta = Venta.find(:last)
@vid = @last_venta.id
@precio_de_instalacion_original = precio_de_instalacion
@mitad_de_instalacion = @precio_de_instalacion_original/2
#Venta.update(@vid, :precio_de_instalacion => @mitad_de_instalacion)
ActiveRecord::Base.connection.execute "UPDATE ventas SET precio_de_instalacion = #{@mitad_de_instalacion} WHERE id = #{@vid};"
end
end
#after_save :reduce_product_stock_number
# def reduce_product_stock_number
# Producto.decrement_counter(:en_stock, producto.id)
# end
# --- Permissions --- #
def create_permitted?
true
end
def update_permitted?
false
end
def destroy_permitted?
false
end
def view_permitted?(field)
true
end
end
And this is my observer that diminishes the en_stock column from producto:
class VentaObserver < ActiveRecord::Observer
def after_save(venta)
@venta_as_array = venta
if venta.producto_id?
@pid = @venta_as_array[:producto_id]
Producto.decrement_counter(:en_stock, @pid)
end
if venta.cart_id
@cid = @venta_as_array[:cart_id]
@cart = Cart.find_by_id(@cid)
for item in @cart.cart_items do
# @pid = @cart.cart_items.producto.id
Producto.decrement_counter(:en_stock, item.producto.id)
end
#si el instalador es a destajo se debe descontar la mitad del rpecio de instalacion
end
end
end
It seems you've got a lot going wrong here.
First of all, you're doing way too much work. This is all you really need.
before_save :check_product_stock
def check_product_stock
if product.stocknumber == 0
flash[:notice] = "Producto con pedos de stock"
end
end
Secondly, the flash hash is not available in models. You can use the ActiveRecord error object to make errors available to the controller and views by replacing
flash[:notice] =
with errors.add_to_base
I used errors.add_to_base because the error is not exactly a part of this model, yet is still blocking the save.
Thirdly, it seems like you're reducing product.stocknumber at some point. Probably as a before_validation so it's highly possible that product.stocknumber is less than 0 during the check if product.stocknumber was 0 before the save call.
So let's change the if condition to reflect that.
unless product.stocknumber > 0
Finally, you're using a before_save callback, so just adding an error will not cancel the transaction. You need to return false for a before/after save/create/update/valdiaiton callback to cancel the transaction.
Putting this all together gives you
before_save :check_product_stock
def check_product_stock
unless product.stocknumber > 0
errors.add_to_base "Producto con pedos de stock"
return false
end
true # guards against returning nil which is interpreted as false.
end
As for displaying these errors you can either use the nice error_messages_for helper on the object in the view. Or copy the errors to the flash hash in the controller.
In the view:
<%= error_mesages_for :order %>
Or, in the controller in the else block of if @order.save
:
flash[:errors] = @order.errors.full_messages.join "<br />"
I prefer the errors over notice when it comes to passing errors in the flash hash because it makes it easy to distinguish the two via CSS if an action happens to produce both a notices or an error. Also it's more DRY to always display flash[:errors] with a class that gives red text, the write the logic into your view to determine if the contents of flash[:notice] are an error or a notice.