5.3. View TemplatesPhoto Share is supposed to be a web application for storing photos, but so far the scaffolding shows only boring filenames. To make that change, we'll work with view templates and controllers. Edit the file app/views/photos/show. rhtml , which is the view template created by the scaffold generator. If you have used template languages like ASP or JSP [*] before, you will recognize the syntax for embedding executable code within the HTML template. In this case, Rails is using the ERb (Embedded Ruby) template system for embedding Ruby code within an HTML template. As you recall, text between <% and %> is Ruby code that is executed, text between <%= and %> is a Ruby expression, and the results from executing that code is inserted into the HTML when ERb evaluates the template.
Insert this line at the beginning of app/views/photos/show.rhtml : <%= image_tag 'photos/' + @photo.filename %> This line calls the Rails helper function image_tag , which generates an HTML <img> tag for the photo's filename. By default, images are expected to be in the public/images directory of our Rails app, but the photos are in public/images/photos , so prefix the filename with photos/ . @photo contains the database record for the photos that we want to display and that was set by the photos controller: def show @photo = Photo.find(params[:id]) end Let's see how this looks. Make sure that the web server is started, browse to http://127.0.0.1:3000/photos/list, and click on the Show link for any of the pictures. Now that (Figure 5-2) is much niceran actual picture! Figure 5-2. Showing an actual photoNow that you can see the images, it's time to go back and beautify the photo/list page. Do this by including the thumbnail image in place of the filename, and make it clickable, as a link to the show page. This strategy lets you eliminate almost everything else about the photo and enables the user go to the show page to see the details. Edit app/views/photos/list.rhtml to look like this: <h1>Listing photos</h1> <table> <% for photo in @photos %> <tr> <td> <%= link_to(image_tag("photos/#{photo.thumbnail}", :size => '75x56', :border => 1), url_for(:action => 'show', :id => photo) ) %> </td> <td> <%=h photo.filename %> <br/> <%= link_to 'delete me', { :action => 'destroy', :id => photo }, :confirm => 'Are you sure?' %> </td> </tr> <% end %> </table> <%= link_to 'Previous page', { :page => @photo_pages.current.previous } if @photo_pages.current.previous %> <%= link_to 'Next page', { :page => @photo_pages.current.next } if @photo_pages.current.next %> <br /> <%= link_to 'New photo', :action => 'new' %> There is a lot going on in this code, so we will go through it in considerable detail, but first, let's just see how it looks. Browse to http://127.0.0.1:3000/photos/list; you should see something like Figure 5-3. This is starting to look halfway decent. Figure 5-3. Thumbnails in the photo listLet's examine that code in detail:
5.3.1. LayoutsYou may have noticed that the HTML pages that we created are incomplete. Rails uses a feature called layouts to let you specify a common set of display elements for every page rendered by a controller. This feature is typically useful for common headers, footers, and sidebars. By default, Rails looks in its app/view/layouts directory for an RHTML file whose name matches the controller's name . Take a look at app/views/layouts/photos.rhtml ; you should see something like this: <html> <head> <title>Photos: <%= controller.action_name %></title> <%= stylesheet_link_tag 'scaffold' %> </head> <body> <p style="color: green"><%= flash[:notice] %></p> <%= @content_for_layout %> </body> </html> This is the layout template for photos controller. The HTML output created by any action in the photos controller is inserted into the layout where you see the line: <%= @content_for_layout %> and sent back to the browser for display. The end result is a valid HTML page. Let's modify this layout to add some common links that will show at the bottom of every page. Edit app/views/layouts/photos.rhtml , and insert the following code just before the </body> tag: <div style="background-color:LightBlue"> <p> <%= link_to 'Photos', :controller => 'photos', :action => 'list' %> <%= link_to 'Categories', :controller => 'categories', :action => 'list' %> <%= link_to 'Slideshows', :controller => 'slideshows', :action => 'list' %> </p> </div> This layout displays a simple navigation bar with links to the pages that list the photos, categories, and slideshows. This navigation bar appears at the bottom of every page displayed by the photos controller. Browse to http://127.0.0.1:3000/photos/list; you should see a web page like the one in Figure 5-4. Try clicking the new photo link or any of the thumbnails, and notice that the navigation remains at the bottom of the page. Figure 5-4. Common navigation barThis navigation bar is good, but it still has a few problems. First, it appears only when you are in the photos controller. If a user clicks on the Categories or Slideshows links, the navigation will be gone. You really want the same layout to appear throughout. Second, you should move the navigation bar to the top of the page so that it doesn't seem to jump around as users move from page to page. By default, Rails looks for a layout file with the same name as the controller, which is why we added our navigation bar in the app/views/layouts/photos.rhtml file. You can also tell Rails what layout file to use. We'll do that, not directly in the various controller classes, but in the common parent class for all of the controllers. The common superclass for all of the controllers is defined in app/controllers/application.rb . Edit this file and add layout 'standard' to the class body so that it looks like this: class ApplicationController < ActionController::Base layout 'standard' end This tells Rails to use a layout named "standard" instead of the default name. And putting this in the superclass is the same as putting it in each controller individually. This approach is better, of course, because you don't have to duplicate the code, and if you add a new controller in the future, it will automatically use the same layout. Now let's create the layout template. Create app/views/layouts/standard.rhtml with the following content: <html> <head> <title>Photo Share</title> <%= stylesheet_link_tag 'scaffold' %> </head> <body> <div style="background-color:LightBlue"> <p> <%= link_to 'Photos', :controller => 'photos', :action => 'list' %> <%= link_to 'Categories', :controller => 'categories', :action => 'list' %> <%= link_to 'Slideshows', :controller => 'slideshows', :action => 'list' %> </p> </div> <p style="color: green"><%= flash[:notice] %></p> <%= @content_for_layout %> </body> </html> You probably recognize this text as pure HTML, with a few simple Ruby expressions to link to the list actions for photos, categories, and slideshows. This layout is the same as photos.rhtml , except that the navigation bar has been moved to the top of the page. Now you can click on any link, and every page in this Photo Share application will have this navigation bar at the top. We no longer need the other layout files in app/views/layouts , so delete all of them, except for standard.rhtml . |