This workshop is important because:
Rails provides a ton of helper methods to make it easier to write code, but it can take a long time to learn them all. In this workshop, we'll look at a few important helpers that every Rails app should take advantage of.
After this lesson, developers will be able to:
- Recognize Rails path helpers and URL helpers.
- Explain benefits of using Rails form helpers and link helpers, and determine correct syntax for them.
Before this workshop, developers should already be able to:
- Start a Rails app with a route and controller for a home page view.
- Incorporate routes, a controller, and a model for a single resource.
- Read and write routes.
Rails adds helper methods that return the paths for routes in your app. These are configured through the config/routes.rb
file.
Here's some rails routes
output:
$ rails routes
Prefix Verb URI Pattern Controller#Action
turkeys GET /turkeys(.:format) turkeys#index
POST /turkeys(.:format) turkeys#create
new_turkey GET /turkeys/new(.:format) turkeys#new
edit_turkey GET /turkeys/:id/edit(.:format) turkeys#edit
turkey GET /turkeys/:id(.:format) turkeys#show
PATCH /turkeys/:id(.:format) turkeys#update
PUT /turkeys/:id(.:format) turkeys#update
DELETE /turkeys/:id(.:format) turkeys#destroy
The Prefix column on the left helps us see the available URL and path helpers.
Based on the turkeys
prefix from the first row, we can tell that a turkeys_path
helper exists. This method will return the path that corresponds to the index route for all turkeys ('/turkeys
).
Looking further down the line, we can see following helpers exist: new_turkey_path
, edit_turkey_path
, turkey_path
.
In the URI Pattern column, we can see that some of those paths require an id. For those routes, we'll pass an argument to the helper so it can fill in the :id
portion of the path.
# examples
turkey_path(12) returns "turkeys/12/edit"
turkey_path(@turkey) returns "turkeys/#{@turkey.id}"
You can set individual route prefixes by using as:
in your routes.
# inside config/routes.rb
get 'posts/new', to: 'posts#new', as: 'new_post'
The turkeys output from above used resources
in the route configuration, so the Rails auto-generated prefixes for many of the routes. It's good practice to stick to these prefixes when possible even if you're writing out routes by hand instead of using resources
.
# inside config/routes.rb
resources :turkeys
There are also URL helpers that use the same prefixes to generate a full URL instead of just the path part. For instance, turkeys_url
. See the Rails Routing Guide Path and URL helpers section.
Everywhere you want a link or a redirect in your app!
Here's part of a posts#create
action:
# inside app/controllers/PostsController.rb
def create
# create a post with params from client and save to post variable
# THEN ...
redirect_to "/posts/#{post.id}"
end
The method will create a post then redirect to that post's show page (or try to - there's no error handling!).
Instead of writing out redirect_to "/posts/#{post.id}"
, we should take advantage of the post_path
helper:
redirect_to post_path(post.id)
Rails can pull out the id for us.
redirect_to post_path(post)
There's also an even shorter syntax!
redirect_to post
Rails provides a huge swath of helpers designed to make it more convenient to generate HTML for your views, especially HTML related to your resources. These view helpers also enforce the Rails way by automatically setting some attributes inside the HTML.
Let's start by looking at some simple and very commonly used view helpers.
Pair up. One person should silently skim the documentation for link_to
. The other should silently skim the documentation for
button_to
.
After 2 minutes, turn to your partner and explain what kind of element your method generates in the HTML and what kind of request we can expect that element to send.
As a team, list differences between link_to
and button_to
. Come up with an example of where we could use each in a blog app.
Simple link:
link_to "Profile", @profile
# => <a href="/profiles/1">Profile</a>
Setting class and id in HTML:
link_to "Articles", articles_path, id: "news", class: "article"
# => <a href="/articles" class="article" id="news">Articles</a>
Image delete button
<%= button_to "Delete Image", { action: "delete", id: @image.id },
method: :delete, data: { confirm: "Are you sure?" } %>
# => "<form method="post" action="/images/delete/1" class="button_to">
# <input type="hidden" name="_method" value="delete" />
# <input data-confirm='Are you sure?' value="Delete Image" type="submit" />
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# </form>"
Remember: run
rails routes
and look at the Prefix column to see what_path
helpers are available.
Path helper | using this path helper with link_to in erb |
---|---|
turkeys_path |
link_to "view all turkeys", turkeys_path |
new_turkey_path |
link_to "create a new turkey", new_turkey_path |
edit_turkey_path |
link_to "edit this turkey", edit_turkey @turkey |
turkey_path |
link_to "view this turkey", turkey_path @turkey |
Some browsers don't support PUT, PATCH & DELETE as form submission methods. Rails however has a work-around for this.
Rails adds a hidden input field with the name _method
. Rails sets the actual method of the form to "post" but internally changes the request type based on the hidden field before the request gets to the routes.
As we saw with button_to
, Rails can generate forms for us. There are two main kinds of helpers we can use to generate forms: FormTagHelper and FormBuilderHelper. You can read more about both in the Form Helpers Rails Guide
- FormTagHelper's
form_tag
is very general, and it's often used for method/action combinations that don't map directly to a RESTful route for one of our resources.
<%= form_tag("/search", method: "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
Generated html:
<form accept-charset="UTF-8" action="/search" method="get">
<input name="utf8" type="hidden" value="✓" />
<label for="q">Search for:</label>
<input id="q" name="q" type="text" />
<input name="commit" type="submit" value="Search" />
</form>
- FormBuilderHelper's
form_for
is intended to work with our resources and RESTful routes. It does a lot to help you pre-fill values.
<%= form_for @article, url: {action: "create"}, html: {class: "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, size: "60x12" %>
<%= f.submit "Create" %>
<% end %>
Generated html:
<form accept-charset="UTF-8" action="/articles" method="post" class="nifty_form">
<input id="article_title" name="article[title]" type="text" />
<textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
<input name="commit" type="submit" value="Create" />
</form>
We'll mostly be working with resources, so it's important to get some exposure to form_for
.
- You build up a form in ERB.
<%= form_for @article do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, size: "60x12" %>
<%= f.submit "Submit" %>
<% end %>
Inside a form builder, you'll build up a form using an object. That's the parameter in the form_for
do
... end
block. It's usually called f
.
Each line inside the form will generate a label or an input. Most of these f.____
methods take in a symbol. That symbol tells the form builder which attribute of the model is being input in that field. Looking at the form builder above, we can tell that the @article
variable has a title
attribute and a body
attribute.
- Rails uses this code to generate a form for you!
Note that when the HTML is generated, the name HTML attribute for each form input
will be a combination of the model name and the attribute symbol.
<form accept-charset="UTF-8" action="/articles" method="post">
<input id="article_title" name="article[title]" type="text" />
<textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
<input name="commit" type="submit" value="Create" />
</form>
The name HTML attribute is important to us in forms because these names become the keys in the data the client sends to the server.
- You get the data in your controller!
In Rails, we access this data in a controller through the params
hash. In the example above, the controller will receive a params
hash that looks like this:
{
'article' => {
'title' => '#whatever value the title text input had when submitted',
'body' => '#whatever value the body textarea had when submitted'
}
}
It's a best practice to use "strong parameters," which is a pattern of using built-in methods to say what format of parameters your app will accept. With the example above, we'd want to write the following in our controller code:
private
# Using a private method to encapsulate the permissible parameters
# is a good pattern since you'll be able to reuse the same
# permit list between create and update.
def article_params
params.require(:article).permit(:title, :body)
end
Rails 5.1 also added form_with
, which can be used in resource-based situations like form_for
and for more general forms like form_tag
.
Research one of the methods below, and prepare to give a 2 sentence explanation about where it is used and what it does to everyone!
csrf_meta_tags
stylesheet_link_tag
javascript_include_tag
audio_tag
image_tag
image_url
video_tag
time_ago_in_words
hidden_field
orf.hidden_field
password_field
color_field
f.label
check_box
collection_check_boxes
select
(form builder)date_field
date_select
truncate
pluralize
simple_format
number_to_human
- How can we figure out what path helpers are available?
- Why would we use
form_for
andlink_to
? - Where would you look for syntax for Rails form helpers?
- Glossary
- Rails Guides:
- API documentation:
- ActionView's FormHelper
- ActionController's
redirect_to