Posted over 2 years back at Luke Redpath - Home
RailsConf Europe was really great for the most part. There were some awesome keynote talks (sorry, “plenaryâ€) with particular highlights being Dave Thomas’ excellent closing talk (which fully deserved the standing-ovation it deserved. Kathy Sierra also gave an awesome talk on creating passionate users. Both were the most confident and professional speakers of the two days but there were many other great talks as well, especially on the Thursday.
A personal highlight was seeing how popular Dan’s UJS talk was. I’ve already spoke about the talk but I must restate how cool it was to see the main hall fill out during Friday lunchtime after Dan was asked to repeat his talk due to so many people being disappointed on the Thursday morning. Speaking of UJS, we hope to have 0.4 out soon but a combination of my lack of net access last week and the both of us being really busy means that it might be a few more weeks yet. We have fixed a good few bugs however so we might push a point release in the meantime; I haven’t decided yet.
Gavin Bell and Tom Armitage (who I’d seen give an excellent talk at LRUG) gave an interesting talk on polymorphism as a pattern in social software. I felt that perhaps their overall point got lost a little but it was interesting nonetheless. It was cool to see testing with Javascript getting a good airing by Thomas Fuchs (see my live notes on his talk) and Marcel Molina Jr. showed some useful tips and tricks for sharing and reusing RJS code. An unexpected highlight of Marcel’s talk came towards the end when DHH and Piers Cawley got into a small disagreement over the separation of concerns between models and views – for the record I think DHH was spot on and I was somewhat confused at Piers’ ranting. It was entertaining though.
<img title='My notes from Jim Weirich\'s RailsConf Europe 2006 talk - click for larger version' src='/assets/2006/9/27/werichnotes_railsconf_small.jpg' alt='Photo of notes' />
Apart from DHH’s opening address, which I’ll come to shortly, the other talk that sticks in mind was Jim Weirich’s talk. He gave a great overview on “playing safe with others†and how to write good Ruby code without unintended side-effects. I’m too lazy to write up my notes, but you can click on the image above for a larger view of my Moleskine scribblings – sorry about the dodgy handwriting!
David Heinemeier Hansson gave a great talk to kick the conference off, which was mostly about code (with all of his slides in Textmate as he didn’t have Keynote on his laptop…cool!) and I have to say that I’m finally convinced about ActiveResource and REST. Simply Helpful looked really neat as well. The one part of David’s talk that I didn’t get to see was the part he had to postpone until the core team chat later in the day (I was already on the way home for an early night by that point). I didn’t see it, but its hard not to know all about it. I’m sure you’ve all seen the photo. So what was my reaction? To be honest, disappointment.
I know David likes to make controversial statements in this way (we all remember “Fuck Youâ€). He’s one strongly opinionated guy and in many ways it can be a positive quality (one that comes across heavily in Rails). And in some ways I agree with him – just because you download a piece of open source software it doesn’t mean you are entitled to anything. You aren’t entitled to support, developers aren’t obliged to listen to your feature requests and ideas and they certainly don’t have to listen to (or deserve) unconstructive criticism and bitching. However well you thought the recent Rails security hole was handled there was no call for some of the petty bitching, moaning and whining that some people felt the need to do. Constructive criticism is fine and should be encouraged but whining helps nobody.
What I don’t agree with is David’s black and white attitude towards people. I don’t like the notion of “if you haven’t contributed back to the community then I don’t care what you have to sayâ€. Just because somebody might be new to the community or hasn’t had the time to contribute much to the community be it in the form of patches, plugins, or help on the mailing list it shouldn’t meant that they should just be ignored by default. David may well have no legal responsibility towards anybody who downloads and uses Rails – a point he has been quite clear about. But in my most humblest of opinions, when you put out a piece of open source software like Rails, promote its use and see it grow into what it has become today, with many developers and companies livelihoods depending on Rails you carry a certain degree of moral responsibility to those developers. Giving a big “fuck you†to people just because they haven’t yet made some kind of contribution back to the community is short-sighted and somewhat immature and I was disappointed not so much by the point David had to make, but the way in which he made it and had I been around for the core panel talk I’m sure I would have left with a somewhat bitter taste in the mouth.
After that last sentence it would be somewhat ironic for me to end my RailsConf thoughts on that note so let me get back to being positive. The conference was well organised (except for those shitty passes) and most of the talks were interesting. Above all else, I had a great two days and got to meet some great people. Damien, Max, Robby, David, Jarkko, James, all the guys at Aegis Media and everybody else I met over those two crazy days. It was great to meet you guys and share some beers! Here’s to RailsConf Europe 2007 – see you in Berlin!
Posted over 2 years back at Luke Redpath - Home
RailsConf Europe was really great for the most part. There were some awesome keynote talks (sorry, “plenary�) with particular highlights being Dave Thomas’ excellent closing talk (which fully deserved the standing-ovation it deserved. Kathy Sierra also gave an awesome talk on creating passionate users. Both were the most confident and professional speakers of the two days but there were many other great talks as well, especially on the Thursday.
A personal highlight was seeing how popular Dan’s UJS talk was. I’ve already spoke about the talk but I must restate how cool it was to see the main hall fill out during Friday lunchtime after Dan was asked to repeat his talk due to so many people being disappointed on the Thursday morning. Speaking of UJS, we hope to have 0.4 out soon but a combination of my lack of net access last week and the both of us being really busy means that it might be a few more weeks yet. We have fixed a good few bugs however so we might push a point release in the meantime; I haven’t decided yet.
Gavin Bell and Tom Armitage (who I’d seen give an excellent talk at LRUG) gave an interesting talk on polymorphism as a pattern in social software. I felt that perhaps their overall point got lost a little but it was interesting nonetheless. It was cool to see testing with Javascript getting a good airing by Thomas Fuchs (see my live notes on his talk) and Marcel Molina Jr. showed some useful tips and tricks for sharing and reusing RJS code. An unexpected highlight of Marcel’s talk came towards the end when DHH and Piers Cawley got into a small disagreement over the separation of concerns between models and views – for the record I think DHH was spot on and I was somewhat confused at Piers’ ranting. It was entertaining though.

Apart from DHH’s opening address, which I’ll come to shortly, the other talk that sticks in mind was Jim Weirich’s talk. He gave a great overview on “playing safe with others� and how to write good Ruby code without unintended side-effects. I’m too lazy to write up my notes, but you can click on the image above for a larger view of my Moleskine scribblings – sorry about the dodgy handwriting!
David Heinemeier Hansson gave a great talk to kick the conference off, which was mostly about code (with all of his slides in Textmate as he didn’t have Keynote on his laptop…cool!) and I have to say that I’m finally convinced about ActiveResource and REST. Simply Helpful looked really neat as well. The one part of David’s talk that I didn’t get to see was the part he had to postpone until the core team chat later in the day (I was already on the way home for an early night by that point). I didn’t see it, but its hard not to know all about it. I’m sure you’ve all seen the photo. So what was my reaction? To be honest, disappointment.
I know David likes to make controversial statements in this way (we all remember “Fuck You�). He’s one strongly opinionated guy and in many ways it can be a positive quality (one that comes across heavily in Rails). And in some ways I agree with him – just because you download a piece of open source software it doesn’t mean you are entitled to anything. You aren’t entitled to support, developers aren’t obliged to listen to your feature requests and ideas and they certainly don’t have to listen to (or deserve) unconstructive criticism and bitching. However well you thought the recent Rails security hole was handled there was no call for some of the petty bitching, moaning and whining that some people felt the need to do. Constructive criticism is fine and should be encouraged but whining helps nobody.
What I don’t agree with is David’s black and white attitude towards people. I don’t like the notion of “if you haven’t contributed back to the community then I don’t care what you have to say�. Just because somebody might be new to the community or hasn’t had the time to contribute much to the community be it in the form of patches, plugins, or help on the mailing list it shouldn’t meant that they should just be ignored by default. David may well have no legal responsibility towards anybody who downloads and uses Rails – a point he has been quite clear about. But in my most humblest of opinions, when you put out a piece of open source software like Rails, promote its use and see it grow into what it has become today, with many developers and companies livelihoods depending on Rails you carry a certain degree of moral responsibility to those developers. Giving a big “fuck you� to people just because they haven’t yet made some kind of contribution back to the community is short-sighted and somewhat immature and I was disappointed not so much by the point David had to make, but the way in which he made it and had I been around for the core panel talk I’m sure I would have left with a somewhat bitter taste in the mouth.
After that last sentence it would be somewhat ironic for me to end my RailsConf thoughts on that note so let me get back to being positive. The conference was well organised (except for those shitty passes) and most of the talks were interesting. Above all else, I had a great two days and got to meet some great people. Damien, Max, Robby, David, Jarkko, James, all the guys at Aegis Media and everybody else I met over those two crazy days. It was great to meet you guys and share some beers! Here’s to RailsConf Europe 2007 – see you in Berlin!
Posted over 2 years back at Luke Redpath - Home
I’m currently sitting in the main congress hall awaiting the start of Thomas Fuch’s presentation. As I’m sure many readers of my blog are aware, I’m a huge advocate of testing, or to be specific, good testing. However, one thing that I’ve never managed to get into is unit testing with JavaScript. I’ve never really been aware of the tools available or how well it works.
I’m going to write this post live; hopefully it won’t just come across as a mish-mash of incoherent ramblings.
- Traditional JavaScript “testing†generally revolves around <filter:jscode lang='javascript'>alert</filter>. it can be useful sometimes but it generally doesn’t offer anything interesting. Use it sparingly.
- There are many common misconceptions or attitudes towards JavaScript: “we don’t need tests for 10 lines of codeâ€; “but you can’t debug JavaScriptâ€. Wrong and wrong again. Enter unit testing for JavaScript.
- Some options exist already, such as jsunit. These have their problems, such as awkward syntax or problems with Prototype.
- Scriptaculous has its own unittest.js library. All you need to do is include the unittest.js file and an empty <filter:jscode lang='html'>div</filter> with a “testlog†HTML ID (defaults). Now you’re ready to roll with Test.Unit.Runner.
- Test.Unit.Runner looks quite similar to the standard xUnit family of testing libraries. It has the standard setup and teardown methods and a suite of assertions.
- It has some good testing functionality for dealing with effects, and time-sensitive behaviour (wait function).
- It has a basic benchmarking system too!
- Rake integration is provided through a the javascript_test plugin – it allows you to launch browsers and run your javascript unit tests through a single command: <filter:jscode lang='shell'>rake test:javascripts</filter>. It uses a WEBrick server and supports multiple browsers, including Camino, Firefox, Safari and Internet Explorer. It’s fairly trivial to add support for other browsers too. It seems to be missing the functionality to close the browser after the rake test run. Perhaps the browser definition classes could be extended to support a “close†method that is called after the test run?
- The plugin also provides a generator for generating test stub files (HTML format) in test/javascript.
- Did I mention the browser-based test runner looks pretty sweet?
- OK, here’s the killer feature so far: RSpec-style syntax, including should* style expectations and context/spec format. I’m convinced, sign me up!
- Some other hints and tips: If you aren’t using Firebug already, then start using it! It is awesome and makes debugging AJAX and general JavaScript problems a lot easier. (as an aside, its also great for debugging your behaviours when you are using UJS). There is also a tool for Safari called Drosera.
- Don’t forget your RJS templates either. RJS has some basic debugging support built-in (although this could really do with being expanded upon).
During the question and answer session, Simon Willison mentioned a tool that was part of the Dojo Toolkit that uses a command-line JavaScript interpreter to run its unit tests. It sounds interesting although I feel its a lot more useful to run the tests in the actual environment they are going to run in (i.e. the browsers). By introducing something like a separate interpreter that end-users aren’t going to be using, you are relying on that interpreter being correct.
All in all, it was a good talk and has really got me interested in unit testing with JavaScript. It’s definately something I should be doing, especially as I am so strict about testing with the rest of my code.
Finally, a word of warning for those who want to try a bit of live blogging: IRC is evil and distracting. Use with caution!
Links and useful information:
Posted over 2 years back at Luke Redpath - Home
The Decorator Pattern is a design pattern that enables you to dynamically wrap behaviour around an existing object at runtime. It is especially useful when an object can have many variables that can be combined in different ways, which in turn affect it’s behaviour.
This small, simple implementation of the decorator pattern in Ruby sums up what I love about the hottest dynamic language on the planet.
I’ll borrow a simple example from the excellent Head First Design Patterns book by Eric Freeman, Elisabeth Freeman, Kathy Sierra, and Bert Bates.
Let’s say you want to calculate the cost of a cup of coffee. You have Coffee class, which implements a cost() method. For the purposes of this example, let’s just hardcode a value:
class Coffee
def cost
2
end
end
Great. But what if we want the cost of a coffee with milk? We could have a new class:
class WhiteCoffee
def cost
2.4
end
end
OK. But now we want cream. And sprinkles. Clearly, creating new classes is going to lead to a huge number of classes in our application. It just isn’t realistic to create classes for different combinations of coffee and extras. It could get worse – what if we have different types of coffee? We would then have to have combinations of extras with each different type of coffee. It just isn’t going to work. Enter the decorator pattern. Here’s the the 8 lines of Ruby mentioned in this entry’s title:
module Decorator
def initialize(decorated)
@decorated = decorated
end
def method_missing(method, *args)
args.empty? ? @decorated.send(method) : @decorated.send(method, args)
end
end
And thats all you need. You can include this into any class you want to act as a decorator. You can then use that decorator as if it was the object it is decorating; by default all messages sent to the decorator are forwarded on to the decorated object. You can then decorate the methods you need to extend:
class Milk
include Decorator
def cost
@decorated.cost + 0.4
end
end
So how does this solve our original problem? The real power of decorators lies in the fact that they can act like the objects they are decorating. By taking this one step further, you can wrap decorators with other decorators as long as they share the same interface. By creating decorators for our different “extrasâ€, we can create coffees using a combination of decorators and get the total cost of the coffee.
class Whip
include Decorator
def cost
@decorated.cost + 0.2
end
end
class Sprinkles
include Decorator
def cost
@decorated.cost + 0.3
end
end
Whip.new(Coffee.new).cost
#=> 2.2
Sprinkles.new(Whip.new(Milk.new(Coffee.new))).cost
#=> 2.9
Of course, there’s nothing stopping us from making life easier with a few factory methods:
class CoffeeFactory
def self.latte
SteamedMilk.new(Espresso.new)
end
def self.cappuccino
Sprinkles.new(Cream.new(Milk.new(Coffee.new)))
end
end
order = Order.new
order.add(Coffee.new)
order.add(CoffeeFactory.cappuccino)
puts order.total
Due to Ruby’s highly dynamic nature, the Decorator pattern isn’t the only way of extending class functionality at runtime, however I just love how simple it is to implement the pattern in Ruby. For more information on implementing decorators in Ruby, including generic decorators and alternatives to the traditional decorator pattern, see the DecoratorPattern page at the RubyGarden.
Finally, it would be nice to maintain some kind of identity when using decorators. The RubyGarden page above has one approach. Whilst we aren’t using inheritance, it would be nice to retain one of its features:
CoffeeFactory.cappucino.kind_of? Coffee
#=> true
I can think of a few ways of extending my Decorator class to retain this functionality, but I’m gonna leave this one to the reader. Over to you.
Update: In typical Ruby-fashion, my 8 lines of code has been beaten by, well, zero lines of code by Trevor Squires. Using modules, super and extend, Trevor came up with this alternative solution, which maintains identity as well. Bow down to his Ruby-fu.
Update 2: Never one to step back from a challenge, I see Trevor’s Ruby-fu and raise him with a bit of my own. I still feel my decorator implementation carries some weight, with a nice bit of syntatic sugar:
class Milk
include Decorator
end
class Whip
include Decorator
end
class Sprinkles
include Decorator
end
# normal coffee
Coffee.new
# coffee with milk, whip and sprinkles
Coffee.with :milk, :whip, :sprinkles
The self.with method could do with being extracted into a Decoratable module but here’s a concrete implementation. Trevor’s method still has an advantage in that it maintains object identity, but I have some ideas to solve that. But alas, it is past 1am and bed beckons.
Update 3: Trevor fights back with his own self.with() implementation. Personally I prefer the Coffee.with :sym, :sym syntax over Coffee.with Module, Module syntax, but thats just personal preference. Building on his extend implementation, it eliminates the symbol to class trickery, and still maintains identity. His ‘fu is still strong.
However, there is one downside to Trevor’s method: you can only apply a decorator to an object using <filterjscode inline='true' lang='ruby'>extend</filter:jscode> once. But what if you wanted double sprinkles?
Sprinkles.new(Sprinkles.new(Coffee.new))
# or with a bit of sugar (no pun intended)
Coffee.with :sprinkles, :sprinkles
Posted over 2 years back at Cody Fauser
Geoffrey Grosenbach a.k.a. Topfunky of nuby on rails fame has launched an excellent new Rails screencast series called PeepCode.
The first episode in the series is on RJS templates. I was able to watch the screencast before its release and I was mightily impressed.
Geoffrey gives RJS a very thorough treatment from the basics of getting started all the way up to advanced concepts like collection proxies and testing RJS with ARTS.
I would highly recommend this screencast even if you're already familiar with RJS because you'll definitely learn a new trick or two. Congratulations to Geoffrey on a job well done.
Posted over 2 years back at Ajax on Rails
Ajaxified Drag Drop Tree in RoR
CASE STUDY
I m providing a very generalized use case where the tree fits in a good position. Here it is…
Consider a model Item, a controller Items. Item model is using a fabulous acts_as_tree and we are going to put a seed for Item to grow it in an ajax tree
… Ok no more non-code talk. So, lets start the code now…
==========================================================
I have also incorporated the code into a sample application which you can directly check out and try the tree yourself if you find it a
headache to add the following code in a number of described files.
So, here is the Sample Tree Application
or you can try to code yourself as…
Create a sample rails application say treeapp by running
rails treeapp
from the command prompt.
Now simply change your directiry into just created treeapp and make sure that you are in the directory treeapp
Now configure the database settings for this application by modifying the file /config/database.yml as …
development:
adapter: mysql
database: tree_dev
username: root
password: root
host: localhost
Here it simply shows that you have a mysql database named tree_dev and a user root with password root can access this database. So make sure about these settings.
From the command prompt in application root(i.e. you are in the directory treeapp) run this command to generate the model Item…
treeapp> ruby script/generate model item
Add the following code to the file app/models/itme.rb
class Item < ActiveRecord::Base
acts_as_tree
validates_presence_of :name
attr_accessor :style
def self.roots
self.find(:all, :conditions=>["parent_id = ?", 0])
end
def level
self.ancestors.size
end
end
This simply shows that you should have a table named tems in your database…
so why we havnt mentioned it earlier ?
Thats the thing which will make you feel an agile web development.
Now look at the directory db/migrateand a you will find a file named as db/migrate/001_create_items.rb
Add the following code to this file 001_create_items.rb
Here we are creating our database table and also adding some initial data to work with.
class CreateItems < ActiveRecord::Migration
def self.up
create_table "items", :force => true do |t|
t.column "name", :string
t.column "created_at", :datetime
t.column "parent_id", :integer, :default => 0, :null => false
end
%w(item1 item2 item3 item4 item5).each do |name|
parent = Item.new(:name=>name)
parent.save
Item.create(:name=>name+".1", :parent_id=>parent.id)
Item.create(:name=>name+".2", :parent_id=>parent.id)
Item.create(:name=>name+".3", :parent_id=>parent.id)
end
end
def self.down
drop_table :items
end
end
Now from the command line from the root of your application run the following command to have a table named Item in your database with some initial data.
treeapp> rake db:migrate
Before we start handling our views and controller part just have a smart small image named as drag.gif in your public/images directory that we will use as a handle to drag the nodes. So, now you can see a small image at public/images/drag.gif, cool !.
Now from the command line from the root of your application run the following command to create a controller …
treeapp> ruby script/generate controller items show
Make sure that now you have the files app/controllers/items_controller.rb and app/views/items/show.rhtml.
Add the following code in the file app/controllers/items_controller.rb
class ItemsController < ApplicationController
def show
@items = Item.find(:all)
@item = Item.find(:first)
# select according to your choice...
#this item will be selected node by default in the tree when it will first be loaded.
end
def display_clicked_item
# this action will handle the two way syncronization...all the tree nodes(items) will be linked
# to this action to show the detailed item on the left of the tree when the item is clicked
# from the tree
if request.xhr?
@item = Item.find(params[:id]) rescue nil
if @item
# the code below will render all your RJS code inline and
# u need not to have any .rjs file, isnt this interesting
render :update do |page|
page.hide "selected_item"
page.replace_html "selected_item", :partial=>"items/item", :object=>@item
page.visual_effect 'toggle_appear', "selected_item"
end
else
return render :nothing => true
end
end
end
def sort_ajax_tree
if request.xhr?
if @item = Item.find(params[:id].split("_").first) rescue nil
parent_item = Item.find(params[:parent_id])
render :update do |page|
@item.parent_id = parent_item.id
@item.save
@items=Item.find(:all)
page.replace_html "ajaxtree", :partial=>"items/ajax_tree", :object=>[@item,@items]
page.hide "selected_item"
page.replace_html "selected_item", :partial=>"items/item", :object=>@item
page.visual_effect 'toggle_appear', "selected_item"
end
else
return render :nothing => true
end
end
end
end
Add the following code in the file app/views/items/show.rhtml
<h2>Ajax Tree Application</h2>
<div id=”ajaxtree” style=”width:40%;float:left;”>
<%= render :partial=>’items/ajax_tree’, :object=>[@item,@items] %>
</div>
<div id=”selected_item”>
<%= render :partial=>’items/item’, :object=>@item %>
</div>
Add the following code in the file app/views/items/_item.rhtml
<% if @item %>
<h2>Selected Item is <%=h @item.name%> </h2>
<% else %>
Item not found
<% end %>
Add the following code in the file app/views/items/_ajax_tree.rhtml
<script type="text/javascript">
function toggleDiv()
{
Element.toggle('mytree');
Element.toggle('expanded');
Element.toggle('collapsed');
return false;
}
function showDrag()
{
var drag_images = $$('img.drag_image');
drag_images.all(function(value,index){return value.style.display='inline';});
Element.toggle('done');
Element.toggle('reorder');
return false;
}
function hideDrag()
{
var drag_images = $$('img.drag_image');
drag_images.all(function(value,index){return value.style.display='none';});
Element.toggle('done');
Element.toggle('reorder');
return false;
}
</script>
<style>
.mytree{padding:0 0 0 0px;}
.mytree li {padding:2 0 0 3px;}
.outer_tree_element{margin:0 0 0 10px;}
.inner_tree_element{margin:5px 0 0 10px;}
.mytree a{text-decoration:none; font-size:13px; color:black;}
.mytree a:hover{background-color:lightblue;}
.mytree label{font-weight:normal;}
.highlighted{background-color:lightblue;}
.normal{background-color:white;}
.drag_image{border:0px;}
</style>
<div id="mytree" class="mytree">
<% @ancestors = @item.ancestors.collect{|parent| parent.id} if @item.has_parent? %>
<% @items = Item.find(:all) %>
<%= get_tree_data(@items, 0){|n|
link_to_remote(n.name,
:url=>{:controller=>'items', :action=>'display_clicked_item', :id=>n.id},
:loading=>"Element.show('tree_indicator')",
:complete=>"Element.hide('tree_indicator')"
)}
%>
<% @items.each do |node| %>
<%= draggable_element node.id.to_s+'_tree_div',:revert=>true,:snap=>false, :handle=>"'#{node.id.to_s}_drag_image'" %>
<%= drop_receiving_element node.id.to_s+'_tree_div',
:accept=>'inner_tree_element',
:url=>{:controller=>'items',:action=>'sort_ajax_tree', :parent_id=>node.id,:id=>nil},
:loading=>"Element.show('sort_tree_indicator')",
:complete=>"Element.hide('sort_tree_indicator')"
%>
<% end %>
<%= image_tag 'indicator.gif', :id=>'tree_indicator', :style=>'display:none' %>
<%= image_tag 'indicator.gif', :id=>'sort_tree_indicator', :style=>'display:none' %>
</div>
<script type="text/javascript">
var selected_el = document.getElementById('<%=@item.id%>_tree_item');
selected_el.className='highlighted';
function toggleMyTree(id)
{
Element.toggle(id+'collapsed');
Element.toggle(id+'expanded');
Element.toggle(id+'children');
return false;
}
function toggleBackground(el)
{
// using collection proxies to change the background
var highlighted_el = $$("span.highlighted");
highlighted_el.all(function(value,index){return value.className='normal'});
el.className='highlighted';
selected_el = el;
return false;
}
function openMyTree(id)
{
Element.hide(id+'collapsed');
Element.show(id+'expanded');
Element.show(id+'children');
return false;
}
</script>
As you can see in the above file we have used some indicator and toggle images. So you will be required to have three more images in the directory public/images/.
Here is the small description about these images…
- An indicator image that will be displayed at the bottom of the tree whenever a tree node is clicked. You can select from a number of Ajax Inidicatorsavailable on the web. Select one indicator image and save in your app with the name indicator.gif. So, now make sure that you can see the image at public/images/indicator.gif
- Second, we need to have a small image with + sign. That will be used to toggle the tree. save it as public/images/collapsed.gif
- Similarly, an image with - sign. Save it as public/images/expanded.gif
We have to include the prototype and scriptaculous javascript libraries in the application.
So just manually create a layout file app/views/layouts/application.rhtml and add the following code in the file application.rhtml
<html>
<head>
<%= javascript_include_tag :defaults %>
</head>
<body>
<%= @content_for_layout %>
</body>
</html>
Now the last but the most importatnt…The recursion to obtain the tree.
Add the following code in the file app/helpers/application_helper.rb
module ApplicationHelper
def get_tree_data(tree, parent_id)
ret = "<div class='outer_tree_element' >"
tree.each do |node|
if node.parent_id == parent_id
node.style = (@ancestors and @ancestors.include?(node.id))? 'display:inline' : 'display:none'
display_expanded = (@ancestors and @ancestors.include?(node.id))? 'inline' : 'none'
display_collapsed = (@ancestors and @ancestors.include?(node.id))? 'none' : 'inline'
ret += "<div class='inner_tree_element' id='#{node.id}_tree_div'>"
if node.has_children?
ret += "<img id='#{node.id.to_s}expanded' src='/images/expanded.gif' onclick='javascript: return toggleMyTree(\"#{node.id}\"); ' style='display:#{display_expanded}; cursor:pointer;' /> "
ret += "<img style='display:#{display_collapsed}; cursor:pointer;' id='#{node.id.to_s}collapsed' src='/images/collapsed.gif' onclick='javascript: return toggleMyTree(\"#{node.id.to_s}\"); ' /> "
end
ret += " <img src='/images/drag.gif' style='cursor:move' id='#{node.id}_drag_image' align='absmiddle' class='drag_image' /> "
ret += "<span id='#{node.id}_tree_item'>"
ret += yield node
ret += "</span>"
ret += "<span id='#{node.id}children' style='#{node.style}' >"
ret += get_tree_data(node.children, node.id){|n| yield n}
ret += "</span>"
ret += "</div>"
end
end
ret += "</div>"
return ret
end
end
Now you can check the tree functionality at http://localhost:3000/items/show.. assuming that you are running your server on port 3000. njoy!!
Posted over 2 years back at Cody Fauser
First I'd like to thank the 600 or so people who bought RJS Templates for Rails in the past week.
I'd also like to thank all of the people who contacted me with their feedback and errata.
On that note, I'd like to let you know that if you have already purchased the book that you can go and download an updated, hopefully errata free, version from O'Reilly.
Posted over 2 years back at Cody Fauser
I'm happy to announce the availability of RJS Templates for Rails published by O'Reilly. Here's the intro from the book:
RJS templates are an exciting and powerful new type of template added to Rails 1.1. Unlike conventional Rails templates that generate HTML or XML, RJS templates generate JavaScript code that is executed when it is returned to the browser. This JavaScript generation allows you to perform multiple page updates in-place without a page reload using Ajax. All the JavaScript you need is generated from simple templates written in Ruby. This document helps you get acquainted with how RJS templates fit into the Rails framework and gets you started with a few easy-to-follow examples.
The book covers all aspects and features of RJS that are included in Rails 1.1. It also walks through a few examples, debugging with FireBug, and finishes off with some reference material.
I'm really happy with how the book has turned out and I think you'll really enjoy it.
Posted over 2 years back at Cody Fauser
Are you tired of debugging your RJS calls ? If you answered "yes" then it is your lucky day. Kevin Clark has created a new plugin for Rails called ARTS: Another RJS Testing System.
ARTS allows you to write assertions for your RJS calls in your functional test cases. Kevin has also created an excellent tutorial Test Driven RJS with ARTS.
What are you waiting for? Get over to Kevin's site and get started.
Posted over 2 years back at Ruby on Rails Podcast
Rick Olson explains the Rails plugin system, RJS templates, and Rails-weenie.
1 ... 4 5 6 7