Thread.new - dRuby now much more useful with Rails (2.2)
Rails 2.2 recently entered RC1 with loads of exciting features. Among built-in internationalization and bunch of other improvements, long awaited thread safety arrived. This was something that we (RoR users) were jealous when looking at Merb framework for quite a long time now.
Even if you are not using threaded server for your applications, and still use traditional mongrel/thin/whatever cluster, it’s good news for you. It’s even better if you use JRuby… but back to topic now.
Now, it’s easy to run long lasting tasks in your models for excellent description, look at Pratik Naik blog. It’s perfectly safe to write following code in your controllers now:
...
def create
@post = Post.create(params[:post])
Thread.new do
@post.republish_content_on_some_slow_responding_sites
end
end
...However, I found thread safety even more useful for my recent project, with dRuby server running in the background. Now I can get rid of global mutex in my background process and enjoy one dRuby server shared among multiple server instances. I am running 5 instances of mongrel, each of them using heavily drb daemon which processes ActiveRecord objects - now I get 5x boost in speed with thread safe Rails :)
Extending rails form helpers: a spinbox field
Spinboxes are common control in all desktop GUI applications. They’re found in all windowing toolkits that I know, and I use it all the time to input numbers. However, when it comes to web applications they are not so common. This is because (X)HTML doesn’t define such control.
I have found this great widget that requires prototype library only. It nicely degrades to text field when user doesn’t have javascript on, and is easy to use. However, I wanted to make it play nicely with Rails forms, to easily set up initial value etc.
Nothing easier. Just paste the following code to new file called lib/formhelperextensions.rb in you rails app:
module ActionView
module Helpers
module FormHelper
def spinbox_field(object_name, method, options = {})
min_val = options.delete(:min)
max_val = options.delete(:max)
tag = InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options.merge({:class =>"spin-button"}))
script = '<script type="text/javascript">new SpinButton($("'
script += "#{object_name}_#{method}"
script += '"),{'
script += "min:#{min_val}" if min_val
script += "," if min_val and max_val
script += "max:#{max_val}" if max_val
script += '});</script>'
tag+script
end
end
class FormBuilder
def spinbox_field(method, options = {})
@template.spinbox_field(@object_name, method, options)
end
end
end
end
and include the file at the end of your config/environment.rb
....
require "form_helper_extensions"Now, get a prototype-spin-button compressed archive, unpack it and copy spinbutton.js to your public/javascripts/ directory. Create file public/stylesheets/spinbutton.css and place following code in it:
input.spin-button {
padding-right:20px;
width:35px;
background-color:white;
background-repeat:no-repeat;
background-position:100% 0%;
background-image:url(/images/spinbtn_updn.gif);
}
input.spin-button.up {
cursor:pointer;
background-position:100% -18px;
}
input.spin-button.down {
cursor:pointer;
background-position:100% -36px;
}Last bit is to copy image spinbtn_updn.gif from zip archive to your public/images directory.
And, when you include spinbutton CSS and spinbutton.js in your view, you can use spinbutton in your forms! Your layout should have:
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag "spinbutton" %>
<%= stylesheet_link_tag "spinbutton" %>Use it in your forms, like you use text button:
form_for @user....
f.text_field :name
f.spinbox_field :age, :min => 0, :max => 120
endEnjoy!
BGUL / JTeam meetings - 02.04.2008 and 09.04.2008
This is announcement for our local Linux/Java community at Bialystok Technical University but… I’m a speaker at next two meetings of BGUL, together with JTeam. Subject - JRuby on Rails - I’ll try to prepare some cool examples of code that you might expect to appear on this blog this weekend / next week even before the first meeting.
Exactly when and where? This will appear on JTeam and/or BGUL web sites.
Everyone is invited!
TinyMCE and AJAX
TinyMCE is a visual XHTML editor that you can put on your web app, to convert textareas into Word-like editors. This way you can make it possible for your clients edit pages more easily, saving you lots of trouble explaining them basics ofHTML or even easier formatting languages. TinyMCE doesn’t play well with AJAX calls, however it’s easy to fix it. I will use TinyMCE with Ruby on Rails, version 2.0.2
Let’s start with creating new application:
[hubert@swarog ~]$ rails tiny_mce_ajax
create
create app/controllers
create app/helpers
...........................
create log/development.log
create log/test.log
[hubert@swarog ~]$ cd tiny_mce_ajax/
[hubert@swarog tiny_mce_ajax]$ ls
README app db lib public test vendor
Rakefile config doc log script tmp Now, let’s install tiny_mce plugin:
[hubert@swarog tiny_mce_ajax]$ ruby script/plugin install http://secure.near-time.com/svn/plugins/trunk/tiny_mce
[hubert@swarog tiny_mce_ajax]$ rake tiny_mce:scripts:install TinyMCE plugin used to work right after you do it, however something has changed either in Rails or the editor plugin that requires us to make a little hack here:
First, open this file with your favorite editor:
vendor/plugins/tiny_mce/lib/tiny_mce.rb and put these two lines at top of the file:
require 'tiny_mce_helper'
include TinyMCEHelper We’re ready to go. First, let’s create a RESTful controller:
[hubert@swarog tiny_mce_ajax]$ ./script/generate scaffold note body:text
[hubert@swarog tiny_mce_ajax]$ rake db:migrate An add TinyMCE and Prototype script links to HEAD section of our layout file:
<script src="/javascripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>
<%= tiny_mce %>
<%= javascript_include_tag :defaults %> At this point, we have TinyMCE installed in our application, that will be used on all textareas. However, this will not work if we add another textarea using JavaScript and/or AJAX calls.
To make it work, let’s add partial to our application:
file: app/views/notes/_new.html.erb
<% form_remote_for :note, @note, :update => { :success => "notes" }, :position => :bottom, :url => { :controller => "notes", :action => "create" }, :after => "$('new_note').innerHTML = ''; " do |f| %>
<%= f.text_area 'body', :colls => 100, :rows => 10 %><br/>
<%= submit_tag "Save", :onclick=>"javascript: tinyMCE.triggerSave(); tinyMCE.execCommand('mceRemoveControl', false, 'note_body'); " %>
<% end %>
<script type="text/javascript">
tinyMCE.execCommand('mceAddControl', false, 'note_body');
</scrip> And modify our “index” view:
Listing notes
<table id="notes">
<%= render :partial => "note", :collection => @notes %>
</table>
<br />
<%= link_to_remote "New note", :url => { :action => "new" }, :update => { :success => "new_note" } %>
<div id="new_note">
</div>Add partial for single note: _note.html.erb
<tr>
<td><%=h note.body %></td>
<td><%= link_to 'Show', note %></td>
<td><%= link_to 'Edit', edit_note_path(note) %></td>
<td><%= link_to 'Destroy', note, :confirm => 'Are you sure?', :method => :delete %></td>
</tr> And modify “new” and “create” actions in our controller:
notes_controller.rb
def new
@note = Note.new
if request.xhr?
render :partial => "new"
else
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @note }
end
end
end
def create
@note = Note.new(params[:note])
respond_to do |format|
if @note.save
if request.xhr?
render :partial => @note
return
end
flash[:notice] = 'Note was successfully created.'
format.html { redirect_to(@note) }
format.xml { render :xml => @note, :status => :created, :location => @note }
else
format.html { render :action => "new" }
format.xml { render :xml => @note.errors, :status => :unprocessable_entity }
end
end
end