Section 6.3. Using Drag-and-Drop to Reorder Slides


6.3. Using Drag-and-Drop to Reorder Slides

The scaffolding we have for editing a slideshow shows just the slideshow attributes that are stored directly in the slideshows table: the slideshow's name and the date on which it was created. The most important part is missing: the photos that are part of the slideshow!

By now, you've probably realized that this is because the scaffolding code deals with only one database table: the slideshows table. The relationship data about which photos are assigned to a slideshow and their order in the slideshow are stored in the slides table. Scaffolding does not handle relationships, so you have to write the code to edit this relationship data.

We're going to display a list of thumbnails of all the photos that are in a slideshow, and then let the user reorder them using drag-and-drop. If you've had to struggle through implementing drag-and-drop before, you're not going to believe how easy this is going to be. Here's a hint: this will take a total 34 additional lines of Ruby, CSS, and RHTML template!

Let's start by reviewing the current implementation of the edit action in the slideshow controller:

 def edit   @slideshow = Slideshow.find(params[:id]) end 

This action expects to find the ID of the slideshow to edit passed in as the id parameter, which is normally decoded from the URL. You find the slideshow with that ID and assign that slideshow object to the instance variable @slideshow , so that it can be accessed in the view template.

That is really all that's needed here, so you won't have to add any code to this method. The changes will start with the edit view template, so edit the template photos/app/views/slideshows/edit.rhtml and make it look like this (the changes are in bold):

 <h1>Editing slideshow</h1>  <%= link_to 'Play this Slideshow',             :action => 'show', :id => @slideshow %> <div id='slideshow-contents'>   <%= render :partial => 'show_slides_draggable' %> </div> <div id='slideshow-attributes'>  <%= start_form_tag :action => 'update', :id => @slideshow %>     <%= render :partial => 'form' %>     <%= submit_tag '  Save Attributes  ' %>   <%= end_form_tag %>  </div>  

Notice that the existing <%= render :partial => 'form' %> is wrapped in a <div> tag with an id attribute of slideshow-attributes . You will use this name in one of your CSS files to control how this section is displayed.

There is also a completely new section that displays thumbnails of the photos in the slideshow:

 <div id='slideshow-contents'>    <%= render :partial => 'show_slides_draggable' %> </div> 

This code also uses a <div> tag with an id attribute, for the same reason: to use a CSS file to control its appearance. This div also renders a new partial view template named show_slides_draggable , which we will create next .

Create the file photos/app/views/slideshows/_show_slides_draggable.rhtml with the following contents:

 <ol id='sortable_thumbs'>    <% for slide in @slideshow.slides %>       <li id='thumbs_<%= slide.id %>' class='slides'>          <%= thumbnail_tag slide %>       </li>    <% end %> </ol> <%= sortable_element('sortable_thumbs',                      :url => {:action => 'update_slide_order'}) %> 

The first part is pretty standard stuff. We're creating an HTML ordered list, in which each list item is a thumbnail image of one of the photos in the slideshow (note that the thumbnail_tag helper function that was created earlier). However, it's the last two lines that do the heavy lifting .

sortable_element is a helper function that generates the JavaScript code that turns our list into a user-sortable, drag-and-drop-capable list. It wraps this list an HTML form, and the :url option specifies the URL to post to the server whenever the user changes the order of the list. In this case, it calls the action method update_slide_order in our slideshow controller. This call works in the background using an Ajax call.

The update_slide_order method is pretty simple as well. Edit photos/app/controllers/slideshows_controller.rb , and add this method:

 def update_slide_order   params[:sortable_thumbs].each_with_index do id, position      Slide.update(id, :position => position)   end end 

This method iterates through each slide in the list, extracting its ID and position in the list, and uses this information to update that slide's database row with its new position. Let's walk through this code in a little more detail:

  • params is a hash that holds all the parameters sent to the server in the HTTP request. params[:sortable_thumbs] retrieves the parameter for the sortable_thumbs list, which is an ordered array of the IDs of each thumbnail in the list.

  • each_with_index is a Ruby iterator that, just like the each iterator, walks through the array one item at a time. But on each iteration, each_with_index passes to the code block both the object held in the array (the slide id ) and its index in the array (which is assigned to position ).

  • Slide.update(id, :position => position) then calls the Slide model class to update the slide identified by id with its new position.

We're almost ready to give it a try, but first let's edit photos/public/stylesheets/slideshows.css and add some formatting instructions for the two div IDs we created. Add the following at the end of the file:

 #slideshow-contents {    float: left;    width: 11em;    padding: 0.50em;    text-align: center;    border-right: thin solid #bbb;    padding: 0.50em;    padding-bottom: 10em; } #slideshow-attributes {    margin-left: 23em;    padding-left: 1.5em;    padding-top: 1.5em; } 

This causes the contents of the slideshow (which will be a list of thumbnail images) to be displayed down the left side of the page, and the slideshow's attributes will be displayed immediately to the right of the thumbnails.

Let's see how this looks. Browse to http://127.0.0.1:3000/slideshows/list, and click the edit link for our one and only slideshow. It will look like Figure 6-2.

Figure 6-2. A drag-and-drop list of photos

Click on one of the photos, and try dragging it around. When you drop it into a new location, update_slide_order is called to write the new order to the database.

Let's fix one minor thing here before we move on. Wouldn't it be better to see the number of each photo appear vertically aligned in the middle of the thumbnail instead of at the bottom? Because the HTML for each thumbnail image is created by our own helper function, thumbnail_tag , we just need to edit that function and add a vertical-align style attribute.

First, edit photos/app/helpers/slideshows_helper.rb , and add the code shown in bold:

 module SlideshowsHelper   def thumbnail_tag(slide)     image_tag("photos/#{slide.photo.thumbnail}",  :style=>"vertical-align:middle"  ) if slide   end end 

Now, refresh your browser: the list numbers are nicely centered, as you can see in Figure 6-3.

Figure 6-3. Nicely centered list numbers

With a very small amount of code, we added a very nice drag-and-drop user interface for reordering the slides in a slideshow. But we're just getting started with our Ajax-enabled user interface.



Ruby on Rails[c] Up and Running
Ruby on Rails[c] Up and Running
ISBN: B003D3OGCY
EAN: N/A
Year: 2006
Pages: 94

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net