Problema con select y validate

Hola gente del foro, estoy haciendo una aplicación que me permite crear
un producto con diferentes datos(titulo,descripcion,image_url y
categoria). La categoria se la debe seleccionar mediante un combobox que
carga las categorias disponible de la tabla “Categorias” de la base de
datos. El problema surge cuando activo el validates para el modelo
“Producto”, ya que cuando no ingreso algun dato(es decir no se cumple la
condición de validación) en vez de marcarme los campos erróneos me
muestra el siguiente error:

NoMethodError in Productos#create

Showing productos/new.html.erb where line # raised:

You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each

app/views/productos/new.html.erb:26:in
_run_erb_47app47views47productos47new46html46erb' app/views/productos/new.html.erb:5:in_run_erb_47app47views47productos47new46html46erb’
app/controllers/productos_controller.rb:53:in create' app/controllers/productos_controller.rb:47:increate’
:1:in `start’

Lo que yo entiendo de este error es que hubo un problema al recargar la
página new debido a que el array que estoy recorriendo para formar el
combobox de categorías disponibles me devolvió un nulo. Agradecería
cualquier ayuda. Saludos.

Hernán Pérez wrote:

Showing productos/new.html.erb where line # raised:

You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each

app/views/productos/new.html.erb:26:in
_run_erb_47app47views47productos47new46html46erb' app/views/productos/new.html.erb:5:in_run_erb_47app47views47productos47new46html46erb’
app/controllers/productos_controller.rb:53:in create' app/controllers/productos_controller.rb:47:increate’
:1:in `start’

¿Podrias poner el codigo del metodo create?

Jose Antonio P. wrote:
¿Podrias poner el codigo del metodo create?
Por supuesto, ahí va:

def create
@producto = Producto.new(params[:producto])

 respond_to do |format|
  if @producto.save
    flash[:notice] = 'Producto was successfully created.'
    format.html { redirect_to(@producto) }
    format.xml  { render :xml => @producto, :status => :created, 

:location => @producto }
else
format.html { render :action => “new” }
format.xml { render :xml => @producto.errors, :status =>
:unprocessable_entity }
end
end
end

La linea 47 corresponde a respond_to do |format|
y la linea 53 corresponde a format.html { render :action => “new” }

Hernán Pérez wrote:

Jose Antonio P. wrote:
¿Podrias poner el codigo del metodo create?
ah me olvidaba, también te paso el del new

Categoria
<% @categoria.each do |categoria| %> > <%= categoria.nombre_categoria %> <% end %>

la linea 26 es <% @categoria.each do |categoria| %>
y la 5 se encuentra bién arriba y dice <% form_for(@producto) do |f| %>

Buenas,
entiendo que en tu método new tendrás algo parecido a esto:
def new
@producto = Producto.new
@categorias = Categorias.all
end

de tal manera a que tu vista new.html.erb le llega el array de
categorías, pero cuando te falla la validación, estás cargando esa misma
vista sin haber inicializado el listado. Lo que tendrías que hacer sería
volver a cargarlo dentro del método create(ya sea al principio o sólo
cuando no se guarde el objeto).
Otra opción es hacerlo de manera automática:

before_filter :set_categorias
private
def set_categorias
@categorias = Categorias.all
end

Y así tendrías el array con las categorías siempre disponible. si sólo
lo necesitas para determinados métodos, puedes usar las opciones :only o
:except:
http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html

Saludos

Hernán Pérez escribió:

Por cierto, ¿hay alguna razón para hacer el select a mano?
Creo que sería mejor hacerlo con el helper:
<% for_form @producto do |f| %>
<%= f.select :categoria, @categorias.map {|cat| [cat.nombre, cat.id]} %>
<% end %>

salud!

Hernán Pérez escribió:

2008/11/24 Hernán Pérez [email protected]

             <%= categoria.nombre_categoria %>
             </option>
   <% end %>
 </select>

la linea 26 es <% @categoria.each do |categoria| %>
y la 5 se encuentra bién arriba y dice <% form_for(@producto) do |f| %>

Cuando hay errores, caes en el else de product.save, y haces render
:action
=> ‘new’, donde intentas recorrer @categoria, pero es nil porque en el
método create no lo creas en ningún momento.

P.S. Y no utilicéis y
, por Alá :slight_smile:

Manuel González Noriega wrote:

P.S. Y no utilicéis y
, por Alá :slight_smile:
Gracias por tu respuesta, y perdón por lo de los y
recién me
estoy iniciando en la programación web

Borja Martín wrote:

Por cierto, ¿hay alguna razón para hacer el select a mano?
Creo que sería mejor hacerlo con el helper:
<% for_form @producto do |f| %>
<%= f.select :categoria, @categorias.map {|cat| [cat.nombre, cat.id]} %>
<% end %>

salud!
La verdad a ese select lo copié de un tutorial q encontré por la red,
pero también encontré el que me pasaste solo q al otro le entendía
mejor.
Por cierto Borja Martín muchas gracias por tu respuesta, muy explicativa
y concisa. Me sirvió muchisimo.
Por cierto les agradezco a todos sus consejos de programación, ya q uno
se lleva de los minitutoriales q hay en la red y después terminas
programando cualquier cosa. Saludos.

Por cierto, me bailó el tag del formulario. Sería form_for

Salud!

Hernán Pérez escribió:

Borja Martín wrote:

Buenas,
entiendo que en tu método new tendrás algo parecido a esto:
def new
@producto = Producto.new
@categorias = Categorias.all
end

de tal manera a que tu vista new.html.erb le llega el array de
categorías, pero cuando te falla la validación, estás cargando esa misma
vista sin haber inicializado el listado. Lo que tendrías que hacer sería
volver a cargarlo dentro del método create(ya sea al principio o sólo
cuando no se guarde el objeto).

Me quedó una duda en la parte:

pero cuando te falla la validación, estás cargando esa misma
vista sin haber inicializado el listado
por que debo inicializar el listado y no el producto, si estoy cargando
una nueva vista?

Hernán Pérez wrote:

Me quedó una duda en la parte:

pero cuando te falla la validación, estás cargando esa misma
vista sin haber inicializado el listado
por que debo inicializar el listado y no el producto, si estoy cargando
una nueva vista?

Perdón, si estaba inicializada al comienzo de create como:

@producto = Producto.new(params[:producto])

Saludos.