Helper Methods

marywebby

Mary Webby

Posted on March 1, 2024

Helper Methods

➜ Cleaning up config/routes.rb

post("/movies", { :controller => "movies", :action => "create" })
Enter fullscreen mode Exit fullscreen mode
  • anywhere you see the old Hash syntax (:symbol keys with hash rockets =>): switch to the new Hash syntax. Which would be controller: "movies", action: "create"

  • next, it is always good to see how many methods are happening on this line, Raghu's convention is that is there no other methods happening, you can leave out the parentheses. so our output would look something like this get "/movies", controller: "movies", action: "create".

  • we can even go further to just take out the controller and action since it is the only method we are placing into the route. remember, the # symbol is used to indicate an Object#method, which, in this example, is MoviesController#create. which would finally leave us with something like this

get "/movies" => "movies#create"
Enter fullscreen mode Exit fullscreen mode
  • for special circumstances like when you are wanting to display the root page of the website, rails has special syntax that allows you to omit the route being displayed, so instead of # get("/", { :controller => "movies", :action => "index" }), you would write it as this root "movies#index".

➜ Route helper methods

  • at the bash prompt, run rails routes. the display should look like something similar to this
Prefix Verb   URI Pattern                                Controller#Action
            GET    /                                         movies#index
    movies POST   /movies(.:format)                          movies#create
movies_new GET    /movies/new(.:format)                      movies#new
            GET    /movies(.:format)                         movies#index
            GET    /movies/:id(.:format)                     movies#show
            PATCH  /movies/:id(.:format)                     movies#update
            GET    /movies/:id/edit(.:format)                movies#edit
            DELETE /movies/:id(.:format)                     movies#destroy
Enter fullscreen mode Exit fullscreen mode
  • Prefix means that Rails has defined a method that we can call anywhere in our view templates, controller actions, etc., that will return the path as a string.

  • to test out what exactly this code is doing, move over to the index.html.erb page, type in <%= movies_path %>, and see what the page renders. you can see that it is displaying the string "/movies". if we were to try others, we can see that <%= movies_new_path %> refresh the change, and /movies renders "/movies/new". Following this pattern, <%= root_path %> just renders "/".

  • movies and movies_new are static routes, without dynamic ID numbers in the path, so Rails just puts the segments together and gives you the method. But, for all the rest of the routes that do contain :id, there are no methods defined yet. We get to define those methods ourselves!

    ➜ Creating our own route helper methods

get "/movies/:id" => "movies#show", get "/movies/:id" => "movies#show", as: :details
Enter fullscreen mode Exit fullscreen mode
  • say for the one above, "/movies/:id" has :id within the route, so we have to properly define it after the route, just like we are doing above, the as: :details part of the route is us defining a specific method, we can then transition back into the index.html.erb file and define our route like so <%= details_path %>.

  • if we see what this provides us with it will be an error No route matches {:action=>"show", :controller=>"movies"}, missing required keys: {:id}. this is because it is a dynamic route, so rails cant produce a route unless you tell it what to put in the path!

  • say if we were to put (42) within this ruby syntax helper method, it would be able to display the route with the :id being (42).

  • you can also change the embedded ruby method to details_url(42), then you will be able to see the full url of the app, including the path, this allows you to see fully qualified url's. this means you dont need to hardcode anything because it will be able to full run on any persons own personal web browser.

  • now we are going to be placing them into the normal conventions that every ruby developers use. such as

get "/movies/new" => "movies#new", as: :new_movie
get "/movies/:id/edit" => "movies#edit", as: :edit_movie
Enter fullscreen mode Exit fullscreen mode
  • we however dont need to define the helper methods for delete or patch
patch "/movies/:id" => "movies#update"
delete "/movies/:id" => "movies#destroy"
Enter fullscreen mode Exit fullscreen mode

➜ implementing helper methods

  • Now we are going to be taking those helper methods and placing them into the rest of our code, so these are going to work the same way as routes, where instead of having the routes path and then placing the variable into it with ruby <%= a_movie.id %> like this, we will change it to something like below...
<form action="<%= movie_path(@the_movie.id) %>" method="post" data-turbo="false">
  <input name="authenticity_token" value="<%= form_authenticity_token %>" type="hidden">
Enter fullscreen mode Exit fullscreen mode
  • another point, since we are taking the specific movie id for the route, we can use ruby convention and just always assume that that is what it will naturally grab specifically unless we say otherwise action="<%= movie_path(@the_movie) %>"

  • say we are implementing them into our controllers for redirection, for this piece of code for example...

if @the_movie.valid?
      @the_movie.save
      redirect_to("/movies", { :notice => "Movie created successfully." })
    else
      render template: "movies/new"
    end
Enter fullscreen mode Exit fullscreen mode
  • we can instead change "/movies" to movies_url, since we want to specifically route them to a url and not use the path name /movies

➜ Creating forms with helper methods

<%= form_with(url: movies_path) do %>
  <div>
    <!--    <label for="title_box">
      Title
    </label>-->
    <%= label_tag :title_box, "Title" %>
    <!--<input type="text" id="title_box" name="query_title" value="<%#= @the_movie.title %>">-->
    <%= text_field_tag :query_title, @the_movie.title, { id: "title_box" } %>
  </div>

  <div>
    <!--<label for="description_box">
      Description
    </label>-->
    <%= label_tag :description_box, "Description" %>
<!--    <textarea id="description_box" name="query_description" rows="3"><%#= @the_movie.description %></textarea>\ -->
    <%= text_area_tag :query_description, @the_movie.description, id: "description_box", rows: 3 %>
  </div>    

 <!-- <button>
    Create Movie
  </button>-->
    <%= button_tag "Button"%>
<% end %>
Enter fullscreen mode Exit fullscreen mode
  • here you can see the before and after of placing in tags to our forms, and below is a much more organized way to look at it
<%= form_with(url: movies_path) do %>
  <div>
    <%= label_tag :title_box, "Title" %>
    <%= text_field_tag :query_title, @the_movie.title, { id: "title_box" } %>
  </div>

  <div>
    <%= label_tag :description_box, "Description" %>
    <%= text_area_tag :query_description, @the_movie.description, id: "description_box", rows: 3 %>
  </div>    

    <%= button_tag "Button"%>
<% end %>
Enter fullscreen mode Exit fullscreen mode

find_by method

  • what we have been practicing before has led us to this moment where we will be totally deducing our 3 steps to get an ActiveRecord instance (a single row of a table, compared to an ActiveRecord:Relation (which is many rows of a table.

  • in the beginning of learning ruby, we had something very similar to this setup in our code...

def show
    the_id = params.fetch(:id) # FIRST we get the ID

    matching_movies = Movie.where(id: the_id) # THEN we get the set of matching rows (ActiveRecord:Relation)

    @the_movie = matching_movies.first # FINALLY we get one instance of ActiveRecord, or one row
  end
Enter fullscreen mode Exit fullscreen mode
  • now we are presented with something very similar to this, essentially reducing whatever we started with to a more simplified version, such as this...
def show
    @the_movie = Movie.where(id: params.fetch(:id)).first
  end
Enter fullscreen mode Exit fullscreen mode
  • now, finally we are going to be stripping that even more to a better more conventional version of this piece of code, something using the .find_by method. it is essentially the same thing as where, except that is automatically returns the .first record given in a collection without having to explicitly say that.
  def show
    @the_movie = Movie.find_by(id: params.fetch(:id)) 
  end
Enter fullscreen mode Exit fullscreen mode

or shorter

def show
    @the_movie = Movie.find(params.fetch(:id))
  end
Enter fullscreen mode Exit fullscreen mode

important to note here that the .find() method only takes an integer argument and is specifically for finding ID's in the ID column table

  • now we can accurately and effectively search for what we need without using lines and lines of code as we were doing before.

➜ Creating a checkbox form

getting an array with checkbox

<form>
  <label>Red</label>
   <input type="checkbox" name="zebra[]" value="red"> 

  <label>Blue</label>
  <input type="checkbox" name="zebra[]" value="blue"> 
</form> 
Enter fullscreen mode Exit fullscreen mode

output looks something like this

zebra["red", "blue"]
Enter fullscreen mode Exit fullscreen mode

getting an array with hashes with checkbox

<form>
  <label>Red</label>
   <input type="checkbox" name="zebra[giraffe]" value="red"> 

  <label>Blue</label>
  <input type="checkbox" name="zebra[elephant]" value="blue"> 
</form> 
Enter fullscreen mode Exit fullscreen mode

output looks something like this

zebra["giraffe" => "red", "elephant" => "blue"]
Enter fullscreen mode Exit fullscreen mode

➜ Mass assignment with forms

<%= form_with(model: @movie, data: { turbo: false }) do |form| %>
  <div>
    <%= form.label :title %>

    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :description %>

    <%= form.text_area :description, { rows: 3 } %>
  </div>

  <%= form.button %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

➜ Adding method

  • This movie_params is a good tool to understand and takes away the need to write in a new table over and over again when making it cause you would just add it in one place and then it could be added everywhere.
def movie_params
    params.require(:movie).permit(:title, :description, :image_url, :director_id)
  end
Enter fullscreen mode Exit fullscreen mode

➜ partial view templates

  • You can only add a partial to a big, not a big to a big or a big to a partial. this helps up organize our code into more folders and shorter lines so we are not overwhelmed by how many lines could be for each page.
<%= render "shared/flash_messages", locals: { person: "Alice" }%>
Enter fullscreen mode Exit fullscreen mode

Image description

  • could be good for explaining name for each user in the top corner

  • in the file youre displaying

<%= render partial: "movies/form", locals: { foo: @the_movie} %>
Enter fullscreen mode Exit fullscreen mode
  • in the partial
<% foo.errors.full_messages.each do |message| %>
  <p style="color: red;"><%= message %></p>
<% end %>
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
marywebby
Mary Webby

Posted on March 1, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related