XpenseTracker – Ajax based CURD with ROR and RJS

2 min read

RJS templates for Rails by OReilly is a cool book , If you want to learn how to give Ajax functionality to your website (using Rails) this is the best book to start with.
I searched for the source code of the examples given in this book but couldn’t find one, So I quickly prepared one and kept in google code as ProjectExpenseTracker. I also added few other features like Ajax based update and delete, index page and so on.

If you want to download from svn, click
http://code.google.com/p/projectexpensetracker/source/checkout
If you want to just browse the source code , click
http://code.google.com/p/projectexpensetracker/
Running the project

  1. Goto google code – svn http://code.google.com/p/projectexpensetracker/source/checkout
  2. configure db.yml to your database settings
  3. Migrate the database to current version using ‘rake db:migrate’

Now, if you are interested, here is some explanation about the project.
The index page will appear like
xpensetracker1
The main page with tables and add, update, delete functionalities
xpensetracker2
Quick explanation about the code I added/modified:
This project is too long to explain everything, so I suggest to read the book first 😉
Delete an expense item:
_item.rhtml
[sourcecode language=’ruby’]
<%= link_to_remote(image_tag('delete.gif', :border => 0, :title => ‘Delete expense’),
:confirm => “Delete selected item line?”,
:loading => ‘ExpenseTracker.disableExpenseForm()’,
:complete => ‘ExpenseTracker.enableExpenseForm()’,
:url => hash_for_expenses_url(
:project => @project,
:action => ‘destroy’,
:id=>expense.id)) %>
[/sourcecode]
Link_to_remote is an Ajax link
Image_tag is for adding icon for the delete link
:loading , when the user is making an ajax call to the server we should disable the form in order make the user send any further requests.
:complete, when the ajax call is complete we have to enable the form that we disable earlier.
Backend code for deleting the record from the database table is written in
expense_controller.rb
[sourcecode language=’ruby’]
def destroy
@delete_success = true
begin
Expense.destroy(params[:id])
flash[:notice] = “Expense item deleted successfuly”
rescue Exception => exception
#Log the exception that throwing it console.
@delete_success = false
end
end
[/sourcecode]
@delete_success variable is used in the destroy.rjs template for giving proper error message upon destroy failure.
Rjs code to show the page after deletion of record in
destroy.rjs
[sourcecode language=’ruby’]
if !@delete_success
page.alert ‘error deleting’
else
page.update_summary @project
page.update_total number_to_currency(@project.total_expenses)
page.remove(‘expense-‘+ params[:id].to_s)
page.replace_html :notice, flash[:notice ]
flash.discard
end
[/sourcecode]
Update an expense item:
See _item.rhtml, it got an Ajax link for edit
[sourcecode language=’ruby’]
<%= link_to_remote( image_tag('edit.png',:size => ’17×14′, :title => ‘Edit Expense’, :border=>0),
:url => hash_for_expenses_url(
:project => @project,
:action => ‘edit’,
:id=>expense.id)) %>
[/sourcecode]
Edit.rjs
[sourcecode language=’ruby’]
page.replace_html ‘expense-‘+ params[:id].to_s, :partial => ‘edit’
[/sourcecode]
When user clicks on edit the row will be replaced by the _edit.rhtml page which contains edit form.
_edit.rhtml page
[sourcecode language=’ruby’]

<% form_remote_for :expense, Expense.new, :url => hash_for_expenses_url(:project => @project, :action => ‘update’, :id=> params[:id]),
:loading => ‘ExpenseTracker.disableExpenseForm()’,
:complete => ‘ExpenseTracker.enableExpenseForm()’,
:html => { :id => ‘expense-form’ } do |f| %>


<%= text_field 'expense', 'description', :size => 60 %>

<%= text_field 'expense', 'amount', :size => 10 %>

<%= submit_tag 'Update' %>
<%= button_to_remote 'Cancel', :url => hash_for_expenses_url(
:project => @project,
:action => ‘cancel’,
:id=>params[:id]) %>

<% end %>

[/sourcecode]
I used text_field here because when user clicks on edit button he will get to displayed with form with filled values so that he can edit the data and update in to the database.
Edit action in expense controller
expense_controller.rb
[sourcecode language=’ruby’]
def edit
@expense = Expense.find(params[:id])
End
[/sourcecode]
Backend logic for updating the form values in the database
expense_controller.rb
[sourcecode language=’ruby’]
def update
@expense = Expense.find(params[:id])
@expense.update_attributes(
:description => params[:expense][:description],
:amount => params[:expense][:amount])
flash[:notice] = “Expense item updated successfully”
end
[/sourcecode]
Now finally the update.rjs for updating the page
update.rjs
[sourcecode language=’ruby’]
if @expense.valid?
page.replace ‘expense-‘ + params[:id].to_s, :partial => ‘expense’, :locals => {:expense => @expense}
page.update_summary @project
page.update_total number_to_currency(@project.total_expenses)
page.replace_html :notice, flash[:notice ]
flash.discard
else
page.display_errors @expense
end
[/sourcecode]
This will check the validation for the form and if correct values are submitted the page will be updated as well.
Conclusion:
While this worked our example is pretty much fine.
If you are interested we can add you as project members in google code so that you can contribute further.
Some features that can be implemented further is.
1. CRUD for project
2. Internationalization of the content
3. Begin/Rescue options for all db operations.
4. Fallback option to Javascript disabled browsers.

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *