class ReviewsController < ApplicationController
def index
@product = Product.find(params[:product_id])
@reviews = @product.reviews
end
def new
@product = Product.find(params[:product_id])
@review = Review.new
end
def create
@product = Product.find(params[:product_id])
@review = Review.new(review_params)
@review.product = @product
if @review.save
flash[:notice] = "Review saved successfully."
redirect_to product_path(@product)
else
flash[:alert] = "Failed to save review."
render :new
end
end
def review_params
params.require(:review).permit(:body)
end
end
# alternative syntax for saving the correct product to the review:
class ReviewsController < ApplicationController
def index
@product = Product.find(params[:product_id])
@reviews = @product.reviews
end
def new
@product = Product.find(params[:product_id])
@review = Review.new
end
def create
@review = Review.new(review_params)
if @review.save
flash[:notice] = "Review saved successfully."
redirect_to product_path(@product)
else
flash[:alert] = "Failed to save review."
render :new
end
end
def review_params
params.require(:review).permit(:body).merge(product: Product.find(params[:product_id]))
end
end
Forms: If a form has its own page, the form_for will have to have an array that hold both the object for the parent and the child, where the parent was defined as an instance variable in the Review#new
class ReviewsController < ApplicationController
...
def new
@product = Product.find(params[:product_id])
@review = Review.new
end
...
end
<h1>New Review for <%= @product.name %></h1>
<%= form_for [@product, @review] do |f| %>
<%= f.label :body %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Simply consider whether or not it will be necessary, for example if the form for a new review was on the product show page, you would not need a necessarily need a nested route (unique URL) for the form, and would instead have:
class ProductsController < ApplicationController
...
def show
@product = Product.find(params[:id])
@review = Review.new
end
...
end
<h1>New Review for <%= @product.name %></h1>
<%= form_for [@product, @review] do |f| %>
<%= f.label :body %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
# submission will hit Review#create
class ReviewsController < ApplicationController
def create
@review = Review.new(review_params)
if @review.save
flash[:success] = "Review has been successfully created!"
else
flash[:error] = @review.errors.full_messages.join(", ")
end
redirect_to post_path(@review.post)
end
...
private
def review_params
params.require(:review).permit(:body).merge(product: Product.find(params[:product_id]))
end
end
Path helpers: keep in mind that with nested routes, for exmaple if you are trying to go to a review show page or rerender a form template if you filled it out incorrectly, you must make sure to define and pass in both the parent and child objects
- rake routes is your best friend
- use
| grep thingofinterest
to filter through routes
# example of how to use path helper, pass in the arguments in the correct order of nesting, use URI in rake routes to help inform you
product_review_path(@product, @review)