So this is a simple project where there are products and you can bid for them. Think eBay.
I built the project as follows:
$ rails new routetest
$ rails g scaffold product productname reserveprice:integer
$ rails g scaffold bid bidprice:integer product_id
On the 'show' view for each product I include
<p id="notice"><%= notice %></p>
<h2>Normal Products\Show Part</h2>
<p>
<strong>Productname:</strong>
<%= @product.productname %>
</p>
<p>
<strong>Reserveprice:</strong>
<%= @product.reserveprice %>
</p>
<%= link_to 'Back', products_path %>
<br /><br />
<h2>List of bids</h2>
<table>
<thead>
<tr>
<th>Product ID</th>
<th>Bid Price</th>
</tr>
</thead>
<tbody>
<% @bids.each do |bid| %>
<tr>
<td><%= bid.product_id %></td>
<td><%= bid.bidprice %></td>
</tr>
<% end %>
</tbody>
</table>
<br /><br />
<h2>Form For Bids</h2>
<h4>Make a Bid</h4>
<%= form_for(@bid) do |b| %>
<div class="field">
<%= b.number_field :bidprice %>
</div>
<div>
<%= b.hidden_field :product_id, :value => (params[:id]) %>
</div>
<div class="actions">
<%= b.submit %>
</div>
<% end %>
On clicking 'submit' the bids controller#create action is called.
def create
@bid = Bid.new(bid_params)
if @bid.save
redirect_to "/products/#{@bid.product_id}", notice: 'Bid was successfully created.'
else
render action: 'new'
end
end
So a sucessful bid returns the user to the product show view and adds the record to the bids section of the page.
I have a validates_presence_of validation in the bids model. So if the user leaves the bids field empty the validation fails and the bids controller crate action renders the bids new view. Including the error messages. The bids new view includes the scaffold generated code "<% if @bid.errors.any? %> etc"
What I actually want to do instead of rendering the new action is to throw the user back to the products show page as it does when a successful bid is made only to show the error messages on the products show page. Basically this gives the user the sense of staying on the products show page instead of throwing them to the bids new page.
The problem I have is how do I get the error message to pass back to the products show page? If I edit the bids controller create action code above and replace the "render action: 'new'" line with
redirect_to "/products/#{@bid.product_id}"
then the user is returned to the page but the error message isn't passed. I think this is because the error message is stored as part of the rendering of the new action (of the bids controller)
So my question is how do I achieve what I want to do? To return to the products show view and show the error messages that come from the failed validation. Thank you.
PS - I kow I need to add the scaffold generated code "<% if @bid.errors.any? %> ..." code to the products show view but I haven't done so in the code above because it will cause a NilMethod error because the error isnt created for the method to exist on it.
You want something like this
redirect_to product_path(@bid.product_id), :flash => { :error => @bid.errors.full_messages.join(', ') }
This will redirect to the product page but pass the errors as a flash message.
One quick option would be to render the show
product view from within the bids#create
action:
if @bid.save
redirect_to "/products/#{@bid.product_id}", notice: 'Bid was successfully created.'
else
@product = Product.find(params[:bid][:product_id])
render template: 'products/show'
This will display what you want but the URL will still show as the create
bid path which might be confusing. And it might be a little hard to read since we have to bounce between two controllers to accomplish this one task.
A better option might be to move the bid creation action into your products controller. To do this you could...
Add a new route for /products/:id/create_bid
in routes.rb
:
resources :products do
member do
post 'create_bid'
end
end
Use this route in your bid creation form:
<h4>Make a Bid</h4>
<%= form_for(@bid, url: create_bid_product_path(@product)) do |b| %>
Define this action in your products controller:
def create_bid
@bid = Bid.new(bid_params)
if @bid.save
redirect_to product_url(params[:id]), notice: 'Bid was successfully created.'
else
@product = Product.find(params[:id])
render action: 'show'
end
end
And copy over the bid_params
method from the bids controller into the products controller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With