When you're developing an application in Rails (or Ruby), you spend lots of time in the IRB, the Interactive Ruby Shell. Usually just to test some Ruby code, start an application console or debug something going on inside the project. Yesterday, looking at a coworker screen, I saw he had his console with lots of color hints, and I thought it was pretty nice. I asked him about that and he told me he was using a special gem for that.
The gem is called wirble. It has some nice defaults and allows you to configure the colors as you wish. To use it in your consoles, just add this lines to your ~/.irbrc file:
If you ever try to run a GUI Java application when using xmonad as the Window Manager, you'll probably end up with a nice flat grey window where your buttons, toolbars and other desktop GUI goodies should be. I ran into that problem the other day when trying to evaluate the RubyMine Ruby on Rails IDE from which I heard such good things. After a rather painful installation of the official Java 6 JDK from Oracle in Ubuntu Lucid Lynx (which I'll write about in some other time), I managed to start up RubyMine just to find out I was seeing absolutely nothing on the screen.
Sometimes you need to use multiple databases in your Rails projects. Usually when some data must be shared between different applications. When this happens you usually have some models in a shared database, and some other models in the specific application database. This can be easily done using the establish_connection method in the shared models to tell them they have to connect to a different database.
However, when you need some interaction between those shared models and the models of your specific application, like a has_many, :through association, some problems arise. The typical Many To Many association uses an intermediate database table that links the relation between two models, and allows you to add some extra information on that relation. When navigating through the association, Rails tries to make an SQL query that joins the model with this intermediate table. For example, imagine you have a Team model, which has many Players, but a player can also be on more than one team. We use an intermediate model TeamPlayers (and we can also use it to save the role of that player into that team, for example). You would have those three tables:
teams
players
teams_players
When asking for the players of a given Team, Rails would do something similar to this:
SELECT"players".*FROM"players"INNERJOINteams_players" ON "players".id = "teams_players".player_id WHERE "players".team_id = 1
Where 1 is the id of the team you asked for. This [obviously] works perfectly fine when everything is in the same database, and it's as efficient as the SQL database manager you're using. What happens, however, when we have the Player model in another database? It will miserably fail because Rails will try to join with a table that doesn't exist.
Unfortunately, there's no efficient way to solve this problem, that is, using SQL, as you can't work with tables from different databases. However, there's a rather elegant solution that Brian Doll cared to implement as a gem a while ago. As indicated in the GitHub readme, you just have to use a has_many_elsewhere relation instead of the usual one, and make sure that the model referenced has the connection established to the shared database. And that's all.
The magic donde behind the scenes is pretty simple: this gem just replicates the same methods that the ActiveRecord::Base class does in the has_many method call, changing the failing unique SQL calls to double SQL calls, one for each database, fetching the intermediate models first, and then fetching the remote models using those ids.
This method is not perfect, as probably not all the goodness of the original association can be done with it, but for simple scenarios is more than enough.
Ubiquo is a Ruby on Rails, MIT Licensed Open Source CMS we develop and use at gnuine for a variety of projects. One of the features of Ubiquo is the ability to run jobs separately from the http requests to the site. Today I'm going to show you how to customize the Ubiquo Jobs plugin to create your own types of jobs and managers to launch them.
Sometimes can be useful to create different managers. An example of this situation is when you want to run different kind of jobs in different circumstances.
Ubiquo Jobs provides a default manager which will get ActiveJob jobs depending on priorities and schedule times:
defself.get(runner)recovery(runner)candidate_jobs=job_class.all(:conditions=>['planified_at <= ? AND state = ?',Time.now.utc,UbiquoJobs::Jobs::Base::STATES[:waiting]],:order=>'priority asc')job=first_without_dependencies(candidate_jobs)job.update_attributes({:state=>UbiquoJobs::Jobs::Base::STATES[:instantiated],:runner=>runner})ifjobjobend
The job_class variable defaults to UbiquoJobs::Jobs::ActiveJob. If you want to make your own manager to handle special jobs, or change the way the jobs are picked, the best way to do so is to implement your own manager. A nice rails-like way to do that is include them in the lib/ folder of your ubiquo project.
The class you should inherit from is UbiquoJobs::Managers::ActiveManager. If you wanted the manager to just pick up a specific subclass of ubiquo jobs, it would suffice to reimplement the self.job_class class method to return your own kind of job:
However, there’s a better way to do this. For this special case, the default UbiquoJob class provides a special member which stores the job’s class name, allowing you to select all objects subclasses of ActiveJob by its classname. For example, imagine you have a kind of job for special tasks that you know for sure will take a long time to complete. Seems reasonable to have a different manager to handle those jobs. You would create a new job in the file app/jobs/very_long_job.rb:
classVeryLongJob<UbiquoJobs::Jobs::ActiveJobdefdo_job_work#Do what needs to be done herereturn0endend
Then you could create a manager that handles only those kind of jobs by implementing your own subclass of the UbiquoJobs::Managers::ActiveManager class:
moduleJobManagersclassVeryLongJobManager<UbiquoJobs::Managers::ActiveManagerdefself.get(runner)recovery(runner)candidate_jobs=job_class.all(:conditions=>['planified_at <= ? AND state = ? AND type = ?',Time.now.utc,UbiquoJobs::Jobs::Base::STATES[:waiting],'VeryLongJob'],:order=>'priority asc')job=first_without_dependencies(candidate_jobs)job.update_attributes({:state=>UbiquoJobs::Jobs::Base::STATES[:instantiated],:runner=>runner})ifjobjobendendend
The code is exactly the same as the default ActiveManager class, but the finder will take an extra parameter, 'VeryLongJob', to indicate that only the ActiveJob objects that are of the subclass VerylongJob should be taken.
After that, you need to modify the task that calls the workers so it takes your manager, or create a new task that will run your manager. The default task that will
start a worker looks as this:
desc"Starts a new ubiquo worker"task:start,[:name,:interval]=>[:environment]do|t,args|options={:sleep_time=>args.interval.to_f}.delete_if{|k,v|v.blank?}UbiquoWorker.init(args.name,options)end
This uses a special configuration parameter to determine the manager to use. This configuration option is stored in Ubiquo::Config.context(:ubiquo_jobs), the name of the configuration option is :job_manager_class, and takes the manager class as a value. So in order to create a task that will use your manager, you should create a new task like this one:
desc"Starts a new ubiquo worker"task:start_very_long_jobs,[:name,:interval]=>[:environment]do|t,args|options={:sleep_time=>args.interval.to_f}.delete_if{|k,v|v.blank?}Ubiquo::Config.context(:ubiquo_jobs).set(:job_manager_class,JobManagers::VeryLongJobManager)UbiquoWorker.init(args.name,options)end
Your should call this task like this (assuming it’s on the same namespace as the default task):