Re-initialising page after validation fails

Hi,

I have a controller and two of the actions in it are as follows:

GET /bids/new

GET /bids/new.xml

def new
@bid = Bid.new
@auctionItems = AuctionItem.find(:all)

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

end

GET /bids/1/edit

def edit
@bid = Bid.find(params[:id])
end

POST /bids

POST /bids.xml

def create
@bid = Bid.new(params[:bid])

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

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

The new.html.erb contains this line:

<%= f.select(:auction_item_id, @auctionItems.collect {|i| [ i.title,
i.id ]

Which populates a select with the auctionItems fetched in the new
action.

If validation fails in the “create”, I get an error something like:

NoMethodError in Bids#create

Showing app/views/bids/new.html.erb where line #8 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.collect

Extracted source (around line #8):

5:
6:
7:


8: <%= f.select(:auction_item_id, @auctionItems.collect {|i| [ i.title,
i.id ] }, { :include_blank => true }) %>
9:


10:
11:

I am guessing this is because the auctionItems is not repopulated for
this request.

So, does this:

    format.html { render :action => "new" }

Mean it only displays new.html.erb, and not re-runs the “new” action?

What is the best way to ensure that @auctionItems gets repopulated. I
suppose I modify create like this:

def create
@bid = Bid.new(params[:bid])

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

:location => @bid }
else
@auctionItems = AuctionItem.find(:all)
format.html { render :action => “new” }
format.xml { render :xml => @bid.errors, :status =>
:unprocessable_entity }
end
end
end

But it doesn’t seem the best practice. Is there a better way to do
this? I have seen some mention of “Helpers” - is this something they
could be used for?

Many thanks,
Andrew.

On Aug 8, 7:20 am, Andrew M. [email protected]
wrote:

Extracted source (around line #8):
I am guessing this is because the auctionItems is not repopulated for
this request.

So, does this:

    format.html { render :action => "new" }

Mean it only displays new.html.erb, and not re-runs the “new” action?

Yep - all that does is render the selected template. The idea is that
that the form will be redisplayed with the contents of @bid.

    format.html { redirect_to(@bid) }

But it doesn’t seem the best practice. Is there a better way to do
this? I have seen some mention of “Helpers” - is this something they
could be used for?

This is a very typical use of helpers - you could put this code into
app/helpers/bid_helper.rb:

def auction_select(form)
form.select(:auction_item_id, AuctionItem.all.collect {|i|
[ i.title,
i.id ] })
end

and then call it from your views as:

<%= auction_select(f) %>

It tidies things up, and then when you need to select an auction
someplace else, it can be reused.

BTW, mixed-case variable names are nonstandard in Rails - normally,
you use underscored names (@auction_items rather than @auctionItems).
No real difference, but it looks odd to experienced programmers.

–Matt J.

Thanks Matt - that sounds like the solution I am after. Also thanks for
the advice re variable names. I am coming to Ruby from Java and have a
bit to learn in that regard. :slight_smile:

Matt J. wrote:

This is a very typical use of helpers - you could put this code into
app/helpers/bid_helper.rb:

def auction_select(form)
form.select(:auction_item_id, AuctionItem.all.collect {|i|
[ i.title,
i.id ] })
end

and then call it from your views as:

<%= auction_select(f) %>

It tidies things up, and then when you need to select an auction
someplace else, it can be reused.

BTW, mixed-case variable names are nonstandard in Rails - normally,
you use underscored names (@auction_items rather than @auctionItems).
No real difference, but it looks odd to experienced programmers.

–Matt J.