DEV Community

Alexander Rovang
Alexander Rovang

Posted on

Notes to Myself (Rails:Entry#3 - select_tag)

My goal here was to associate a movie review with a particular movie via a dropdown list of movie titles.

This is the movie show page:

<h1>Movies#show</h1>

<div>
<p>Name: <%= @movie.name %></p>
<p>Year: <%= @movie.year %></p>
<p>Genre: <%= @movie.genre %></p>
<p>Director: <%= @movie.director %></p><br>
Reviews:
<% @movie.reviews.each do |review|%>
<p> "<%= review.post %>"</p>
<% end %>
<button><%= link_to "Add a Review!", new_review_path %></button>
</div>
Enter fullscreen mode Exit fullscreen mode

The link_to method has 3 components.

1) the method name "link_to"
2) the element that the user will click on, here the words "Add a Review!" followed by a comma
3) the route path of the link, in this case the "new_review_path" which is the new method in the reviews controller

Once we arrive at the new_review_path we are given this code:

  def new
    @review = Review.new
  end
Enter fullscreen mode Exit fullscreen mode

...which simply sets up the ability of the new.html.erb page to create a new review.

This is the new.html.erb form page:

<h1>Review this movie</h1>

<%= form_for(@review) do |review| %>
<%= select_tag(:name, options_for_select(Movie.all.collect{ |u| [u.name]})) %>
<p>Post: <%= review.text_area :post %></p>
<p><%= review.submit %></p>
<% end %>
Enter fullscreen mode Exit fullscreen mode

I'll gloss over the form_for method since I covered that in a previous blog post, but it is important to note that the select_tag should go inside of the form so that it's parameters can be submitted to the create path.

The select_tag also has 3 components.

1) the method name "select_tag"
2) an argument whose first part is the symbol for the params hash, in this case :name
3) the options_for_select method

The way I've ordered my options_for_select argument is via a class iteration of Movie that returns all of the movies in the database by name.

Once this form is submitted, if you were to inspect the params that is sent to the create method in the Reviews controller, you would see this:

 #<ActionController::Parameters {"authenticity_token"=>"g5hKHV_DHRaR6THLAbvsnXAuaK_ZBIoyQKTVLldgaUxOt0eJ60yXOc1qyQDdqRIuNUAIZ7O-RdCb-zeLynjwdg", "name"=>"Jaws", "review"=>{"post"=>"I can't stand it"}, "commit"=>"Create Review", "controller"=>"reviews", "action"=>"create"} permitted: false>
Enter fullscreen mode Exit fullscreen mode

Here you'll see that a 🔑 of "name" has been set to the movie title "Jaws", as well as the actual review hash params which contains a key of "post" (the name of the review attribute in the database) which is set to the value "I can't stand it"... the actual review.

So we end up with 2 things. A review, and a movie. Both identifiable, and therefore easy to associate in the Review controller's create method.

 def create
    review = Review.new(accept_params)
    movie = Movie.find_by(:name => params[:name])
    review.movie_id = movie.id
    review.save
    redirect_to movie_path(movie.id)
  end
Enter fullscreen mode Exit fullscreen mode

In the create method I

-instantiate a new Review
-find a movie by it's title via the params[:name] key
-set the movie id of that movie to the foreign key of my new review
-save the review
-redirect to the show page of this movie

And there you have it! Only thing to mention: due to strong params in this program, I defined a private method for both my normal form information and my "imported" form info (the movie names/ids).

private

  def accept_params
    params.require(:review).permit(:post)
  end

  def movie_params
    params.require(:movie).permit(:name)
  end
Enter fullscreen mode Exit fullscreen mode

If you fail to do this, the review won't be saved in the database because it won't accept the movie_id.

Top comments (0)