Thursday, November 23, 2006

Flexstore on Rails Tutorial

Flexstore on Rails Tutorial









Overview

Flexstore is a traditional
Shopping Cart application. In this tutorial,
we create two modules:


  1. The administration module is an
    internal application used to maintain the
    product database. You use the administration
    module to create, update, and delete products.
  2. The store module is a
    customer-facing application. Customers
    use the store module to browse and filter
    the product catalog.

In the administration module, we use
Rails' simple scaffolding feature to automatically
provide the default infrastructure to list, view,
create, edit, and delete products. In the store
module, we experiment with additional features:



  • Templates
  • Filtering using Ajax
  • Partial Page Templates
  • Builder Templates

  • Putting a Flex front-end on top of a
    Ruby on Rails application

This tutorial uses a MySQL database. It is assumed
that you already have MySQL up and running.


Create the Flexstore Database



  1. Create a database called "flexstore"

    Open a command prompt, navigate to the bin directory of your MySQL Server installation, and type the following command:


    mysqladmin -uroot create flexstore


    Note: Provide values for userid (-u) and password
    (-p) as appropriate if the above values don't
    match your installation.


  2. Import the data


    • Download flexstore.sql.zip here
    • Extract flexstore.sql into the bin
      directory of your MySQL Server installation
    • Type the following command to import
      the data in the flexstore database:

      mysql -uroot flexstore <
      flexstore.sql


Install Ruby and Rails



  1. Install Ruby

    • Download the Ruby installer here

    • Run the installer. Accept all
      the default settings.

  2. Install Rails

    Type the following command in the c:\ruby directory:


    gem install rails --remote --
    include-dependencies


Create the Administration module



  1. Create the flexstore application

    • Create a directory called rails in c:\
    • Type the following command in c:\rails:

      rails flexstore


  2. Configure the database for the flexstore application


    • Edit database.yml in c:\rails\flexstore\config
    • Set the database parameter to
      flexstore in the development,
      test, and production sections

  3. Create a controller for the administration
    module

    Type the following command in c:\rails\flexstore


    ruby script\generate controller Admin


  4. Create a model for the products

    Type the following command in c:\rails\flexstore:


    ruby script\generate model Product



  5. Modify the admin controller to enable Rails' scaffolding

    • Edit admin_controller.rb in c:\rails\flexstore\app\controllers
    • Modify the class as follows:


  6. Test the application

    • Start the WEBrick web server installed with Rails

      Type the following command in c:\rails\flexstore:


      ruby script\server


    • Open a browser and access the following URL:

      http://localhost:3000/admin


      Rails' scaffolding defined in the
      Admin controller automatically provides
      default actions and views to list, view,
      create, edit and delete products.
      Each of these actions and views can be overwritten.
      We overwrite the default index action in the
      next steps.



  7. Define a custom index action

    • Edit admin_controller.rb in c:\rails\flexstore\app\controllers
    • Define an index action as follows:


  8. Create the view for the index action

    • Create a file name index.rhtml in c:\rails\flexstore\app\views\admin
    • Edit index.rhtml as follows:

      <html>
      <head>
      <title>Product List</title>
      </head>
      <body>



      <table>
      <tr>
      <td>Name</td>
      <td>Price</td>
      </tr>


      <% @products.each do |product| %>
      <tr>
      <td><%= link_to product.name, :action => "show", :id => product.id %></td>
      <td align="right"><%= sprintf("$%0.2f", product.price) %></td>
      </tr>
      <% end %>
      </table>
      <p><%= link_to "Create new product", :action => "new" %></p>



      </body>
      </html>




  9. Test the application. Open a browser and access the following URL:

    http://localhost:3000/admin


  10. Validation

    • Edit product.rb in c:\rails\flexstore\app\models
    • Modify the class as follows:


  11. Test the application again. Try to add a product without a name or with a non numeric price value.

Create the Store module




  1. Deploy the product images and the flexstore stylesheet

    • Download assets.zip here.
    • Extract assets.zip in c:\rails\flexstore\public.

  2. Create a controller for the administration module

    Type the following command in c:\rails\flexstore:


    ruby script\generate controller Store


  3. Define an index action in the Store controller

    • Edit store_controller.rb in c:\rails\flexstore\app\controllers
    • Define an index action as follows:



  4. Create the view for the index action

    • Create a file name index.rhtml in c:\rails\flexstore\app\views\store
    • Edit index.rhtml as follows:

      <html>
      <head>
      <title>Flexstore on Rails</title>
      <%= stylesheet_link_tag "flexstore", :media => "all" %>
      </head>


      <body>



      <!-- begin catalog -->
      <div id="catalog">
      <% for product in @products %>


      <!-- begin thumbnail -->
      <div class="thumbnail">
      <strong><%= product.name %></strong>
      <img src="<%= product.image %>"/>
      <div>
      <font color="#CC6600"><b><%= sprintf("$%0.2f", product.price) %></b></font>
      <p>
      <%= product.camera==1?'Camera<br />':'' %>
      <%= product.video==1?'Video<br />':'' %>
      <%= product.triband==1?'Triband':'' %>
      </p>
      </div>
      </div>
      <!-- end thumbnail -->



      <% end %>
      </div>
      <!-- end catalog -->


      </body>
      </html>


  5. Test the application

    Open a browser and access the following URL:


    http://localhost:3000/store


Using Partial Page Templates


In real life, you would probably have to display product thumbnails in different parts of the application. In fact, we will need product thumbnails in the filter module described in the next section. To avoid code duplication, we will isolate the HTML fragment used to render a product thumbnail in a partial page template.




  1. Create a file named _product.rhtml (the partial page template) in c:\rails\flexstore\app\views\store
  2. Open index.rhtml in c:\rails\flexstore\app\views\store
  3. Copy the HTML fragment corresponding to the thumbnail div and paste it in _product.rhtml
  4. In index.rhtml:

    • Delete the content of the catalog
      div (both the for loop and the thumbnail div)
    • Add the following line of code as
      the sole content of the catalog div:

      <%= render(:partial => "product", :collection => @products) %>


      Because we are passing a collection (the list of products) as a parameter, the partial page template will be repeaded for each item in the collection.


  5. Test the application. The product catalog should look the same as in the previous section.

    http://localhost:3000/store



Filtering with Ajax


In this section, we provide the product
catalog with filtering capabilities to allow
the user to specify a price range. In response
to the user's selection, the product catalog is
refreshed to display the phones in the selected
price range only. For a better user experience,
the product catalog is refreshed without refreshing
the entire page. This is accomplished using Rails'
built-in support for Ajax.



  1. Add a filter action to the store controller

    • Edit store_controller.rb in c:\rails\flexstore\app\controllers
    • Define a filter action as follows:


      Notice the use of the partial page template
      to return a list of thumbnails for the products
      in the selected price range.


  2. Modify the index view to allow the user
    to enter a price range

    • Edit index.rhtml in c:\rails\flexstore\app\views\store
    • Add the following JavaScript include tag
      immediately after the stylesheet link tag

      <%= javascript_include_tag "prototype" %>



    • Add the following html fragment immediately
      before the catalog div.

      <div id="left">
      <%= form_remote_tag(:update => "right", :url => {:action => :filter}, :loading => "$('right').innerHTML=''") %>
      Select your price range:<br />
      <br />
      From:<br />
      <%= text_field_tag("from", "0") %>
      <br />
      <br />
      To:<br />
      <%= text_field_tag("to", "1000") %><br />




      <br />


      <%= submit_tag "Filter" %>


      <%= end_form_tag %>


      </div>


  3. Change the id of the catalog div to "right". This will allow the stylesheet to position the product catalog to the right of the filter panel.
  4. Test the application

    http://localhost:3000/store


Builder Templates


Using Builder templates, you can dynamically
generate XML documents. This provides an
integration point that allows other technologies
to integrate with Rails, and leverage productivity
features of the framwework. In this section,
we create a template that generates an
XML document for the product catalog.




  1. Add a productlist action to the store controller

    • Edit store_controller.rb in c:\rails\flexstore\app\controllers
    • Define a productlist action as follows:


  2. Create the builder template

    • Create a file called productlist.rxml in c:\rails\flexstore\app\views\store
    • Edit productlist.rxml as follows:
      xml.list do
      @products.each do |product|
      xml.product do
      xml.name(product.name)
      xml.description(product.name)
      xml.image(product.image)
      xml.camera(product.camera)
      xml.video(product.video)
      xml.triband(product.triband)
      xml.price(product.price, :currency => "USD")
      end
      end
      end


  3. Test the Builder template by accessing the following URL in a browser:

    http://localhost:3000/store/productlist


    You should see an XML document similar to the one below:



Putting a Flex Front-End on Top of the Rails Application


In this section, we use Flex to improve the
user experience of the product catalog. The user
interface to capture the filtering criteria is
still implemented in HTML.


The Flex-based product list uses the Builder
template created in the previous section to
retrieve the catalog data. Contrary to our
current version, the Flex-based list handles
product filtering at the client-side.
Combined with the use of rich effects and transparency,
this provides the user with smoother transitions
between selections. These transitions implement the
User Interface Design best practise of "visual continuity",
and include visual cues indicating which products
are being filtered out and filtered in.



  1. Define a flex action

    • Edit store_controller.rb in c:\rails\flexstore\app\controllers
    • Define a flex action as follows:


  2. Deploy catalog.swf (the compiled version
    of the Flex-based product catalog).

    • Download flexcatalog.zip here.
    • Extract flexcatalog.zip in c:\rails\flexstore\public

    Notes:



    • This application was built using the Flex XML-based framework. You can download the source code here.
    • The application was built with Flex 2 beta and requires Flash Player 8.5 beta 2 available here.


  3. First Cut

    In our first iteration, the user interface
    of the application remains very similiar to the
    HTML version. We simply replace the HTML-based
    product list with a Flex-based version.



    • Create a file named flex.rhtml in c:\rails\flexstore\views\store
    • Copy the code below in the flex.rhtml

      <html>
      <head>
      <title>Flexstore on Rails</title>
      <%= stylesheet_link_tag "flexstore", :media => "all" %>
      <script type="text/javascript" src="/flex/embedflash.js" ></script>
      <script type="text/javascript" src="/flex/FABridge.js" ></script>
      <script>



      function filter() {
      var from = document.getElementById("from").value;
      var to = document.getElementById("to").value;
      var flexApp = FABridge.store.root();
      flexApp.filter(from, to);
      }


      </script>
      </head>


      <body>


      <div id="left">
      Select your price range:<br />
      <br />
      From:<br />
      <input type="text" id="from" value="0"/>
      <br />
      <br />
      To:<br />
      <input type="text" id="to" value="1000"/><br />
      <br />
      <input type="submit" value="Filter" onclick="filter()"/>



      </div>


      <div id="flex">
      <script>embedFlash("flexApp", "/flex/catalog.swf", 690, 510, "bridgeName=store");</script>
      </div>


      </body>
      </html>


    • Test the application

      http://localhost:3000/store/flex


  4. Optimizing the user experience

    In this second iteration, we optimize the filtering
    experience: We use sliders (from the Yahoo UI library)
    to select the price range. The Flex-based product list
    reacts to the user's selection as the sliders are dragged.




    • Install the Yahoo sliders. Download slider.zip here, and unzip the file in c:\rails\flexstore\public.
    • Overwrite the content of flex.rhtml with the code below:

      <html>
      <head>
      <title>Flexstore on Rails</title>
      <%= stylesheet_link_tag "flexstore", :media => "all" %>
      <script type="text/javascript" src="/flex/embedflash.js" ></script>
      <script type="text/javascript" src="/flex/FABridge.js" ></script>
      <script type="text/javascript" src="/yui/YAHOO.js" ></script>
      <script type="text/javascript" src="/yui/event.js" ></script>
      <script type="text/javascript" src="/yui/dom.js" ></script>
      <script type="text/javascript" src="/yui/dragdrop.js" ></script>
      <script type="text/javascript" src="/yui/slider.js" ></script>



      <script type="text/javascript">


      var slider1, slider2;


      function init() {


      document.getElementById("camera").checked = false;
      document.getElementById("video").checked = false;
      document.getElementById("triband").checked = false;


      slider1 = YAHOO.widget.Slider.getHorizSlider("slider1", "thumb1", 0, 200, 2);
      slider1.onChange = function(offsetFromStart) {
      var newValue = offsetFromStart * 5;
      document.getElementById("value1").innerHTML = newValue;
      var flexApp = FABridge.store.root();
      flexApp.setMinimum(newValue);
      };
      slider1.onMouseUp = function() {
      var flexApp = FABridge.store.root();
      flexApp.layoutTiles();
      };
      slider2 = YAHOO.widget.Slider.getHorizSlider("slider2", "thumb2", 200, 0, 2);
      slider2.onChange = function(offsetFromStart) {
      var newValue = 1000 + offsetFromStart * 5;
      document.getElementById("value2").innerHTML = newValue;
      var flexApp = FABridge.store.root();
      flexApp.setMaximum(newValue);
      };
      slider2.onMouseUp = function() {
      var flexApp = FABridge.store.root();
      flexApp.layoutTiles();
      };
      }



      window.onload = init;


      </script>


      </head>
      <body style="margin-top:20px; margin-left:20px;">


      Select your price range:<br />
      <br />
      <div id="slider1" class="sliderBG"
      onkeypress="return handleHorizSliderKey(this, YAHOO.util.Event.getEvent(event))" >
      Minimum: Minimum: $<span id="value1" >0</span>
      amp;lt;span id="value1" >0</span>
      <div id="thumb1" class="thumb"><img id="img1" src="/yui/horizSlider.png"></div>
      </div>
      <br /><br />
      <div id="slider2" class="sliderBG"
      onkeypress="return handleHorizSliderKey(this, YAHOO.util.Event.getEvent(event))" >
      Maximum: Maximum: $<span id="value2" >1000</span>
      amp;lt;span id="value2" >1000</span>
      <div id="thumb2" class="thumb" style="left:200px"><img src="/yui/horizSlider.png"></div>
      </div>



      <br /><br />


      Select the required features<br />on your mobile device:<br />
      <br />
      <table>
      <tr><td><input type="checkbox" id="camera" onClick="var app = FABridge.store.root();app.setCamera(this.checked);"/></td><td>Camera</td></tr>
      <tr><td><input type="checkbox" id="video" onClick="var app = FABridge.store.root();app.setVideo(this.checked);"/></td><td>Video</td></tr>
      <tr><td><input type="checkbox" id="triband" onClick="var app = FABridge.store.root();app.setTriband(this.checked);"/></td><td>Triband</td></tr>
      </table>



      <div id="flex">
      <script>embedFlash("flexApp", "/flex/catalog.swf", 690, 510, "bridgeName=store");</script>
      </div>
      </body>
      </html>


    • Test the application

      http://localhost:3000/store/flex



Resources




3 comments:

Anonymous said...

Does anyone have the files this tutorial links to? His site is still down.

Anonymous said...

hello

try this link instead:

http://webddj.sys-con.com/read/223793.htm

good luck

:)

Anonymous said...

After I download a copy of Flex 2 SDK, it comes with sample of the product dB , with assets like CSS and image files.

The download files are removed, but you can retrieve same dataset from Flex 2 SDK samples - flexstore

good luck

:)

Pay Pal

Sign up for PayPal and start accepting credit card payments instantly.

Ruby Corner

Earn Money