Skip to content

In-line editing that's efficient with markup and requests

License

Notifications You must be signed in to change notification settings

kobsy/freight_train

 
 

Repository files navigation

FreightTrain

FreightTrain is a full-stack DSL for representing collections that can be edited inline.

FreightTrain is especially useful for:

  • Rendering light-weight models as lists or tables
  • Enabling users to create, update, and destroy objects with AJAX calls
  • Editing objects' attributes using JavaScript without sending a request to the server

Installation

For Rails 3:

rails plugin install git://github.com/boblail/freight_train.git

The path assets\javascripts\freight_train contains JavaScripts that should be copied to your public path. I recommend symlinking the folder like this:

cd public/javascripts; ln -s ../../vendor/plugins/freight_train/assets/javascripts/freight_train freight_train 

For Rails 2:

Rails 2 support has been deprecated from the master branch. To use FreightTrain with Rails 2, see the rails2 branch.

Getting Started

Creating a sample application

Let's say we're creating a simple to-do list application:

rails new to-do-list
cd to-do-list
rails generate scaffold ToDoItem description:string
rake db:create db:migrate
rails server

You should be able to see the scaffolded app at http://localhost:3000/to_do_items. Add a few items so we can play with them later.

Using FreightTrain

Now let's see what FreightTrain can do. Install the plugin as described above. Then add include FreightTrain to your ApplicationController and <%= include_freight_train :adapter => :prototype %> to your layout. Mine now look like this:

controllers/application_controller.rb:

class ApplicationController < ActionController::Base
  include FreightTrain
  protect_from_forgery
end 

views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<head>
  <title>TestApp</title>
  <%= stylesheet_link_tag :all %>
  <%= javascript_include_tag :defaults %>
  <%= csrf_meta_tag %>
</head>
<body>

<%= yield %>

<%= include_freight_train :adapter => :prototype %>
</body>
</html>

(Note that I set :adapter => :prototype. If you are using jQuery, just set that to :adapter => :jquery.)

Now, open app/views/to_do_items/index.html.erb and replace the <table> tag and everything inside it with <% table_for :to_do_items %>:

views/to_do_items/index.html.erb:

<h1>Listing to_do_items</h1>
<% table_for :to_do_items %>
<br />
<%= link_to 'New to_do_item', new_to_do_item_path %>

The table_for command sets FreightTrain to work with the collection we've supplied, :to_do_items. FreightTrain will generate everything you need to list, edit, and delete the items belonging to that collection. But we need to tell FreightTrain how we'd like each item to be rendered. We do this by creating a partial for named to_do_item:

views/to_do_items/_to_do_item.html.erb:

<% row_for to_do_item do |row| %>
  <%= row.text_of :description %>
<% end %>

Re-launch your server and you should see a simple one-column table that lists each item you've created.

Editing and Deleting in FreightTrain

To make FreightTrain interactive, we first need to set up our controller so that it lets FreightTrain respond to AJAX calls. To do this we add uses_freight_train to any controller that will use FreightTrain. This method causes the controller to use FreightTrain's Responder (For more information about Responders in Rails 3, read Default RESTful Rendering by Ryan Daigle on EdgeRails.)

Your scaffold-generated controller will need to be refactored to use the new responds_with convention:

controllers/to_do_items_controller:

class ToDoItemsController < ApplicationController
  uses_freight_train
  respond_to :html

  def index
    @to_do_items = ToDoItem.all
    respond_with @to_do_items
  end

  def new
    @to_do_item = ToDoItem.new
    respond_with @to_do_item
  end

  def create
    @to_do_item = ToDoItem.new(params[:to_do_item])
    @to_do_item.save
    respond_with @to_do_item
  end

  def update
    @to_do_item = ToDoItem.find(params[:id])
    @to_do_item.update_attributes(params[:to_do_item])
    respond_with @to_do_item
  end

  def destroy
    @to_do_item = ToDoItem.find(params[:id])
    @to_do_item.destroy
    respond_with @to_do_item
  end
end

Now, let's build an editor for our to-do list items. In index.html.erb, we'll replace <% table_for :to_do_items %> with <% table_for :to_do_items do |ft| %> which gives us more control over the table that's created:

views/to_do_items/index.html.erb:

<% table_for :to_do_items do |ft| %>
  <% ft.headings do %>
    <th>Description</th>
  <% end %>
  <%= ft.editor do |editor| %>
    <td><%= editor.text_field :description %></td>
  <% end %>
<% end %>

Finally, FreightTrain supplies a JavaScript helper method to facilitate deleting records. That method is named FT.#{Model Name}.destroy (in our case FT.ToDoItem.destroy) and it accepts the id of the object to destroy. You can call this method manually, or use a FreightTrain convenience parameter to scaffold a delete link. To scaffold the link, add :commands => [:delete] to row_for:

views/to_do_items/_to_do_item.html.erb:

<% row_for to_do_item, :commands => [:delete] do |row| %>
  <%= row.text_of :description %>
<% end %>

Events

When FreightTrain's Responder creates, updates, or destroys a record, it fires an event: ft:create, ft:update, and ft:destroy respectively. ft:create and ft:update are fired from the row affected.

To use these events to highlight the changes that have been made to the page, add this code to the bottom of your layout (assuming you're using Prototype):

<script type="text/javascript">
  document.observe('dom:loaded', function(){
    document.body.observe('ft:update', function(event){
      var element = event.element();
      if(element) {
        element.highlight();
      }
    });
  });
</script>

Where to go from here

The FreightTrain contains a sample app at ./test/test_app which demonstrates a few more features than Getting Started covered.

Running the Tests

To run FreightTrain's tests, do

cd test/test_app
bundle install
bundle exec cucumber

Contributing

Pull requests are welcome!

About

In-line editing that's efficient with markup and requests

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 64.6%
  • JavaScript 27.3%
  • HTML 4.0%
  • Gherkin 3.1%
  • CSS 1.0%