Posted on Sun Feb 17 21:47:00 UTC 2008
If you use git submodules, as git-rails does, and want to use Capistano, you’ll need to patch patch Capistrano (lib/capistano/recipes/deploy/scm/git.rb) to make sure your submodules get included.
def checkout(revision, destination)
git = command
branch = head
fail "No branch specified, use for example 'set :branch, \"origin/master\"' in your deploy.rb" unless branch
if depth = configuration[:git_shallow_clone]
execute = "#{git} clone --depth #{depth} #{configuration[:repository]} #{destination} && "
else
execute = "#{git} clone #{configuration[:repository]} #{destination} && "
end
execute += "cd #{destination} && #{git} checkout -b deploy #{branch}"
if submodules = configuration[:git_enable_submodules]
execute += " && git-submodule init &&"
execute += "git-submodule update"
end
execute
end
then define this in your deploy.rb:
set :git_enable_submodules,1
Or you can use the trunk version (post 2.1), which includes that support already.
Posted in Rails
|
Tags rails
|
1 comment
Posted on Thu Feb 07 00:21:00 UTC 2008
After releasing the first version of git-rails, Ron Damen created a clone of the repository and started improving on it. And I liked what he was doing, so now was the time to figure out how to get some of his changes back in to the master repo.
Here is the list of steps (and what they mean) to get his changes into the master branch on Gitorious.
First, define a remote branch to track his cloned repository
git remote add ron git://gitorious.org/git-rails/rons-mainline-clone.git
This adds this to .git/config:
[remote "ron"]
url = git://gitorious.org/git-rails/rons-mainline-clone.git
fetch = +refs/heads/*:refs/remotes/ron/*
Before doing the actual checkout, make sure you have nothing to commit in the current branch, then checkout a tracking branch:
git checkout -b ron/master
Now get the content from thre remote (remote “ron”, branch “master”)
git pull ron master
Once you’ve reached this point, it is easy to switch back and forth between branches
git checkout master
git checkout ron/master
Next, I created a temporary branch to merge what I like from Ron (not needed really)
git branch merge-ron
git status # does not switch branch!
git checkout merge-ron
This could be used as a shortcut: checkout -b merge-ron
Merge only specific changes (obtained using git log in ron/master branch)
git cherry-pick dc3de57a073e24eeb398e0cacbe52340258e861b
git cherry-pick 61579f92e1bfc95e582728011fcd21c79f08c3ae
Merge from merge-ron branch into local master
git checkout master
git merge merge-ron
And finally, push to origin
git push origin
From now on, the only thing needed to get more changes from Ron is to pull changes into ron/master, cherry-pick changes and merge back into master. Sweet!
Posted in Rails
|
Tags rails
|
0 comments
Posted on Wed Feb 06 02:11:00 UTC 2008
What is RUR (Rails Undo Redo)
RUR (Rails-Undo-Redo) is a rails plugin (and soon a gem as well) to make it so easy to implement multi-level undo redo in your Rails application that you better start thinking of better excuses not to implement Undo/Redo (no, seriously, it is going to be a lot easier).
Try the demo!
To get a feel on how undo/redo can help make your app a lot more difficult for users to make mistake, test drive the RUR demo app
The full source code for that demo app is available here: rur_demo. Or via git:
git clone git://gitorious.org/rur_demo/mainline.git
Installing RUR
Using git-rails (this way, you’ll be able to stay up to date, assuming you use git):
git-rails install git://gitorious.org/rur/mainline.git rur
Using scrip/plugin:
script/plugin install http://svn.nanorails.com/plugins/rur
Then copy the migration from vendor/plugins/rur/migrations to db/migrations (renumber as needed), then run:
rake db:migrate
Using RUR
Define the undoable models
Once you have installed the plugin, for each model that you’d like to have its changes undone, just add act_as_undoable>
class Project < ActiveRecord::Base
belongs_to :user
has_many :tasks
acts_as_undoable
end
Define the undoable controllers:
Add the undo/redo logic to all your controllers:
class TasksController < ApplicationController
...
undoable_methods
...
end
Track changes
For all controller methods that make a change (and that are directly called by the user), you need to specify 3 things:
- an explanation of the change is
- what url to go back to when the user decides to undo the action
- what url to go back to when the user decides to redo the action
For this, you enclose the code that will change the records within a “change block”.
For example, here’s a create method:
def create
@task = @project.tasks.new(params[:task])
respond_to do |format|
change("create task #{@task.title}", project_tasks_path(@project), project_tasks_path(@project)) do
if @task.save
flash[:notice] = 'Task was successfully created.'
format.html { redirect_to(project_task_path(@project, @task)) }
format.xml { render :xml => @task, :status => :created, :location => @task }
else
format.html { render :action => "new" }
format.xml { render :xml => @task.errors, :status => :unprocessable_entity }
end
end
end
end
or for update:
def create
@task = @project.tasks.new(params[:task])
respond_to do |format|
change("create task #{@task.title}", project_tasks_path(@project), project_tasks_path(@project)) do
if @task.save
flash[:notice] = 'Task was successfully created.'
format.html { redirect_to(project_task_path(@project, @task)) }
format.xml { render :xml => @task, :status => :created, :location => @task }
else
format.html { render :action => "new" }
format.xml { render :xml => @task.errors, :status => :unprocessable_entity }
end
end
end
end
or for destroy:
def destroy
@task = @project.tasks.find(params[:id])
change("delete task #{@task.title}", project_task_path(@project, @task), project_tasks_path(@project)) do
@task.destroy
end
respond_to do |format|
format.html { redirect_to(project_tasks_url(@project)) }
format.xml { head :ok }
end
end
Or even a non REST method:
def move_to
@task = @project.tasks.find(params[:id])
@new_project = Project.find(params[:task][:new_project_id])
unless (@new_project == @project)
change("move task #{@task.title} to #{@new_project.title}", project_task_path(@project, @task), project_task_path(@new_project, @task)) do
@task.project.tasks.delete @task
@new_project.tasks << @task
end
end
flash[:notice] = "Task was successfully reassigned to #{@new_project.title}"
redirect_to(project_task_path(@new_project, @task))
end
Any change within a change block to a model with an “act_as_undoable” attribute will be recorded and can then later on be undone and redone by calling undo or redo.
Let the user undo and redo
The last piece of the puzzle is to add the following to your views (the layout is probably a good place for it):
<% if undo_redo_links != "" %>
<p><%= undo_redo_links %></p>
<% end %>
Example
For a real life example, check out the rur_demo source code.
How does it work?
Coming up shortly… :)
Contributing
The ruby forge RUR project
Clone away the Git repository: git://gitorious.org/rur/mainline.git
git clone git://gitorious.org/rur/mainline.git
Or, better yet, create your own branch on gitorious.
Posted in Rails Undo Redo
|
Tags rails
|
0 comments
Posted on Tue Feb 05 01:12:00 UTC 2008
Git is quickly becoming one of the best option for using a DVCS (Distributed Version Control System). Git main goal is to be quick (most everything you do is local), and has already been battle tested by the Linux Kernel dev team.
Recently, I’ve started experimenting with git after Rick switched Mephisto to git.
Even though things are pretty straightforward, some things are easier than others, especially when you have to take it all in in one shot.
So, over the weekend, I created git-rails, completed with a rubyforge project, an installable gem (gem install git-rails), and a git repository hosted by Gitorious
Currently, git-rails provides 3 functions:
- init repository (hookup to remote git repository, rails aware .gitignore)
- install plugin managed by git (using git submodules)
- update plugin
For now, I’m happy to use giston to manage svn hosted plugins, but I’m considering whether to add that functionality as well. We’ll see how things go.
To get started with git-rails, head over to the new git-rails project page.
Inspired by piston, and its newest sibling: giston/braid
Posted in News, Rails
|
Tags rails
|
3 comments
Posted on Mon Aug 20 22:24:00 UTC 2007
I had been hearing about Gentoo for a long time, and finally discovered it in depth about 6 months ago. Gentoo is really a different beast as Linuxes go. You get to build everything from sources. No binaries. That’s right. That means that you get to build everything with compatible flags, get to remove a lot of the unnecessary bloat (Do I hear X windows for example?). It also means that the initial setup could take you several days if your machine is not so powerful. Suffice it to say, I really, really like the approach and that is now what I’m using to run this blog.
Of course, if I need a server setup in a hurry, I’ll still go for a Debian or Ubuntu. But if I want a very fined tune system, Gentoo is it.
Of course, there is an ebuild for rails (ebuild is gentoo-speak for describing a package your can grab and build), but it did bring a lot more that what I cared for, so here’s the step by step instructions for getting Rails+Mongrel+nginx going on Gentoo.
This assumes that you are starting from a Gentoo 2006.1 stage 3 without much else.
A word of warning
Even though I’ve used these notes to successfully setup 3 machines (both on x86 and amd64), your experience may still be different, or you may need slightly different options or settings as the packages are bound to evolve, or I’ve made some assumptions that do not apply in your case, or something was obvious to me that should not have been, or, perish the thought, I just plain forgot something. If that happens, remember, Google is your friend, or don’t be shy, ask a question here, someone might know the answer.
So with that out the way, let’s get started.
Preamble
auto start ssh:
rc-update add sshd default
update portage tree
emerge --sync
emerge portage
emerge -av --update --deep world
At this point, you are going to have a lot of configuration files that out of date. Since we are doing a new setup, we just want to silence the warnings and making sure we use the latest version. So to find each file:
find /etc -iname '._cfg????_*'
But do not overwrite inittab if it is only putting back more terminal login than you need.
Now it is time to add a few very useful tools like sudo, stuff to help you figure out what’s installed, and to find things (namely sudo, gentoolkit and sys-apps/slocate)
emerge -av app-admin/sudo app-portage/gentoolkit sys-apps/slocate
Now it is time to create your user. And set its password.
useradd user
passwd user
Add user to /etc/sudoers with ALL
Add vim (or whatever else you fancy)
emerge -av vim
Change default
EDITOR
vi /etc/rc.conf
There, comment out /bin/nano, and uncomment /bin/vim
Install subversion
emerge -av subversion
Even though not strictly necessary for Rails, a few network utilities always come in handy (traceroute, dig, nslookup):
emerge -av traceroute bind-tools
If you want to send/receive emails:
emerge -av mail-client/mailx
emerge --unmerge mail-mta/ssmtp
emerge -av syslog-ng mail-mta/exim
rc-update add exim default
There are lots of options to do SMTP, but I find exim4 the quickest and simplest to setup:
create /etc/exim/exim.conf from /etc/exim/exim.conf.dist
To lockdown mail to localhost (you just want your Rails app to send emails), add this exim.conf:
local_interfaces = 127.0.0.1
And to allow non users to send mails (comment out this line)
##require verify = sender
And finally, start your mail server:
/etc/init.d/exim start
Rails Setup
My preferred database remains MySQL. I know, some people prefer PostgrSQL.
emerge -av dev-db/mysql
rc-update add mysql default
Then, to configure MySQL and create a first database, first you need to figure out which version you just installed. If you were not paying attention as the logs were flying by (I know I wasn’t), use
equery list mysql
And then
emerge --config =dev-db/mysql-5.0.26-r2
To get rubygems 0.9.x, you need to unmask it. For that, add a new line to
/etc/portage/package.keywords with:
dev-ruby/rubygems ~amd64
Replace with ~x86 if you are not on an AMD chip, then run:
emerge -av dev-lang/ruby dev-ruby/mysql-ruby dev-ruby/rubygems dev-ruby/ruby-termios
For any kind of image manipulation (resizing and such), install Image Magick. First, it it does not already exist create /etc/portage/package.use
dev-ruby/rmagick lcms gif imagemagick jbig jpeg jpeg2k pdf png svg tiff truetype unicode wmf xml xpm pcre
media-gfx/imagemagick lcms gif imagemagick jbig jpeg jpeg2k pdf png svg tiff truetype unicode wmf xml xpm pcre
emerge -av media-gfx/imagemagick dev-ruby/rmagick
The above line represents the options for that ebuild.
Time to get the latest nginx
- add a new line to /etc/portage/package.keywords with (Again, on Intel, use
~x86)
"www-servers/nginx ~amd64
Then run emerge again:
emerge -av www-servers/nginx
Ok, now time to install what we actually wanted to install, Ruby on Rails and a few useful gems:
gem install -y rails rake capistrano daemons gem_plugin mongrel mongrel_cluster rmagick BlueCloth RedCloth ruby-debug termios ruby-openid ruby-yadis
Start mysql, create a database for rails test app
/etc/init.d/mysql start
mysqladmin -u root -p create test1_development
mysqladmin -u root -p create test1_production
And finally, install a rails app (we’ll use beast as it is pretty simple to install)
svn checkout http://svn.techno-weenie.net/projects/beast/trunk beast
cd beast/
rake rails:freeze:edge
#create config/database.yml from config/database.example.yml
rake db:schema:load RAILS_ENV=production
./script/server -e production
Test that everything’s fine fine by pointing your browser to port 3000.
Now, let’s configure mongrel (We are almost there, I promise).
cd [app]
sudo useradd -n mongrel
sudo chown -R mongrel:mongrel [app]
mongrel_rails cluster::configure -e production -p 8000 -N 3 -c [app] -a 127.0.0.1 --user mongrel --group mongrel
Later, a few useful commands to use
#start cluster
mongrel_rails cluster::start
#restart cluster
mongrel_rails cluster::restart
#stop cluster
mongrel_rails cluster::stop
To setup nginx, edit /etc/nginx/nginx.conf to match your setup
To setup mongrel_cluster for autostart
mkdir /etc/mongrel_cluster
ln -s [app]/config/mongrel_cluster.yml /etc/mongrel_cluster/[app].yml
#copy from wherever the gem is installed (use locate to figure out the location)
ln -s /usr/lib64/ruby/gems/1.8/gems/mongrel_cluster-0.2.1/resources/mongrel_cluster /etc/init.d/mongrel_cluster
chmod +x /etc/init.d/mongrel_cluster
Add nginx and mongrel_cluster to startup
rc-update add nginx default
rc-update add mongrel_cluster default
For smooth reboot, you may need to delete the pid files
Apply this patch (from http://textsnippets.com)
create file “mongrel_cluster.patch” with:
--- bin/mongrel_rails-orig 2007-05-16 14:41:51.000000000 -0400
+++ bin/mongrel_rails 2007-05-16 14:42:50.000000000 -0400
@@ -83,9 +83,17 @@
config = Mongrel::Rails::RailsConfigurator.new(settings) do
if defaults[:daemon]
if File.exist? defaults[:pid_file]
- log "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors."
- log "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start."
- exit 1
+ # mongrels that crash can leave stale PID files behind, and these
+ # should not stop mongrel from being restarted by monitors…
+ pid = File.new(defaults[:pid_file]).readline
+ unless `ps -ef | grep #{pid} | grep -v grep`.length > 0
+ # use "ps ax" for freebsd
+ log "!!! PID file #{defaults[:pid_file]} exists, but is stale, and will be deleted so that this mongrel can run."
+ File.delete(defaults[:pid_file])
+ else
+ log "!!! PID file #{defaults[:pid_file]} already exists and the process id referred to in it is running. This mongrel is probably already running. #{defaults[:log_file]} for errors. EXITING."
+ exit 1
+ end
end
daemonize
then apply the patch
patch -p0 /usr/lib64/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails < mongrel_cluster.patch
And there you have it. A nice, humming Ruby on Rails+Mongrel+nginx on Gentoo.
Posted in Linux, Rails
|
Tags rails
|
4 comments
Posted on Wed Feb 14 18:52:00 UTC 2007
It started innocently enough. I was writing a Rails Plugin, and needed to call a Class Method on a Model. No problemo, right? In init.rb just call the method (To register a renderer in this case).
Site.register_template_handler(".erubis", ErubisTemplate)
The method goes on and adds some date to a Class Variable. I try it and it worked…
... For the first request only :( After that, the data is gone from the class! What gives???
Well, there is a very convenient mechanism that reloads all your models, views and controllers so you don’t have to restart your app every time you make a change. Except here. Once the class gets unloaded, BAM! There goes the Class Variable and my carefully registered renderer.
First Solution
The code responsible for unloading and reloading all the models, views, and controllers is
Dispatcher.reset_application!, so why not piggy back on reset_application! ? So using
alias_method_chain, after a few iteration, here’s what I came up with:
class << Dispatcher
def register_erubis_template
Site.register_template_handler(".erubis", ErubisTemplate)
end
def reset_application_with_erubis_registration!
returning reset_application_without_erubis_registration! do
register_erubis_template
end
end
alias_method_chain :reset_application!, :erubis_registration
end
Dispatcher.register_erubis_template
Since reset_application! is not called till the second request, I had to also call the registration method once, which is why I created a register_erubis_template method.
It now worked. That was nice. But, then I started implementing a second plugin, which needed the same code. Not very DRY.
So I wrote down what ideally I wanted to end up with:
after_reset_application {
Site.register_template_handler(".erubis", ErubisTemplate)
}
So next time I have the same problem, I can just reuse the same
after_reset_application call with any other code I need to run after all the classes get unloaded.
Lots of aborted attempts
Foolishly, I thought it would be quite easy to transform what I had into something reusable. A little dose of Monkey Patching here and there, a bit of Meta Programming, and there you have it. Well, I did not keep all the many iterations I tried, here are just a few that did not work for one reason or an other (I did not try to find out why, just moved on to the next attempt)
Dispatcher.alias_method_chain :reset_application!, #{feature}
Dispatcher.class_eval do
def reset_application_with_#{feature}!
returning reset_application_without_#{feature}! do
register_#{feature}
end
end
end
def after_reset_application(feature, &block)
patch = <<-end_eval
class << Dispatcher
def register_#{feature}
proc
end
def reset_application_with_#{feature}!
returning reset_application_without_#{feature}! do
register_#{feature}
end
end
alias_method_chain :reset_application!, #{feature}
end
end_eval
eval patch#, &block, __FILE__, __LINE__
Dispatcher.send "register_#{feature}"
end
Use the singleton-class, Luke! Use the singleton-class!
Then I retrieved a post from Ola Bini that I had read some months back: The ruby singleton class and I started to make some progress after I understood that to define methods, I needed to do it on the singleton class, not the class itself, because even though it did not fail, it did not accomplish much. And finally arrived at:
To retrieve that singleton class:
class << Dispatcher; self end
So now, I finally arrived at this code:
require 'dispatcher'
def after_reset_application(feature, &block)
class << Dispatcher; self end.class_eval do
define_method("register_#{feature}", &block)
define_method("reset_application_with_#{feature}!") {
returning Dispatcher.send("reset_application_without_#{feature}!") do
Dispatcher.send("register_#{feature}")
end
}
alias_method_chain :reset_application!, "#{feature}"
end
Dispatcher.send("register_#{feature}")
end
after_reset_application("erubis_registration") {
Site.register_template_handler(".erubis", ErubisTemplate)
}
The key reasons why this works is that it is adding the methods to the singleton class, not the class itself. It is using send to be able to build the method names, and using alias_method_chain to be able to monkey patch reset_application! as many time as needed. I had to add a parameter to after_reset_application for the same reason, so it can be called more than once. And it uses define_method because you can give it a block, plus you can define the method name from variables.
All good, except that it is still not very DRY. What if I want to use the same technique on a different class? A different method?
The final version (for now?)
This one was easy, just add a few parameters, deal safely with ?, ! and = and there you go
def after_method(klass, target, feature, &block)
# Strip out punctuation on predicates or bang methods since
# e.g. target?_without_feature is not a valid method name.
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
class << klass; self end.class_eval do
define_method("register_#{feature}", &block)
define_method("#{aliased_target}_with_#{feature}#{punctuation}") {
returning klass.send("#{aliased_target}_without_#{feature}#{punctuation}") do
klass.send("register_#{feature}")
end
}
alias_method_chain target, "#{feature}"
end
klass.send("register_#{feature}")
end
Then, to implement
after_reset_application:
require 'dispatcher'
def after_reset_application(feature, &block)
after_method(Dispatcher, :reset_application!, feature, &block)
end
And to use:
after_reset_application("erubis_registration") {
Site.register_template_handler(".erubis", ErubisTemplate)
}
Phew! The block gets called once the first time, and every time the classes need to be reloaded.
Posted in Just Enough, Rails
|
Tags rails
|
0 comments
Posted on Mon Jan 15 19:25:00 UTC 2007
Well, well, well, almost a year after signing up with Dream Host, after going through many turbulent times, trying to fix things up myself, and again, surviving an unannounced, and not so welcome upgrade, after hoping for mongrel support, it really came down to a severe case of overselling. Performance had become abysmal, database connections hard to come by, site was down for longer and longer periods of time. Sometimes several hours without much I could do to revive it.
Don’t get me wrong, not all overselling is bad as long as it is managed properly. In my case, it came down to cpu and resource usage (database, memory). I mean, a rails application like typo is no small app. It routinely had 3 fcgi processes, each 70Mb plus, which on a 4 Gb machine is over 5% of memory, ouch! A good thing that not everyone there runs typo! But I don’t think that was the problem though. On average, the load of the machine was between 10 to 20, which is high but could be sustainable if it wasn’t for the fact that cpu usage seems to be above 90% all the time. This does not give much for a little boost when needed. And on that front, Dream Host needs to make some improvements quickly!
To be honest, this does not seem to be a big issue to run something like wordpress and my other sites on the same machine seem to be doing just fine and I don’t plan to move then anywhere anytime soon. I mean, it is hard to beat the amazing storage space and bandwidth allotment.
So with all that in mind, it was time for a new host! I knew what I wanted:
- mongrel support
- ssh support
- no need for extravagant bandwidth
- no setup fee, reasonable month to month cost
To find the best contenders, I used Google and the Hosting page on rubyonrails.org.
The best fit: Rails Playground. This post is hosted there, and so far, so good. For $12/month, that looks like a very competitive plan for a rails app. Granted I can only run one app with 2 mongrels, but that will do great for now.
The transition went really smoothly, all things considered.
First thing was to export the database, and I hit a first snag trying to get the data. I could not get a database connection to dump the data, fortunately, I was able to do the export using phpMyAdmin.
On the Rails Playground side, it came down to setting up a database, importing the data, setting up Capistrano, and putting out a request for mongrel setup. Less than a couple hours works and the request for mongrel setup was completed overnight.
Then the only thing left was to switch dns (so the old site was still up, at least as much up as it can be while the dns change propagates), and that’s where the only hitch happened. I ran into a perl error on the Dream Host control panel. Nothing their support couldn’t solve, and an hour later the whois database was updated, and dns servers all over started to pick up the change, and Voila! Rails Playground, here I come!
I now have the distinct (ahem… cough) advantage of having the 2 biggest processes running on this new machine but shush, don’t tell anyone…
And what a difference this makes. Average cpu usage seems to be below 5% and so far, not dreaded 500 error page :)
Note: if you read this via RSS, this may get delayed because as I write this, FeedBurner is still polling the old site. Hopefully this will update by tomorrow.
Posted in News, Rails
|
Tags rails
|
11 comments
Posted on Mon Dec 18 15:17:00 UTC 2006
A while back I wrote BookmarkIt! , a social bookmarllet plugin for Typo, and it worked for a while, but the Typo plugin API changed, and changed again, and again, and keeping up was no fun. So since then, I’ve already changed my approach for my TextLinkAds plugin and instead wrote a bona fide rails plugin, and since Typo 4.0.3 broke the plugin one more time, it was time to take the same route.
Morevover, the previous version did not allow for putting the Bookmkarlets inline with the post and this new version addresses that also. It is now a real Rails plugin, useable in any Rails app.
How to Get the plugin
script/plugin install http://svn.nanorails.com/plugins/bookmarkit/
or to use svn:externals to get updates
script/plugin install -x http://svn.nanorails.com/plugins/bookmarkit/
The install will automatically copy the config file, the images, the css and the partial in their final location. If you delete these files, you can reinstall with:
script/plugin install --force http://svn.nanorails.com/plugins/bookmarkit/
How to configure the plugin
To configure, edit the file config/bookmarkit.yml to change the title and select which bookmarklets you want displayed.
title: Bookmark It!
delicious: true(default)/false
digg: true(default)/false
reddit: true(default)/false
blinklist: true(default)/false
dzone: true(default)/false
newsvine: true(default)/false
furl: true(default)/false
spurl: true(default)/false
simpy: true(default)/false
fark: true(default)/false
blogmarks: true(default)/false
myweb2: true(default)/false
wists: true(default)/false
How to use the plugin
To use, inside any view (.rhtml), use:
<%= render_BMI(title, url) %>
For example, in Typo, you would include the following in app/views/articles/read.rhtml
<%= render_BMI(@article.title, @article.location) %>
For finer control of the rendering, it also copies a css (bookmarkit.css) to public/stylesheets. To use, include in your main layout with:
<%= stylesheet_link_tag "/stylesheets/bookmarkit" %>
Adding more bookmarklets
All the bookmarklet html is in the _bookmarkit.rhtml partial.
For example, for
BlinkList, I’ve used:
<a style="font-size:22px;" title="Blink '<%= title %>'" href="http://www.blinklist.com/index.php?Action=Blink/addblink.php&Url=<%= url %>&Title=<%= title %>">
<img style="border:0;" hspace="3" class="bookrmarkit" alt="Blink" title="Blink '<%= title %>'" src="/images/bookmarkit/blinklist.gif" />
</a>
You should also add an entry in bookmarkit.yml
If you want more bookmakrlets included, submit your patches in the comments or send to psq_at_no_spam_nanorails_dot_no_spam_com.
Posted in html/css, Rails
|
Tags rails
|
3 comments
Posted on Mon Oct 16 17:56:00 UTC 2006
Just a few days ago, I had the opportunity to upgrade my iMac from a 20” to a 24”. Not only does it have more real estate on the screen, not only is the CPU slightly faster, but it also can take up to 3 Gb of RAM, from 2Gb, which is quite an improvement, especially if you like to run multiple VMs (using Parallel).
So it was quite a relief to us my notes to install Rails on Mac OS Tiger. Except that a lot has changed in the past 3 months since I last wrote that article, and before I update the page to make more sense to newcomers, I’ll just write down a few notes on what I had to do differently.
These reflect the installation on MacOS 10.4.8 and the latest version of MacPorts (as of 10/14/06).
First of all, Darwin Ports is no more: long live MacPorts!
Which means that here is a new location for darwin ports installer.
Then I uncovered a problem in the order of the steps:
Set the PATH before running “sudo port -d selfupdate”, not after as suggested.
One thing that I did not realize, is that you need to actually install a C compiler before you can get started! The easiest is to install XCode 2.4. There is a free registration you need to fill in.
I missed a sudo:
cp httpd.conf.sample httpd.conf => sudo cp httpd.conf.sample httpd.conf
The path to the launchctl file for apache2 has changed:
sudo launchctl load -w /Library/LaunchDaemons/org.macports.apache2.plist instead of sudo launchctl load -w /Library/LaunchDaemons/org.darwinports.apache2.plist
To initialize the database, you need to add:
add "sudo -u mysql mysql_install_db5"
The path to the launchctl file for mysql5 has changed as well:
sudo launchctl load -w /Library/LaunchDaemons/org.macports.mysql5.plist instead of sudo launchctl load -w /Library/LaunchDaemons/org.darwinports.mysql5.plist
replace rb-mysql5 with rb-mysql since rb-mysql supports both flavors
And that’s where it got a bit tricky. With that combination of MacOS 10.4.8 and the current version of MacPorts, rb-mysql fails to compile.
gcc -I. -I. -I/opt/local/lib/ruby/1.8/i686-darwin8.8.1 -I. -DHAVE_MYSQL_SSL_SET -DHAVE_MYSQL_H -I/opt/local/include/mysql5/mysql/ -I/usr/local/include -O -pipe -I/opt/local/include -fno-common -O -pipe -I/opt/local/include -fno-common -pipe -fno-common -c mysql.c
mysql.c: In function 'Init_mysql':
mysql.c:2015: error: 'ulong' undeclared (first use in this function)
mysql.c:2015: error: (Each undeclared identifier is reported only once
mysql.c:2015: error: for each function it appears in.)
mysql.c:2015: error: parse error before numeric constant
mysql.c:2018: error: parse error before numeric constant
{standard input}:6318:non-relocatable subtraction expression, "_cMysqlTime" minus "L00000000065$pb"
{standard input}:6318:symbol: "_cMysqlTime" can't be undefined in a subtraction expression
{standard input}:5382:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000045$pb"
{standard input}:5382:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:5355:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000044$pb"
{standard input}:5355:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:5333:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000044$pb"
{standard input}:5333:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:4861:non-relocatable subtraction expression, "_cMysqlTime" minus "L00000000042$pb"
{standard input}:4861:symbol: "_cMysqlTime" can't be undefined in a subtraction expression
{standard input}:4359:non-relocatable subtraction expression, "_cMysqlTime" minus "L00000000041$pb"
{standard input}:4359:symbol: "_cMysqlTime" can't be undefined in a subtraction expression
{standard input}:4106:non-relocatable subtraction expression, "_eMysql" minus "L00000000041$pb"
{standard input}:4106:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:3957:non-relocatable subtraction expression, "_cMysqlTime" minus "L00000000040$pb"
{standard input}:3957:symbol: "_cMysqlTime" can't be undefined in a subtraction expression
{standard input}:3895:non-relocatable subtraction expression, "_eMysql" minus "L00000000040$pb"
{standard input}:3895:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:3824:non-relocatable subtraction expression, "_eMysql" minus "L00000000039$pb"
{standard input}:3824:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:3803:non-relocatable subtraction expression, "_eMysql" minus "L00000000038$pb"
{standard input}:3803:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:3256:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000023$pb"
{standard input}:3256:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:3226:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000022$pb"
{standard input}:3226:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:3200:non-relocatable subtraction expression, "_cMysqlRowOffset" minus "L00000000022$pb"
{standard input}:3200:symbol: "_cMysqlRowOffset" can't be undefined in a subtraction expression
{standard input}:2749:non-relocatable subtraction expression, "_eMysql" minus "L00000000019$pb"
{standard input}:2749:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:2595:non-relocatable subtraction expression, "_eMysql" minus "L00000000018$pb"
{standard input}:2595:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:2412:non-relocatable subtraction expression, "_cMysqlStmt" minus "L00000000016$pb"
{standard input}:2412:symbol: "_cMysqlStmt" can't be undefined in a subtraction expression
{standard input}:973:non-relocatable subtraction expression, "_eMysql" minus "L00000000008$pb"
{standard input}:973:symbol: "_eMysql" can't be undefined in a subtraction expression
{standard input}:290:non-relocatable subtraction expression, "_cMysqlField" minus "L00000000004$pb"
{standard input}:290:symbol: "_cMysqlField" can't be undefined in a subtraction expression
{standard input}:232:non-relocatable subtraction expression, "_cMysqlRes" minus "L00000000003$pb"
{standard input}:232:symbol: "_cMysqlRes" can't be undefined in a subtraction expression
{standard input}:190:non-relocatable subtraction expression, "_eMysql" minus "L00000000002$pb"
{standard input}:190:symbol: "_eMysql" can't be undefined in a subtraction expression
make: *** [mysql.o] Error 1
At this point your are either stuck waiting for an update version, or if you are not afraid to dip into the code, you can arm-twist it into working by following these steps:
rb-mysql patch
These steps should be fairly simple to follow:
cd /opt/local/var/db/dports/build/_opt_local_var_db_dports_sources_rsync.rsync.darwinports.org_dpupdate_dports_ruby_rb-mysql/work/mysql-ruby-2.7.1
sudo ruby extconf.rb --with-mysql-include=/opt/local/include/mysql5/mysql/ --with-mysql-lib=/opt/local/lib/mysql5/mysql/
add '#include "my_global.h"' to mysql.c (as the first #include)
sudo make clean
sudo make
sudo make install
And voila. Running the tests will show 3 failing tests, mostly due to imprecisions, but I think you can live with them. Further testing with rails apps did not reveal any problems with MySQL access.
Note: I’ve contacted the maintainer of that port but I have not heard back yet. I will update this post when I do.
A few bonus gems I’ve found helpful, or can’t live without
And since you are in setup mode, you might as well add them to your collection.
sudo gem install acts_as_versioned ajax_scaffold_generator BlueCloth builder fastercsv ferret gettext htmltools mocha payment radiant radius rcov rdig RedCloth ruby-debug rubyful_soup selenium shipping
sudo gem install map_by_method what_methods
A word from nano RAILS sponsors
The business of web hosting has a
strong influence over the internet as a web site can not exist without
hosting services. Whether it is a
microsoft certifications web site or a
web site with original material about home
based business work. The leading web hosts provide different types of
hosting packages such as domain or email
hosting. Along with other comprehensive services such as web site
development. Sites do needs proper
search engine submission in order to
capture a good rank, whether it is a web site for
online certification or a site for
holiday planning.
Posted in Mac, Rails
|
Tags rails
|
8 comments
Posted on Sun Oct 01 10:17:00 UTC 2006
Change of Strategy
Instead of updating my constantly breaking Typo sidebar plugin, and to implement Feedvertising from TextLinkAds, I’ve changed gears and chosen to implement just a regular plugin (very close to the new way of doing sidebar plugins in typo 4.1). This approach should work in all versions of typo, as well as any other Ruby on Rails’s application.
The support for feedvertising is slightly different than the one from the Wordpress plugin that is the only option offered so far, but should be fairly close.
Installation
Get the plugin from subversion:
script/plugin install http://svn.nanorails.com/plugins/textlinkads/
or to use svn:externals and get future updates via svn update
script/plugin install -x http://svn.nanorails.com/plugins/textlinkads/
The installation will copy a file textlinkads.yml into your config directory.
The file looks like this:
key: TLA_KEY
affiliateid: 0
title: Sponsors
advertisehere: Advertise here!
testing: false
caching: true
Replace TLA_KEY with the one provided by TextLinkAds, set your affiliateid if you’d like to have a link to TextLinkAds with your affiliate id (so you can get credit if someone signs up for a TextLinkAds account). Change the title and advertisehere messages if you don’t like the defaults.
Set testing to false once you’ve verified it works (while testing=true, the plugin will use a special page provided by TextLinkAds that displays to links. However, that page does not contain any RSS links)
Finally, if the caching done by Rails is not enough, the plugin can cache the calls to retrieve the links. See the caching section for explanations on how to setup caching.
Integrating with Typo
Adding the display of regular links
To add the regular TextLinkAds links, you need to add a call to render_TLA anywhere in the rendering code. In typo, the most likely place is in your template’s default.rhtml
Here’s what my template looks like
<div id="sidebar">
...
<div class="sidebar-node"><%= render_TLA %></div>
<% response.lifetime = 6.hour %>
<%= render_sidebars %>
</div>
to replace the original:
<div id="sidebar">
<%= render_sidebars %>
</div>
Add the RSS links
For RSS2.0 for example, edit the file app/views/xml/_rss20_item_article.rxml to add a call to render_TLA_RSS(post_id)
here’s the original file:
xm.item do
xm.title post_title(item)
if this_blog.show_extended_on_rss
content = item.full_html
else
content = item.body_html
end
xm.description content
xm.pubDate pub_date(item.published_at)
...
xm.item do
xm.title post_title(item)
if this_blog.show_extended_on_rss
content = item.full_html
else
content = item.body_html
end
content += render_TLA_RSS(item.id)
response.lifetime = 6.hour
xm.description content
xm.pubDate pub_date(item.published_at)
Depending of which format you need, you may need to edit a different file.
That’s it.
Integrating with other apps
For other apps, just take a similar approach and add calls to render_TLA and render_TLA_RSS where most appropriate. Both calls are accessible from any Controller or Helper class.
Caching
Set “caching: true” in textlinkads.yml. Make sure Rails is configured with some caching. Typically, you need to have
config.action_controller.perform_caching = true
config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/tmp/cache"
either set from config/environment.rb or config/environment/[CURRENT ENVIRONMENT].rb
This will cache the pages where the ads appear, and cache the feed pages. But to make sure these pages will update properly if the TextLinkAds ads inventory is updated, you must ensure the cache will expire.
The best way to do that is to use the expiring_cache_action plugin. To install:
script/plugin install http://typosphere.org/trac/browser/trunk/vendor/plugins/expiring_action_cache
Then where you added calls to
render_TLA, just add:
response.lifetime = 6.hour
This way, the cached page will expire 6 hours later so that would be the lapse of time to wait to see the updated ads.
No need to expire the cache for RSS, it should get expired automatically every time an article is added.
If you use this plugin in other applications, add a comment or send me a not (psq_0×40_nanorails_0×2e_com) and I’ll add a link to your instructions or code.
Posted in Rails
|
Tags rails
|
3 comments
Posted on Fri Aug 11 18:13:00 UTC 2006
Since I upgraded to Typo 4.0, and in the process rails 1.1.6 I have had a few occurrences where nanoRAILS would hang, several bloated processes would be sitting there and not respond, and the only option at that point was to kill all ruby processes once I realized what was happening, which could be several hours. Suffice it to say, this is not a good option.
So after struggling during last rails upgrade to 1.1 on my host, the next logical step is to also use my own version of ruby so I can have better control on its environment, and even apply patches if necessary.
The following steps apply on a lot of systems. More specifically, my host is DreamHost (aff), and as best I can tell, I’m on a host with Debian Sarge.
Build your own Ruby
Download ruby from http://www.ruby-lang.org. The latest version is currently ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.4.tar.gz
Create the makefile using
./configure prefix=[YOUR_OWN_RUBY_PREFIX]
Since you most likely don’t have root access, you need to override where ruby think it resides, and the way to do that is to set the prefix to somewhere into your home directory. Something like /home/USERNAME/ruby for example. From that point on, libraries, other builtin ruby files, gems will automatically install into your own ruby repository so you never have to worry about getting in trouble with an unforeseen upgrade.
Optionally, you can apply the patch used by Railsbench, with hardcoded default values because I haven’t figured how to set the environment variables for the dispatch.fcgi process (since apache in my case determines that). Download my version of rubygc.patch .
patch gc.c rubygc.patch
Build and install ruby
make
make install
Additionally, so that the command line uses the same version of ruby, add this to your .bashrc or equivalent for your shel.
export PATH=[YOUR_OWN_RUBY_PREFIX]/bin:$PATH
Install your own gems
Now you are ready to install your own gems. Here’s the bare minimum you need.
First, install rubygems
wget http://rubyforge.org/frs/download.php/11289/rubygems-0.9.0.tgz
tar xzvf rubygems-0.9.0.tgz
cd rubygems-0.9.0
ruby setup.rb
Then install the minimum set of gems:
gem install mysql
gem install fcgi
gem install rails --include-dependencies
Now, the only thing you need is to change the path to ruby in your dispatch file (dispatch.rb for mod_cgi, dispatch.cgi for regular cgi, and dispatch.fcgi for FastCGI/fcgid)
Typically, replace
#!/usr/bin/env ruby
by
#![YOUR_OWN_RUBY_PREFIX]/bin/ruby
Replace [YOUR_OWN_RUBY_PREFIX] by your own value you used earlier.
Posted in Linux, Rails
|
Tags rails
|
24 comments
Posted on Mon Aug 07 20:06:00 UTC 2006
Well, the upgrade to Typo 4.0 didn’t go so well. No data loss though, so everything’s cool.
At least most pages seem to be functional, so this is not so bad. Combined with having custom sidebar plugins that no longer work, the fact that the merge between the new code and my old one did not quite go as planned, it was not a too pleasant (most of it my own fault I guess).
Anyway, it is getting really late and I’ll finish the rest of the migration tomorrow.
If you tried to access the site while this was going on and you were inconvenienced, pleas accept my most sincere apologies!
If you notice anything weird, please send me a mail at psq _at_ nanorails _dot_ com.
Update, about 20h later, some sleep…: It seems that everything is back up, I migrated my custom plugins to typo 4.0 (about removing 1 file, removing half of the code linked to configuration and adding a few lines) and it seems that everything has been working smoothly :)
And the best of all of that: no more trackback spam! Well, not that it went away, it caught about 25 since last night, but they don’t get published anymore. Just for that, it was all worth it. Thank you everyone in the typo team!
Update 2: Well rails 1.1.5 came out, and it was not enough, so rails 1.1.6 came out and seems to be strong enough to fill in the security issues
And in the process, I also upgraded to Typo 4.0.2
That last upgrade went very smoothly!
However, I’ve had a few annoying cases of nanoRAILS hanging and not responding for hours on hand till I killed the processes. I don’t know yet at this point whether it is due to the new version of rails, the new version of typo, or pehaps some settings that changes on dreamhost. In any case, I’ve installed my own version of ruby and the full set of gems, so we’ll see if that helps!
Posted in Quid Pro Quo, Rails
|
Tags rails
|
11 comments
Posted on Fri Aug 04 11:30:00 UTC 2006
Court3nay from ~:caboose has started a fundraising to be able to pay professional tech writers to beef up the Rails documentation. It is true that it is not advancing quite at the same pace that rails is and Court3nay’s initiative is a worthy one.
He’s aiming to raise $5,000 and after just a few hours he has reached half his goal.
If you enjoy Rails, please consider making a small donation, $10, $20, or whatever you can spare. That’s an investments that is sure to provide a return! So please help.
Fund the Rails Documentation Drive.
Update: the total is now $13,310, from 94 contributors, in less than 24 hours. Thank you everyone that contributed! This is going to help improve the doc a great deal!
Posted in News, Rails
|
Tags rails
|
0 comments
Posted on Wed Aug 02 14:43:00 UTC 2006
According to Kyle, one of the tireless developer of Rad Rails, he is working on incorporating ruby-debug.
For more details about ruby-debug, see my write up about it.
The command line is great, and there are times when you are working on a remote server where nothing else will do. But having the ability to set breakpoints at the click of the mouse, see your variables in a separate pane, see a lot more of your source code is something quite convenient.
And with the added speed of ruby-debug, this should make debugging in Rad Rails something you can’t afford not to use.
This is very welcome news and I look forward to use it!
Posted in Rails
|
Tags rails
|
2 comments
Posted on Fri Jul 14 16:42:00 UTC 2006
Just a few days ago, Kent Sibilev quietly released an amazing little plugin with far reaching consequences: ruby-debug. This is a marked improvement over Ruby's own rdebug. The major difference is that he removed the major slow down that impacted rdebug usability with Ruby on Rails so it is blazing fast.
Instead of using the Kernel#set_trace_func API, which makes it possible to implement a debugger in Ruby, but has a negative effect on the speed on your program execution, he uses a native extension with a new hook using the Ruby C API
For each trace call Ruby interpreter creates a Binding object, even though it is not being used most of the time. ruby-debug library moves most of the functionality of debug.rb to a native extension, this way significantly improving the execution of your program.
This means that watchpoints and the standard tracing facility are not supported, but I'm gladly giving that up for the comfort and speed. And if you are wondering how the speed is, that is really the difference between utter frustration each time you debug something to bliss!
Previously I covered some options for Debugging in Rails. This is going to become my preferred option by far, and I'm willing to bet this will become yours too. Why? Because you can see the source code of where you are, you can execute step while watching some or your variables, you can inspect of your variables (this you could do with breakpointer), you can use conditional breakpoints, you can get a list of expressions to be displayed every time you step. The downside compared to breakpointer? You can't do it remotely, which in most instances, as best as I can tell, is not going to be a problem at all.
Installation
Ruby-debug comes as a gem so to install, just run:
sudo gem install ruby-debug
Make sure you chose the proper windows or ruby version depending on your platform.
Using ruby-debug
To use in your rails application, assuming you want this to only be available in development mode (this is not such a great idea to leave in in production mode, just in case you forget to remove the breakpoints, and also for performance reasons as I'll explain in a bit)
In environement.rb add the following:
SCRIPT_LINES__ = {} if ENV['RAILS_ENV'] == 'development'
This line is important if you want to be able to see your source code. SCRIPT_LINES__ is an obscure feature of the ruby interpreter. If it is defined, it will store all loaded ruby file in a hash, which debug-ruby will use to display where you are in your source code. The only problem is that it can have some impact on performance, and worst of all, use up quite a bit of memory, which is not so good in production (hence the "if ENV['RAILS_ENV'] == 'development'"). SCRIPT_LINES__ needs to be initialized as early as possible so it can capture all loaded ruby files.
To add a breakpoint, you will need to use:
require 'ruby-debug'
...
def your_method
...
debugger if ENV['RAILS_ENV] == 'development'
...
end
Then start your app using webrick (it does not work with lighttpd and I have not investigated why just yet):
script/server webrick
When the code hits the breakpoint, you are in a console like mode (not unlike irb or script/console).
Ruby-debug commands
- b[reak]
list breakpoints
- b[reak] [file|class:]LINE|METHOD [if expr]
- b[reak] [class.]LINE|METHOD [if expr]
set breakpoint to some position, optionally if expr == true
- cat[ch]
show catchpoint
- cat[ch] EXCEPTION
set catchpoint to an exception
- disp[lay] EXPRESSION
add expression into display expression list
- undisp[lay][ nnn]
delete one particular or all display expressions if no expression number given
- del[ete][ nnn]
delete some or all breakpoints (get the number using "break")
- c[ont]
run until program ends or hit breakpoint
- r[un]
alias for cont
- s[tep][ nnn]
step (into methods) one line or till line nnn
- n[ext][ nnn]
go over one line or till line nnn
- w[here]
displays stack
- f[rame]
alias for where
- l[ist][ (-|nn-mm)]
list program, - list backwards, nn-mm list given lines. No arguments keeps listing
- up[ nn]
move to higher frame
- down[ nn]
move to lower frame
- fin[ish]
return to outer frame
- q[uit]
exit from debugger
- v[ar] g[lobal]
show global variables
- v[ar] l[ocal]
show local variables
- v[ar] i[nstance] OBJECT
show instance variables of object
- v[ar] c[onst] OBJECT
show constants of object
- m[ethod] i[nstance] OBJECT
show methods of object
- m[ethod] CLASS|MODULE
show instance methods of class or module
- th[read] l[ist]
list all threads
- th[read] c[ur[rent]]
show current thread
- th[read] [sw[itch]] nnn
switch thread context to nnn
- th[read] stop nnn
stop thread nnn
- th[read] resume nnn
resume thread nnn
- p EXPRESSION
evaluate expression and print its value
- pp EXPRESSSION
evaluate expression and print its value
- h[elp]
print this help
- RETURN KEY
redo previous command. Convenient when using list, step, next, up, down,
- EVERYHTING ELSE
evaluate
Happy debugging!
Posted in Rails
|
Tags rails
|
29 comments