Wednesday Sep 26, 2007
Wednesday Sep 26, 2007
The jMaki 1.0 framework, with support for Java, PHP, and Ruby, was released yesterday. Last week, Arun Gupta posted a screencast showing how to use jMaki wrappers of button and table widgets from Dojo and Yahoo frameworks in a Ruby on Rails application built using the NetBeans 6.0 Beta IDE.
With Arun's permission, I am supplying the steps to recreate a similar jMaki on Rails project. To save steps, I changed the order a bit. If you don't already have NetBeans Ruby Support, go to the Installing and Configuring Ruby Support tutorial for instructions.
mysqladmin -u root -p create rorjmakitables_developmentIf you don't need a password, omit the -p.
development: adapter: mysql database: rorjmakitables_development username: root password: root_password host: localhost
map.connect '', :controller => 'say', :action=>'table'
<%= jmaki_widget 'yahoo.button',
:value => { :label => 'Select 1',
:action => { :topic => '/jmaki/table/select',
:message => { :targetId => '1' }
}
} -%>
<%= jmaki_widget 'yahoo.button',
:value => { :label => 'Select 2',
:action => { :topic => '/jmaki/table/select',
:message => { :targetId => '2' }
}
} -%>
These buttons use the jMaki publish/subscribe mechanism to publish to the /jmaki/table/select topic, which you will program two table widgets to listen to. The table widgets will select either the first row or the second row, depending on which button is clicked. For more details on how to use publish/subscribe, see Carla Mott's Widgets Talking To Widgets blog entry.
<%= jmaki_widget 'yahoo.dataTable', :subscribe=> "/jmaki/table",
:value =>
{:columns => [
{ :label => 'Title', :id => 'title'},
{ :label => 'Author', :id => 'author'},
{ :label => 'ISBN', :id => 'isbn'},
{ :label => 'Description', :id => 'description'}
],
:rows => [
{ :id=> '1', :title => 'Book Title 1',
:author => 'Author 1', :isbn => '4412',
:description => 'A Some long description'},
{ :id => '2', :title => 'Book Title 2',
:author => 'Author 2', :isbn => '4412',
:description => 'A Some long description'}
]
}
-%>
<%= jmaki_widget 'dojo.table', :subscribe=> "/jmaki/table",
:value =>
{:columns => [
{ :label => 'Title', :id => 'title'},
{ :label => 'Author', :id => 'author'},
{ :label => 'ISBN', :id => 'isbn'},
{ :label => 'Description', :id => 'description'}
],
:rows => [
{ :id=> '1', :title => 'Book Title 1',
:author => 'Author 1', :isbn => '4412',
:description => 'A Some long description'},
{ :id=> '2', :title => 'Book Title 2',
:author => 'Author 2', :isbn => '4412',
:description => 'A Some long description'}
]
}
-%>
class CreateGrids < ActiveRecord::Migration
def self.up
create_table :grids do |t|
t.column :title, :string
t.column :author, :string
t.column :isbn, :string
t.column :description, :string
end
Grid.create(:title=> 'Marathon',
:author=> 'Jeff Galloway',
:isbn=> '0936070250',
:description => 'A running book for everybody');
Grid.create(:title=> 'The Runners Bible',
:author=> 'Marc Bloom',
:isbn=> '0385188749',
:description => 'How to train, race, and get in shape');
end
def self.down
drop_table :grids
end
end
class SayController < ApplicationController
def index
table
render :action => 'table'
end
def table
@rows_data = []
Grid.find_all().each do |data|
@rows_data << { :id => data.id,
:title => data.title,
:author => data.author,
:isbn => data.isbn,
:description => data.description
}
end
end
end
The above code defines the rows_data variable and initializes it to an empty array. It uses the active record to find all the rows from the database and, for each row, add a hash of the fields to the rows_data array.
<%= jmaki_widget 'dojo.table',
:value =>
{:columns => [
{ :label => 'Title', :id => 'title'},
{ :label =>'Author', :id => 'author'},
{ :label => 'ISBN', :id => 'isbn'},
{ :label => 'Description', :id => 'description'}
],
:rows => @rows_data
}
-%>
<%= jmaki_widget 'yahoo.dataTable',
:value =>
{:columns => [
{ :label => 'Title', :id => 'title'},
{ :label => 'Author', :id => 'author'},
{ :label => 'ISBN', :id => 'isbn'},
{ :label => 'Description', :id => 'description'}
],
:rows => @rows_data
}
-%>
There you have it! To learn more about jMaki, go to www.jmaki.com. To learn more about NetBeans support for Ruby, go to wiki.netbeans.org/wiki/view/Ruby.
Thursday Sep 20, 2007
Netbeans Beta 1 was released Monday, and you can download a version of the IDE that contains Ruby support from the NetBeans IDE 6.0 Download Page. A good resource to help you get started is the new tutorial Installing and Configuring Ruby Support. This tutorial provides everything you need to know from downloading, installing, and configuring Ruby support, to working with databases, to deploying a JRuby application to Glassfish.
If you are creating Ruby on Rails applications, we have another new tutorial in that area, Building Relationships Between Rails Models. This tutorials enhances the tutorial Creating a Ruby Weblog in 10 Minutes. by enabling readers to add comments to a blog post. In particular, the new tutorial describes how to create a one-to-one and a one-to-many relationship between models in a NetBeans Ruby on Rails project.
If you are interested in contributing to NetBeans Ruby, please consider joining the Ruby mailing lists: dev@ruby.netbeans.org, used to discuss development of the Ruby features for NetBeans, and users@ruby.netbeans.org, for general support and discussions of NetBeans Ruby. To subscribe to and participate in the aliases, please visit the Mailing List page.
Monday Sep 17, 2007
Last week, Arun Gupta paid a visit to the NetBeans Ruby writers. It was great to finally meet this dynamo in person and find out what a nice guy he is. When we first started writing about NetBeans Ruby, we used Arun's blog Miles to Go as one of our resources to quickly learn about the technology. Arun tells us that the blog's name has a double meaning: he is both an avid runner and he feels like he has a lot to learn in his job.
In addition to Ruby/JRuby and GlassFish, Arun blogs on a variety of topics, including jMaki, web services, WSIT, Ajax, and Web 2.0. Arun somehow manages to be one of the first to write about how to use emerging technologies, so we like to keep an eye on his blog to find out what we will be writing about in the future. For example, last Friday, he blogged about a new GlassFish gem for Rails. We also like to follow his popular "Tip of the Day" entries. You will often see his information folded into our tutorials. Arun seems to really understand his audience's information needs and he has been very helpful by providing good suggestions as to what to include in our tutorials.
Wednesday Sep 12, 2007
There is a rumor floating around that the NetBeans IDE Ruby support only works for JRuby. Don't believe it. The IDE makes it very easy to use your own Ruby installation in addition to the bundled JRuby software. As a matter of fact, the first time that you open or create a Ruby project, the IDE looks on your system for other Ruby installations. If it finds any, it pops up a dialog box listing the available installations and lets you choose which one to use.
Using JRuby is just like using Ruby, and you don't have to know anything about Java to use JRuby. You can open your existing Ruby applications for development in the IDE and work with them using the IDE's features regardless of whether you have chosen to use the JRuby interpreter or your native Ruby interpreter. The one exception that I know of is that with JRuby you have to use the ActiveRecord-JDBC adapter if you are using a database server other than MySQL. However, all you have to do is to put the client driver in JRuby's lib folder, make a couple of simple changes to your database.yml, and add a snippet to your environment.rb. Tom Enebro writes about it here. The ActiveRecord-JDBC adapter works with MySQL, Postgresql, Oracle, Derby/Java DB, HQLSDB, and H2 database management systems.
One of the advantages of using JRuby is that you can access Java libraries from your Ruby application. Tor and Cindy put together a great video about this for NetBeans TV.
Another benefit is that you can war up a JRuby application and deploy it to a Java application server, such as GlassFish, just like you would with a Java web application. Arun Gupta has written several blog entries about this and the upcoming Installing and Setting Up Ruby tutorial provides step-by-step instructions for one of the simpler methods of deploying to the GlassFish server. One advantage of deploying to Java application servers is that they are designed to be multi-threaded and thus can handle more than one request at a time. In addition, Java application servers provide tools that make it easier to manage your deployed applications. For detailed information about creating and deploying JRuby applications, see the Rails Integration page on the JRuby wiki.
Monday Sep 10, 2007
Cindy Church and Tor Norbye have teamed up to create two more videos on NetBeans Ruby, this time focusing on the Ruby editor:
Also recently published is Brian Leonard's and Beth Stearns' article titled Test-Driven Rails Development. This article describes the features of the NetBeans IDE that can help you test your Ruby and Rails code.
Be sure to check out the NetBeans Ruby Wiki and let us know what docs you would like and if you have docs to contribute. The wiki is a community site, and the instructions for contributing are there.
Thursday Sep 06, 2007
I migrated the sample tutorial project that I created for the Sun Java Studio Creator IDE into a NetBeans IDE 6.0 web application that uses the Visual Web Java Server Faces framework. You can download this NetBeans IDE project from here. If the pages do not display in the Visual Designer (and you get an error page instead), do a clean build, then close and reopen the IDE.
Note that this project uses the JSF 1.4 versions of the Web UI components, and not the newer versions.
This sample project:
When you click a detail button, the button's action method uses a tableRowGroup method to get the row key for the row that the button is in. The method then uses the row key to get the value for the foodId column, which it saves in the request bean for use by the detail page.
public String showDetailBtn_action() {
// Find out what row was clicked
RowKey rowKey = tableRowGroup1.getRowKey();
// Save food id so detail page knows what food item to show
// provide detail info for
getRequestBean1().setFoodId(
getSessionBean1().getFoodListDataProvider().
getValue("foodId", rowKey).toString());
return "detail";
}
|
The checkbox column is not bound to any column in the dataprovider, but is instead bound to a page property named selected. The getter and setter use a TablePhaseListener object to manage which checkboxes are selected.
public void setSelected(Object object) {
RowKey rowKey = tableRowGroup1.getRowKey();
if (rowKey != null) {
tablePhaseListener.setSelected(rowKey, object);
}
}
/**
* Getter for selected.
* @return Object value for the current row's checkbox
*/
public Object getSelected() {
RowKey rowKey = tableRowGroup1.getRowKey();
return tablePhaseListener.getSelected(rowKey);
}
|
Winston explains how to do this as well as how to highlight the rows that are selected in his How to Create Muli-Row Selectable Table Component blog.
To calculate calories, the Calculate Calories button's action method calls a method that iterates over the tableRowGroup object's selectedRowKeys to accumulate the total calories for the selected rows.
public String calculateCaloriesBtn_action() {
getSessionBean1().setTotalCalories(getTotalCalories());
return null;
}
public String getTotalCalories() {
int total = 0;
// Go through the list of selected rows
Integer calories;
Integer nbrServings;
FoodListDataProvider foodListDP =
getSessionBean1().getFoodListDataProvider();
RowKey[] selectedRowKeys =
getTableRowGroup1().getSelectedRowKeys();
for (int i = 0; i < selectedRowKeys.length; i++) {
String rowId = selectedRowKeys[i].getRowId();
RowKey rowKey = foodListDP.getRowKey(rowId);
// get serving size
String size = (String)
getSessionBean1().getServingSizeMap().get(rowId);
// get calories for serving size
calories = (Integer) foodListDP.getValue(size, rowKey);
// get number of servings
nbrServings = (Integer)
getSessionBean1().getNbrServingsMap().get(rowId);
// add to total
total += calories.intValue() * nbrServings.intValue();
}
return Integer.toString(total);
}
|
The Nbr Servings text field and Serving Size drop down list are also not bound to the underlying data provider. I created Map objects to store the values for each row and bound the components to session bean properties.
/**
* Getter for property nbrServings.
* @return Value of nbrServings for current row
* defaults to 1
*/
public Integer getNbrServings() {
TableRowDataProvider rowData =
(TableRowDataProvider) getBean("currentRow");
if (rowData == null) {
return new Integer(1);
} else {
String rowId =
rowData.getTableRow().getRowId();
Integer nbrServingsValue =
(Integer) this.getNbrServingsMap().get(rowId);
if (nbrServingsValue == null) {
return new Integer(1);
} else {
return nbrServingsValue;
}
}
}
/**
* Setter for nbrServings for current row
* @param nbrServings New value of nbrServings.
*/
public void setNbrServings(Integer nbrServings) {
TableRowDataProvider rowData =
(TableRowDataProvider) getBean("currentRow");
if (rowData != null) {
String rowId = rowData.getTableRow().getRowId();
this.getNbrServingsMap().put(rowId, nbrServings);
}
}
/**
* Getter for servingSize.
* @return Value servingSize for current row
* Defaults to cup
*/
public String getServingSize() {
TableRowDataProvider rowData =
(TableRowDataProvider) getBean("currentRow");
if (rowData == null) {
return "cupCalories";
} else {
String rowId = rowData.getTableRow().getRowId();
String servingSize =
(String) this.getServingSizeMap().get(rowId);
if (servingSize == null) {
return "cupCalories";
} else {
return servingSize;
}
}
}
/**
* Setter for servingSize for current row
* @param servingSize New value of property servingSize.
*/
public void setServingSize(String servingSize) {
TableRowDataProvider rowData =
(TableRowDataProvider) getBean("currentRow");
if (rowData != null) {
String rowId = rowData.getTableRow().getRowId();
this.getServingSizeMap().put(rowId, servingSize);
}
}
/**
* Holds value of property nbrServingsMap.
*/
private Map nbrServingsMap = new HashMap();
/**
* Getter for property nbrServingsMap.
* @return Value of property nbrServingsMap.
*/
public Map getNbrServingsMap() {
return this.nbrServingsMap;
}
/**
* Setter for property nbrServingsMap.
* @param nbrServingsMap New value of property nbrServingsMap.
*/
public void setNbrServingsMap(Map nbrServingsMap) {
this.nbrServingsMap = nbrServingsMap;
}
/**
* Holds value of property servingSizeMap.
*/
private Map servingSizeMap = new HashMap();
/**
* Getter for property servingSizeMap.
* @return Value of property servingSizeMap.
*/
public Map getServingSizeMap() {
return this.servingSizeMap;
}
/**
* Setter for property servingSizeMap.
* @param servingSizeMap New value of property servingSizeMap.
*/
public void setServingSizeMap(Map servingSizeMap) {
this.servingSizeMap = servingSizeMap;
}
|