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