Oomoo

September 17, 2008

The “V” in MVC

Filed under: ajax, forms, IDE, MVC, rails, view — oomoo @ 8:42 pm

Probably one of the hardest adjustments to make when transitioning from Desktop forms development to browser-based is the endless number of code and template files that must be created and maintained just to have one working “form” (that you will now be calling a “page”). 

With a traditional desktop form, it usually isn’t hard to get your arms around all of the “players” involved in making your form work.  You may have many “layers/tiers”, but most of the pieces are probably written in the same language using the same IDE.  This is not the case when designing web pages/forms where the content for each page is spread across several files (at a minimum) each of which are probably using very different development languages and/or markup styles.  

Why have all of these “pieces” of code and/or markup all over the place?

  1. MVC (Model View Controller)
    The MVC architecture dictates separation between your data/business logic (model), your application code (controller), and the web page presented to the user (view). The “View” in “MVC” really means “a combination of all the pieces needed to create a finished page/form”. 
  2. DRY (Don’t Repeat Yourself)
    DRY is one tenet of Rails development.  It basically says “if you are copying/pasting the same code/markup into multiple files, that code/markup should be put into it’s own file which should just be pulled into the pages that need it at run-time.”  Yes, that is my own paraphrase 🙂
  3. WWW = Best Of Breed
    Web development has accelerated the pace at which tools and technologies are evolving.  We web developers love to complain about all the “disconnectedness” that exists in web-based apps, but we would really scream if some new technology came out and we had to wait a year for some company to boil out the impurities and then bloat it up so it could be “assimilated” before we could work with it (wait, I know that company…).  HTML, CSS, and JavaScript are poster-child technologies for “survival of the fittest” or should I say “survival of the most flexible but yet most simple”… nah, doesn’t have the same ring to it.

So, with just these three demands placed on us as a pre-requisite for developing a web form, it’s no wonder that we end up with so many disparate technologies and pieces all needing to converge without errors inside multiple versions of non-standard browser implementations across multiple operating systems.  Oh man, my stomach just knotted up right there… okay, Ruby and Rails to the rescue!

 

Anatomy Of A View

The following “pieces” are used to produce a single web page/form:

HTML (ERB)

The main part of a web page or “form”.  It resides in \app\views\modelname\myview.html.erb.  Many people consider this the “view”, but it is only one component of the view.  This one file actually contains many types of coding/markup/templating.

  • HTML – text, tags, tables, etc.
  • ERB – in-line Ruby including object/variable references, custom method calls, helper method calls, etc.
  • CSS – in-line style settings override external CSS stylesheet settings.
  • JavaScript – in-line JSP method calls  (can also contain JavaScript methods).
  • Images – icons, pictures, borders, backgrounds, etc. located in \public\images\
  • Flash – or Silverlight, or some other 3rd party client control.

CSS

Your cascading stylesheet(s) which control most of the presentation properties of your page/form.  You will almost always have at least one of these for each application.  It is very likely that you will have several.

  • CSS stylesheets are stored in \public\stylesheets\.
  • Which stylesheet to use is usually established in either an application-level or a controller-level Layout file like this:  
    <%= stylesheet_link_tag ‘mystyle’ %>

 

JavaScript

Your JavaScript classes/functions and 3rd party tools like Scriptaculous, Prototype, and JQuery.   Your application will usually use at least 3 JSP libraries.   Large AJAX-driven client applications can have…lots of them!

  • JavaScript code files are stored in \public\javascripts\.
  • Usually, the Layout file will include:
    <%= javascript_include_tag :defaults, :cache => true %>
    which will include the 5 most commonly used javascript libraries (including Scriptaculous and Prototype).
  • You can also specify
    <%= javascript_include_tag :all, :cache => true %>
    which will automatically include EVERY javascript file found in \public\javascripts\
  • You can also specify
    <%= javascript_include_tag ‘prototype’, ‘effects’, ‘controls’, :cache => true %>
    to control which libraries load or the order in which they are loaded.

 

Helper(s)

Helpers blur the line between a Controller and a View.  As Dave Thomas so brilliantly put it, “A helper is simply a module containing methods that assist a view.  Helper methods are output-centric.  They exist to generate HTML (or XML, or JavaScript)-a helper extends the behavior of a template.”

  • Helpers are stored in \app\controllers\helpers\ 
  • Controller-specific Helpers are named after their Controller with “_helper.rb” appended to the end.
  • The Application-wide Helper is \app\controllers\helpers\application_helper.rb

Layout(s)

A layout is kind of like an HTML/ERB fragment or snippet that gets pulled into your page template at run-time and is usually used to show data/text on the page this is generic across all views/pages for the Controller (like headers, footers, borders, etc.).   

  • All layouts are stored in \app\views\layouts\
    (defined by the constant TEMPLATE_ROOT)
  • Controller-specific layouts are named after their Controller.
  • The application-wide Layout named “application.html.erb”
  • The application-wide layout can be specified in \app\controllers\application.rb
  • Each Controller can override the application-level layout by setting the “layout” property or by passing
    :layout => ‘layouts/mylayout’
    directly in the render( ) method call.
  • You can suppress the use of any Layout by including
    :layout => false
    in the render( ) method call.

Partial

Partials are very much like Controller-level Layouts because they are HTML/ERB fragments that get pulled into your page and rendered at run-time.  The big difference is that Partials are typically used to display repetitive formatted information (like a grid with rows of records) using a code block (DO…END block).

Partials must be manually called for in your HTML/ERB file like this:
<%= render :partial => "clientlist", :locals => { :f => @f, :label_text => "Update"} %>

This will render the partial _clientlist and pass it the local variables (from the Controller) and the set the variable “label_text” to the value "Update"

Rails 2.0 introduced the ability for a Partial to have it’s own Layout.  Yes, it does seem a bit like nesting, but it is nice to have!  Now, we can do something like this in our HTML/ERB file:
<%= render :partial => "header", :Layout => ‘boxed’ :locals => { :post => @post} %>
which will pull in the Layout _boxed.html.erb, which will then pull in the Partial _header.html.erb.

  • Partials are usually used on a “per View basis” and are stored in \app\views\myview\
  • Partials are named beginning with an underscore (i.e.  _mypartial.html.erb)
  • Partial Layouts are stored in the same folder as the Partial and also begin with an underscore.
  • You can re-use a Partial Layout across your application if you store it in
    \app\views\application\

    Then, when calling the partial, just use 
    :layout => ‘layouts\mylayout’

RJS

RJS templates also blur the line between the Controller and the View.  They have access to all of the Controller objects/variables, but they also have an object reference to the current HTML “page” that is in the browser.  RJS templates allow you to infuse JavaScript into your views that is written using Rails “helper methods” (instead of actual JavaScript).  Separate RJS template files are not required (you can accomplish most of the same things with “render updates” directly in your Controller code). 

  • RSJ template files are stored in \app\views\myview
  • RJS templates are named for the Controller “Action” from which they are called with a “js.rjs” extension.
  • RJS templates are not actually “called”, if one exists, it is simply applied when the view is rendered.
  • Make sure you don’t try to name an RJS template the same thing as the View, otherwise the View gets rendered, not the RJS.

 

 

So…

I just showed you how you could easily have 7 or more separate files using 5 or more different technologies included in the 1 page you are trying to display to the user.  Hopefully, knowing is half the battle and at least the reasons “why” make a little more sense to you now.  I also gave you a fairly concise list of the places where the creation/display of a Ruby On Rails “View” can go wrong.  Using Ruby On Rails can sometimes seem like magic, and that is part of the fun.  But, you at least need to know that there “is” someone behind the curtain and try to get as familiar as you can with the plumbing because one day it will back up!

 

How To Debug

Debugging an application with hundreds of files and so many combined technologies is no small feat.  The first step is to remember that all of these “pieces” eventually get smashed back together into the HTML displayed in the browser!  So, you can view the source of the page in the browser (Using the IE Developer Toolbar in Internet Explorer, or even better, using the Firebug plugin for FireFox).

Use a full-blown IDE with a built-in debugger (like Aptana with RadRails, Steel Sapphire, Komodo, etc.)

Use the Logs!  Look at your log files, and don’t forget that you can pepper any problem code with manual log entries.

Use the IRB!  The interactive Ruby console will allow you to spy on your objects and variables as well as manipulate them in real-time.  Yes, it’s command-line Alice.

Use some of the great tools and techniques laid out in this post: Rails Guide – Debugging

 

*This post uses Rails 2.1 and Ruby 1.8.

March 11, 2008

Variables Across The MVC

Filed under: MVC — oomoo @ 1:53 pm

Here are some notes about variables, scoping, etc.

Variables in Ruby/Rails are of your fairly standard variety (local, instance, public).  There is another type called “class” or “class instance” variables that get way too much attention for the amount they are used (or not used) in most apps.  If you are learning Ruby/Rails, just ignore Class Variables for now and don’t use them. 

As with most languages/frameworks, it’s the “visibility” of variables that is important.  This is especially true with web-based applications.  Ruby is based on MVC (Model/View/Controller) architecture (see http://betterexplained.com/articles/intermediate-rails-understanding-models-views-and-controllers/ for a good MVC overview)

In the diagram shown at the website referenced above, notice that the Browse interacts with the Controller, which gets data from the Model, then passes it back using the View.

Models, View, and Controllers are just classes.  Rails hides their complexity making them seem like magic, but they are just Ruby classes.

Models        are ActiveRecord classes 
Views         are ActionView classes 
Controllers  are ActionController classes

Controllers and Views have a special arrangement though, since both of them are part of ActionPack.  This means they actually share a codebase.  (see http://ap.rubyonrails.com/ for a thorough a picture and an explanation)

…snippet…  “Action Pack splits the response to a web request into a controller part (performing the logic) and a view part (rendering a template). This two-step approach is known as an action, which will normally create, read, update, or delete (CRUD for short) some sort of model part (often backed by a database) before choosing either to render a template or redirecting to another action.   Action Pack implements these actions as public methods on Action Controllers and uses Action Views to implement the template rendering.  Some of the features, are tied to ActiveRecord, but that doesn’t mean that Action Pack depends on Active Record. Action Pack is an independent package that can be used with any sort of backend.” 

What this means for you, is that instance variables defined in a Controller are visible to any View called by that controller. 

Local Variable

      current_time = Time.now 

      If defined in a Controller, it can NOT be seen from “any” View called by the Controller. 
 

Instance Variable

      @current_time = Time.now 

      Can be seen only from “this” instance of this class

      If defined in a Controller, it can be seen from “any” View called by the Controller. 
 

Class (instance) Variable

      @@current_time = Time.now 

      Can be seen and changed from “any” instance of this class (one variable shared across all instances)

      If defined in a Controller, it can be seen from “any” View called by the Controller. 
 

Public/Global Variable

      $current_time = Time.now 

      Can be seen and changed from “anywhere” 
 
 
 

An Example 
 

\app\controllers\application.rb

$current_time = Time.now     # Global Variable  (visible everywhere) 
 
 

Controller

class OrdersController < ApplicationController

  def index

    @orders = Tblorder.find_recent_orders   # Call Model Method “find_recent_orders” 

    @filter_scope_name = “Recent Orders”   # Set Instance Variable (visible by view) 

    render :action => ‘list’     # Show the View

  end

end 
 

Model

class Order < ActiveRecord::Base 

  @filter_recent_days  = 15     # Instance Variable (NOT visible by view because this is the Model) 

  def self.find_recent_orders

                                                      # “sql” is a local variable  (not visible anywhere else)

    sql = “SELECT * FROM orders where DATEDIFF(curdate(), ordDateOrderTaken) <= “ + @filter_recent_days.to_s

  

    find_by_sql(sql)

  end

end 
 

View

<!– Most of the HTML is in \app\views\layouts\orders.rhtml –> 

<% if @orders.length == 0 then%>

  <p> No Orders Exist.</p>

<% else %>

  <% if @filter_scope_name %>     # Using Instance Variable from Controller

    <caption><%= h @filter_scope_name %></caption>

    Current Time: <%= $current_time %>     # Using Global Variable from file application.rb

  <% else %>

    <caption>Order List</caption>

  <% end %>

<% end %> 

<% for order in @orders %>

  <%= link_to order.id, :action => ‘show’ %> <br />

  <%= order.ordCustPONum %> <br />

  <%= order.ordOEM %> <br />

  <%= order.ordDescription %> <br />

  <%= order.ordModelNum %> <br />

  <%= order.ordSerialNum %> <br />

  <%= order.ordFinalDisposition %> <br />

  <%= order.ordDateOrderTaken %> <br />

<% end %> 
 
 

A Note About Controller Methods

Even though your Controller Instance Variables will be visible to your View, your Controller Methods will not.  You can get around this by placing methods that need visibility to the View in your Controller Helper (app\helpers\orders_helper.rb based on our example above). 

Manually Testing A Model/Controller

Filed under: controller, model, MVC, rails — oomoo @ 1:26 pm

One of the cool things about Rails, is that with almost no work, you can easily test your new Model/Controller combination.

*Newbie Notes

To initially test a new model-controller, put the line:  “scaffold :mymodelname”  in the controller class code (comment out any other existing code).

This allows you to test that everything is hooked up properly using full CRUD scaffolding.

(No new files are created and no coding changes are done, the scaffold is generated on-the-fly). 
 

Start InstantRails (if you are using it)

   …OR…

      Start Apache/IIS

      Start MySQL 

Start the Ruby Server

    start a “ruby console” command line session
    cd myappname
    ruby script/server
    You will see…
    => Booting Mongrel (use ‘script/server webrick’ to force WEBrick)
    ** Starting Rails with development environment… 
     

Browse the View

      http://localhost:3000/myviewname    (ex:  http://localhost:3000/order) 
 

Experiment with the Model

    Start a Ruby Console:
          cmd…  ruby script/console 
    Create a Record
          @myorder = Order.new 
          myorder.quantity = 5
          myorder.price = 5.95
          myorder.desc = ‘Just a test’
          myorder.ordtime = Time.now 
    Save a Record
          @myorder.save 
    Find a Record
          myorder = Order.find :first 
    Delete a record
          myorder.destroy 
     
     

Troubleshooting 

– ActiveRecord::StatementInvalid: Mysql::Error: Column cannot be null: INSERT INTO

    – You have fields in your table that do not allow NULL.  You will need to supply a value for them before you can save.  *scaffold handles all of this for you. 

– Internet Explorer cannot display the webpage

  • You do not have Apache/IIS started.
  • You do not have MySQL started.
  • You do not have the Ruby server started  (See “Start the Server” above). 
    Remember, your “view” webpage is trying to execute ruby scripts that reside back on the server.  Without a server component running, it cannot do anything.
  • You did not enter the address correctly in the browser (mispelled the view name).

Create A New Model/Controller

Filed under: controller, model, MVC, rails — oomoo @ 1:23 pm
These instructions use an example database table named… orders 
Model
    “ruby script/generate model order”     (Note – use the singular name “order”, not “orders”) 
    “ruby script/generate scaffold order”   (This will create BOTH the Model and Controller and will implement the basic Scaffold functionality as your base code) 
    This command also creates the following files:
             app/models/ order.rb
             test/unit/ order_test.rb
             test/fixtures/ orders.yml 

Controller

    “ruby script/generate controller order index”         (Note – use the singular name “order”, not “orders”) 
    creates…
      app/contollers/orders_controller.rb
      app/helpers/orders_controller.rb
      app/views/orders/index.rhtml
      test/functional/orders_controller_test.rb 
     

View

    Automatically created in the Controller step above. 
    To manually create
          create a folder:  app/views/orders/
          create a file:  index.rhtml  (in the new folder) 
     

Test It

  ruby script/server  (Note – Ruby command line, from the “application” folder) 

  http://localhost:3000/orders (Note – “orders” is the name of the “view folder”.  This will display the “index.rhtml” file by default)

MVC Simple Sample

Filed under: controller, model, MVC, view — oomoo @ 12:45 pm

Assumptions: 

    – MySQL Database named “mydata_development” 
    – Table named my_orders 
     
     

Point YML to correct Database: 

    – File Location:  \config\database.yml 
    development:
      adapter: mysql
      database: mydata_development
      username: root
      password:
      host: localhost 
     
     

Model for Table “my_orders”: 

    – File Location:  \app\models\my_order.rb 
    class MyOrder < Activerecord::Base 
    end 
     
     

Controller: 

    – File Location:  \app\controllers\admin\myorders_controller.rb 
    class MyordersController < ApplicationController
      #scaffold :MyOrder – uncomment to have a full on-the-fly web CRUD scaffold.
     
      def index
        @myorder = MyOrder.find :first
      end
     
      def new
        @myorder = MyOrder.new 
        @myorder.ordPK = 3
        @myorder.ordCustPONum =
      end
    end 
     
     

View: 

    – File Location:  \app\views\myorders\index.rhtml 
    <h1>MyOrder#index</h1>
    <p>Find me in app/views/myorders/index.html.erb</p> 
    <%= @myorder.ordPK %>
    <%= @myorder.ordCustPONum %> 
     

To Run: 

Blog at WordPress.com.