Settng Up The Templates for Ruby on Rails
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
Contents |
[edit] Customizing the Template
A template can be defined as 'A master page that dictates the look and feel of the whole website.' In other words, a template contains information about the layout as well as placeholders for dynamic data, such as navigation, and menu. The definition provides us with the points on which we will be working, layout and navigation. Therefore, to customize the template of Talewiki (Talewiki is the sample website of this tutorial), we will be performing the following tasks:
- Defining the Layout
- Setting up the Navigation
Let us look into the details of each task. Defining the Layout For TaleWiki, we require two separate layouts one for the login page and the other for rest of the TaleWiki pages. The reason is that the login page is, in a way, outside the system and it does not have the menu system. Therefore, we can divide the'defining the layout' task into:
- Defining Layout for Login Page
- Defining Master Layout
The layout for the login page will be embedded within the login page itself whereas the Master Layout will be a separate RHTML file that will be included wherever we require the specific layout. So, let's get started.
[edit] Customizing the Layout of the Login Page
The layout that we are going to define for the login page will be used by the login page only. Therefore, it will not be kept in a different RHTML page. The current layout does not have a header. So the first thing we will be adding is a header. The header is an image file. Open the index.rhtml file from the app/views/users folder. The file contains the following code:
<%= form_tag :action=>'authenticate' %> <table >
<tr align="center" class="tablebody"> <td>User name:</td> <td><%= text_field("user",
"user_name",:size=>"15" ) %></td>
</tr>
<tr align="center" class="tablebody"> <td>Password:</td> <td><%= password_field("user",
"password",:size=>"17"
) %></td> </tr> <tr align="center" class="tablebody">
<td></td> <td><input type="submit" value=" LOGIN " /></td> </tr> </table>
First, enclose the page in the <body> and <html> tags so that the source will be as follows:
<html> <body> <%= form_tag :action=>'authenticate' %>
<table >
<tr align="center" class="tablebody"> <td>User name:</td> <td><%= text_field("user",
"user_name",:size=>"15" ) %></td>
</tr>
<tr align="center" class="tablebody"> <td>Password:</td> <td><%= password_field("user",
"password",:size=>"17" )
%></td> </tr> <tr align="center" class="tablebody">
<td></td> <td><input type="submit" value=" LOGIN " /></td> </tr>
</table> </body> </html>
Next, we have to add the link to the stylesheet that we will be using. RoR makes adding stylesheet reference simpler by providing the stylesheet_link_tag helper. It takes the following arguments:
- Name - It specifies the name of the stylesheet being included.
- Media - It specifies on which kind of media the page is being shown. It can be a hand held device such as a cell phone or it can be a normal browser. If you provide 'all' as value, it becomes generic for all the devices.
The name of the stylesheet is 'basic' and the media is 'all'. Before we add the stylesheet tag to the page, let us create the stylesheet. Open your favorite editor and write the following code:
BODY { background-color: #ffffff; } BODY, P, TD, OPTION, SELECT, INPUT, TEXTAREA { font-size: .98em; }
PRE { font-size: 0.9em; } BODY, P, TD, OPTION, SELECT { font-family: Arial, Helvetica, sans-serif; }
PRE, TEXTAREA { font-family: monospace; } INPUT { font-family: Arial, Helvetica, sans-serif;
} HR { }
A { text-decoration: underline; } A:link { color: #0000ff; } A:visited { color: #0000ff; } A:active {
color: #C01010; } .talewikiheader {
text-align: right; } .talewikifooter {
text-align: right; }
Save it as basic.css in the public/stylesheets folder of the talewiki folder.
If you observe, the Convention-over-Configuration principle is evident here also.
RoR looks for a stylesheet named basic.css inside the folder named public/ stylesheet. Add the stylesheet tag so that the code looks like as follows:
<html> <head>
<%= stylesheet_link_tag "basic", :media => "all" %>
</head> <body> <%= form_tag :action=>'authenticate' %>
<table >
<tr align="center" class="tablebody"> <td>User name:</td> <td><%= text_field("user",
"user_name",:size=>"15" ) %></td>
</tr>
<tr align="center" class="tablebody"> <td>Password:</td> <td><%= password_field("user",
"password",:size=>"17" )
%></td> </tr> <tr align="center" class="tablebody">
<td></td> <td><input type="submit" value=" LOGIN " /></td> </tr>
</table> </body> </html>
Coming back to the header, add an <img> tag enclosed by the div tag. Then, change the table and row/column tags so that it looks like as follows:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <head> <title>TaleWiki</title> <%= stylesheet_link_tag "basic", :media => "all" %> </head> <body>
<div class="talewikiheader"> <div align="center">
<img src="/images/talewiki.jpg" alt="[TaleWiki]"> </div> </div>
<hr> <%= form_tag :action=>'authenticate' %>
<div> <center> <table border=1><tr><td> <table border=0 cellspacing=0>
<tr> <td colspan=2 class="tabletitle"> <b>Please enter your user information</b>
</td> </tr> <tr>
<td align="right">
Username: </td> <td>
<%= text_field("user", "user_name",:size=>"15" ) %>
</td> </tr> <tr>
<td align="right">
Password: </td> <td>
<%= password_field("user", "password",:size=>"17" ) %>
</td> </tr> <tr>
<td colspan=2 align="center"> <HR> <input type="submit" value=" LOGIN " />
</td> </tr>
</table> </td></tr></table> </center> </div> <hr> <div class="talewikifooter"> </div> </body> </html>
Place talewiki.jpg in the images folder, which is directly under the talewiki folder. This image was developed specifically for the header. That completes the layout design for the login page. Let us save the index page as a layout so that we can use it to override the master layout for the index page. There is a small hitch. The layout will override the notices provided through flash. Flash is a message displayed by RoR to convey any information to the user. Do not confuse it with Adobe's flash.
So add the following statement after thebefore the
<% if @flash[:notice] %> <div id="notice"><%= @flash[:notice] %></div> <% end %> <% if @flash[:note] %> <div id="note"><%= @flash[:note] %></div> <% end %>
It checks whether the flash is a note or a notice and shows it accordingly. Next, let us create a master layout and apply it to the rest of the application.
[edit] Defining the Master Layout
We will be performing two tasks while defining the master layout. They are:
- Defining and applying the Master Layout
- Setting up the Navigation
In the master layout, we will have a placeholder for the menu, which we will replace with the menu when we set up the navigation.
[edit] Defining and Applying the Master Layout
Master layout is an RHTML file just like other layout files, with one difference. The master layout contains structure that will be common to all pages. To insert the content generated by other pages into the master layout, we will use a variable called @content_for_layout. This variable is provided by RoR. This variable contains the content/HTML generated by other pages. Wherever RoR sees the @content_for_ layout variable, it replaces the variable with the content generated by the action method that has been called most recently. You can also use the yield method instead of the @content_for_layout variable. Now let us see @content_for_ layout in action.
The layout for the pages of TaleWiki will be as follows:
To create the master layout page, open an editor and write the following code:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/> <body> <table width="778" bgcolor="#FFFFFF" height="428" border="0" cellpadding="0" cellspacing="0"> <tr> <td height="35" width="778" align="left" valign="top"> <!--header--> </td> </tr> <tr> <td width="778"> <table width="778" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="150" align="left" valign="top" bgcolor="#FFFFFF"> <!--leftmenu--> </td> <td width="478" align="left" valign="top"> <!--body--> </td> <td width="150" bgcolor="#FFFFFF" height="384" align="left" valign="top"> </td> </tr> </table> </td> </tr> </table> </body> </html>
Save the file as master.rhtml in the app/views/layouts folder. We will be customizing the highlighted tags,
or in terms of the table, we will be adding our content to the highlighted cells. Let us start with the
body where the dynamic content will be placed. Replace <! body--> with <%=@content_for_layout%> so that the code looks as follows:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/> <style
type="text/css">
body {
MARGIN: 0px; } </style> <body> <table width="778" bgcolor="#FFFFFF" height="428" border="0"
cellpadding="0" cellspacing="0">
<tr> <td height="35" width="778" align="left" valign="top"> <!--header--> </td>
</tr>
<tr> <td width="778"> <table width="778" border="0" cellpadding="0" cellspacing="0">
<tr> <td width="150" align="left" valign="top" bgcolor="#FFFFFF"> <!--leftmenu--> </td> <td width="478"
align="left" valign="top"> <%=@content_for_layout%> </td>
/tr> </table> </td>
</tr> </table> </body> </html>
Next, let us change the header. Add an <image> tag so that it refers to talewiki. jpg. The code will look
as follows after the addition of the image tag:
<html> <head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/> <style type="text/css"> body
{
MARGIN: 0px; } </style> <body> <table width="778" bgcolor="#FFFFFF" height="428" border="0"
cellpadding="0" cellspacing="0"> <tr>
<td height="35" width="778" align="left" valign="top"> <img scr= "/images/talewiki.jpg"/> </td>
</tr>
<tr> <td width="778"> <table width="778" border="0" cellpadding="0" cellspacing="0">
<tr> <td width="150" align="left" valign="top" bgcolor="#FFFFFF"> <!--leftmenu--> </td> <td width="478"
align="left" valign="top"> <%=@content_for_layout%> </td> <td width="150" bgcolor="#FFFFFF" height="384"
align="left" valign="top"> </td>
</tr> </table> </td>
</tr> </table> </body> </html>
This layout also overrides the flash notices. Therefore, we have to add the code block for showing the flash. Add the following code just before the <%=@content_for_ layout%> tag.
<% if @flash[:notice] %> <div id="notice"><%= @flash[:notice] %></div> <% end %> <% if @flash[:note] %> <div id="note"><%= @flash[:note] %></div> <% end %>
Now, we have to tell RoR to use the master layout. For that, we will have to add the layout declaration to the Controllers. Open the user_controller.rb file and place the layout declaration as follows:
class UserController < ApplicationController before_filter :check_authentic_user, :except => [:index,:authenticate] layout "master": : end
However, we do not need the master layout for the index page. So, add the render declaration in the index method so that the method looks like as follows:
def index render :layout=>'login' end
The render method controls the HTML being generated (also known as page rendering) by a particular method. One of the parameters is layout. As, we want to use the login layout, we pass the value login to the layout argument. By doing this, we have overridden the master layout for the index method.
Similarly, add the layout declaration to all the other Controllers. That completes defining the master layout step. Now, let us move on to the step of setting up the menu and navigation.
[edit] Setting up the Navigation
Navigation for a site rests solely on two things. They are the menu and internal links between the pages. Menus help the user to jump from one module to another and internal links provide access to the operations within a particular module. In addition, the internal links provide a good mechanism to control the access to certain features. Let us start with setting up the menu.
We will place the menu in the master layout, as we do not require the generation of menus dynamically. We will replace the following comment with the menu:
<tr> <td width="150" align="left" valign="top" bgcolor="#FFFFFF"> <!--leftmenu--> </td>
Open the master.rhtml file and replace <! leftmenu--> with the following code:
<tr> <td width="150" align="left" valign="top" bgcolor="#FFFFFF"> <table width="778" border="1" cellpadding="0" cellspacing="0" height="387"> <tr><td width="75" height="250"> <table width="75" border="1" cellpadding="2" cellspacing="2"> <tr> <td width="286"><a href="http://localhost:3000/role"> Roles</a></td> </tr> <tr> <td><a href="http://localhost:3000/user">Users</a></td> </tr> <tr> <td><a href="http://localhost:3000/genre">Genres</a> </td> </tr> <tr> <td><a href="http://localhost:3000/tale"> Tales</a></td> </tr> <tr> <td rowspan="6"> </td> </tr> </table> </td>
The menu is very simple. It uses a combination of <td>/<a> tags to create a menu. The menu items link up with the index page of the different modules except for the user module. The reason is that the index page of the user management module is the login page. I haven't used the link_to helper to show that in layouts, simple <a> tags will work just fine. You can try out link_to as an exercise. Next, we have to ensure that only the users with the administrator role should be able to access the user and role modules. For that we require the role of the currently logged in user. So, add the following statement to the authenticate method:
session[:role_name]=valid_user.role.name
Now, the method looks as follows:
def authenticate if request.get? render :action=> 'index' else @user = User.new(params[:user]) valid_user = @user.check_login if valid_user session[:user_id]=valid_user.id session[:user_id]=valid_user.role.name flash[:note]="Welcome "+valid_user.user_name redirect_to(:controller=>'tale',:action => "list") else flash[:notice] = "Invalid User/Password" redirect_to :action=> 'index' end end end
Next, let us surround the user and role menu items with an if statement that will check whether the user has a required role or not.
<% if session[:role_name]== 'administrator' %> <tr> <td width="286"><a href="http://localhost:3000/role"> Roles</a></td> </tr> <tr> <td><a href="http://localhost:3000/user">Users</a></td> </tr> <tr> <td><a href="http://localhost:3000/genre">Genres</a></td> </tr> <%end%>
Next, let us prevent users from accidentally deleting or modifying other users' entries. Open list.rhtml which is in app/views/tales. Surround the 'link_to 'destroy' and link_to 'Edit' tag with an if statement that checks the role of the user. It is similar to what we did for the menu items. The code will look like as follows:
<% for tale in @tales %> <tr> <% for column in Tale.content_columns %>
<td><%=h tale.send(column.name) %></td> <% end %> <td><%= link_to 'Show', :action => 'show', :id =>
tale %></td>
<%if session[:role_name]=='administrator'%> <td><%= link_to 'Edit', :action => 'edit', :id => tale %></td>
<td><%= link_to 'Destroy', { :action => 'destroy', :id => tale }, :confirm => 'Are you sure?', :method =>
:post %></td>
<%end%>
</tr> <% end %>
That completes setting up the navigation. Next, let us test the modifications we have done.
[edit] Testing the Application
The first page that we are going to test is the login page. Open the following URL in your favorite browser: http://localhost:3000/user. If you get the following screen, then the layout for the login page is working fine:
Now give the following as user name and password Username: tester Password: testing
If you get the following screen, then the master layout is working fine.
That completes the testing of the modifications. You can learn more about the layout API from the following URL: http://api.rubyonrails.org/. Look at the documentation of classes under the Action View package for more information on layouts.
[edit] Additional References
- For instructions on Installing Ruby on Rails, click here
- For instructions on Troubleshooting Rails Deployment, click here
