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: <p>
8: <%= f.select(:auction_item_id, @auctionItems.collect {|i| [ i.title,
i.id ] }, { :include_blank => true }) %>
9: </p>
10:
11: <p>
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.
-- 
Posted via http://www.ruby-forum.com/.
On Aug 8, 7:20 am, Andrew Myers <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> 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: <p> > 8: <%= f.select(:auction_item_id, @auctionItems.collect {|i| [ i.title, > i.id ] }, { :include_blank => true }) %> > 9: </p> > 10: > 11: <p> > > 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.> > 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? >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 Jones
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. :-) Matt Jones 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 Jones-- Posted via http://www.ruby-forum.com/.