Skip to content

Instantly share code, notes, and snippets.

@jennceng
Created September 21, 2016 14:05
Show Gist options
  • Save jennceng/40e94abd79579990a97fb8d5066b06c2 to your computer and use it in GitHub Desktop.
Save jennceng/40e94abd79579990a97fb8d5066b06c2 to your computer and use it in GitHub Desktop.
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment