2.7 Render HTML
We’ve written our first functional action, which just redirects someone to a new page. Now let’s render some of our own HTML.
Change the previous code in app/controllers/application_controller.rb
to:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
false)
layout(
# Add your actions below this line
# ================================
def play_rock
# write your code here
# redirect_to("https://www.wikipedia.org")
:plain => "Hello, world!" })
render({ end
end
{: mark_lines=“12-14”}
Rather than redirect_to
, we’ll use another inherited method to complete the request lifecycle: render
.
This method, takes a Hash
as an argument with a key/value pair. The key has many options, here we use :plain
, which will just send back plain text. A boring response, but good to start with.
Now, pretend you’re a user and visit /rock in the GitPod browser. You should see a mostly empty page with the text “Hello, world!” rendered.
Congratulations! You’ve wired up a route; prepare to do it a million more times, because all developers do all day is pick the next spec, wire up the route for the URL so that a user can visit it, and then implement the logic to send back the correct information.
Remember, we did not create and send a file, we are using Ruby to generate this reponse, opening a world of possibilities. For instance, what if we instead rendered a random number:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
false)
layout(
# Add your actions below this line
# ================================
def play_rock
# write your code here
# redirect_to("https://www.wikipedia.org")
:plain => rand(100) })
render({ end
end
{: mark_lines=“14”}
Now everytime we refresh /rock, we get a different random number, generated automatically by Ruby. This is a dynamic response, not just a static page that we placed in the public/
folder. This is a simple example, but fundamentally that’s it. We connected a URL to a method that can do anything. It can call APIs, parse CSVs, compute whatever we want, run machine learning models, etc. Of course, there is a lot more to learn, but fundamentally this is it.
Now let’s send back some actual HTML:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
false)
layout(
# Add your actions below this line
# ================================
def play_rock
# write your code here
# redirect_to("https://www.wikipedia.org")
:html => "<h1>Hellow, world!</h1>".html_safe })
render({ end
end
{: mark_lines=“14”}
The :html
key allows us to place whatever HTML we want in a String
that will be shown on the page. We need the .html_safe
on the end of the String
. Don’t worry about this
Okay, if you really want to know, .html_safe
is a bit of Rails security to prevent one user from injecting malicious HTML into another user’s browser, in case we were getting the given HTML String
from the user (e.g. from a <form>
)., we will see a better way in a moment.
If we refresh /rock, then we should see our rendered HTML. We could go crazy and put our entire HTML document in that String
. But a much better way is to use an embedded Ruby template file.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
false)
layout(
# Add your actions below this line
# ================================
def play_rock
# write your code here
# redirect_to("https://www.wikipedia.org")
# render({ :html => "<h1>Hellow, world!</h1>".html_safe })
:template => "game_templates/user_rock.html.erb" })
render({ end
end
{: mark_lines=“16”}
The :template
key to render
lets us assign a view template. We specify the name of a folder game_templates/
and file user_rock.html.erb
that will contain all of our HTML. This file is an .html.erb
, for embedded Ruby template, rather than a plain .html
file.
We can now create this file in the existing app/views/
folder. All of our application view templates will go here. It is far safer folder than public/
, because users do not have access to its contents, and cannot modify the source code.
We want to keep things organized and put different templates in different sub-folders. Do not put the .html.erb
file in the app/views/layouts/
folder that already exists.
First make a new folder in app/views/
by right-clicking on the folder and selecting “New Folder…”, then naming the folder game_templates
. Then, right-click on this new folder, select “New File…”, and create user_rock.html.erb
. The entire filepath will look like app/views/game_templates/user_rock.html.erb
.
BENP: insert gif of create new folder and create new file steps in GitPod
By using :template =>
in render
, Rails knows to look in app/views/
. We could call the game_templates/user_rock.html.erb
folder and file whatever we want. The user will not see the folder or the file, they will only see /rock, the specified route, in their browser.
Open the newly created user_rock.html.erb
file and add some HTML to render:
<!-- app/views/game_templates/user_rock.html.erb -->
<h2>We played rock!</h2>
Don’t forget to save the file changes if you haven’t done so.
And now when we refresh /rock, we get the text from our new file rendered in HTML.
After all of that, we have an HTML page that does what we could have done quickly if we made a file called rock.html
in the public/
folder. But we can do something way better with this new system.
2.7.1 Completed Code
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
false)
layout(
# Add your actions below this line
# ================================
def play_rock
# write your code here
# redirect_to("https://www.wikipedia.org")
# render({ :html => "<h1>Hellow, world!</h1>".html_safe })
:template => "game_templates/user_rock.html.erb" })
render({ end
end
<!-- app/views/game_templates/user_rock.html.erb -->
<h2>We played rock!</h2>