April 28th, 2010 — How-To, Javascript, Ruby on Rails
Welcome back to TopSecretProject.
I have started using what I think is a pretty robust system for handling JavaScript in my Rails projects.
The basic process is this:
1) In order to create some modularity, each controller in my system has it’s own JS file. The controller file contains the code required for the views in that controller. I still have some higher level files for common and application-wide JS code.
2) Each of the controller files is scoped to a namespace:
//File: javascripts/controllers/dashboard.js
var dashboard = {
init: function() {
//kick-off code for the "dashboard" controller
}
}
3) I have a view helper that appends a load command to the layout. Loading is a matter of calling the namespaced init method: $(document).ready(dashboard.init);
The helper looks like this:
def load_controller_script(script = controller.controller_name)
content_for :javascript do
"<script type=\"text/javascript\">$(document).ready(#{script}.init);</script>".html_safe
end
end
And is included in my layout using: <%= raw(yield :javascript) -%>
Using “raw” because I am in Rails 3 land.
4) At deploy time I use the awesome asset_packager plugin to join all of the controller files into a single file, meaning I only have a single request for JS in my production system. The namespacing ensures that there are no conflicts across the many small files.
That’s it!
I am still investigating the most robust way to setup the namespaces. The above is simple, but not necessarily the best way to go about it.
It would be quite a simple matter to have the files be more granular – you could actually tie them to specific actions in your system. Controller is fine for my use-case as this particular app is very JS-centric and builds actions and views using AJAX and JS in the browser (so a lot of my actions return JSON rather than HTML).
November 23rd, 2009 — Ruby on Rails, Software Development
Busy times recently as I have two sites launched in the last week.
Lucky for me one of the sites was 10 Tips to Stress Less, full of useful advice on how to reduce stress.
The Stress Less campaign is coordinated by the Mental Health Association NSW (MHA) and has the aim of increasing community awareness of the risks of stress and providing tips and ideas on how we can all go about reducing the impact of stress in our lives.
The site is running on my own social “platform” thingy.
Stay tuned for more on this in the very near future.
The Techology
- Ruby On Rails
- Gems & Plugins:
- asset_packager
- acts_as_list
- clearance
- declarative_authorization
- facebooker
- formtastic
- hoptoad_notifier
- paperclip
- sanitize
- will_paginate
- vote_fu
- rSpec, Cucumber, Selenium
- PostgreSQL
- jQuery and a range of plugins
- Facebook Connect, XFBML, FBJS
- Heroku with the RPM add-on
Things I learned:
- Facebook Connect is awesome
- Ruby on Rails continues to be awesome
- Heroku is awesome times infinity
April 6th, 2009 — Future, Software Development
The executive summary:
Twitter prefer Scala rather than Ruby for some back-end processes.
Fun ensues
Some of the Twitter developers were recently intervied by Bill Veners on Scala: Twitter on Scala
Which seemed to raise the ire of many of the Ruby crowd in the infosphere. The fact that Twitterer(?) Alex Payne has a new Scala book smells of vested interest to many.
As Payne posted in Mending The Bitter Absence of Reasoned Technical Discussion:
the story … had gone from “Scala is a nifty language and you should think about it for your business to “Twitter engineer spits on the grave of Ruby, exalts Scala as shining new deity”
Tony Arcieri (REIA, Erlang) has a really great analysis of message queues and Ruby – the best part is some of the implicated Twitter developers address his points in the comments. The team evaulated various message queues and went with their own implementation (a Scala-based app called Kestrel).
The Twitter guys know their code, know their environment. They have tried a bunch of technologies, and have developed something that works for them.
However, it’s comments like this from the interview that really pique my interest:
I think it may just be a property of large systems in dynamic languages, that eventually you end up rewriting your own type system, and you sort of do it badly. You’re checking for null values all over the place. There’s lots of calls to Ruby’s kind_of? method, which asks, “Is this a kind of User object? Because that’s what we’re expecting. If we don’t get that, this is going to explode.” It is a shame to have to write all that when there is a solution that has existed in the world of programming languages for decades now.
Jeremy McAnally summed up my own thoughts on Twitter:
If you have to use kind_of? all over your code to mimic a “type system,” you’re doing it wrong.
Twitter: you’re doing it wrong!
I realise that I have no real right to be calling Twitter out here as my credentials with regards to developing the next big thing with a growth curve that is a straight line all the way up to world domination are currently nil.
But the secret truth of most large software projects is that the code often sucks.
See the Big Ball of Mud for more details.
So given Twitter’s code probably sucks, and your code probably sucks, and my code definitely sucks, what can we do?
I guess we assume they picked the right tool to make some of their code suck a little less.
Well done Twitter.
My takeaways:
The Rubyists are a pretty defensive group. I love Ruby and Rails. but still, I am hopefully not a member of the “cult”.
The JVM is just about the best platform there is for high-scalability. Not Java itself as such, but the JVM. I am fairly certain the future is going to be languages running on the JVM. I think Clojure is interesting for this reason – although Scala may be good middle ground as a future-proof language option. Lisps have a long history of being the best lanaguage ever that never made it to the mainstream.
Afterthought:
One other thing I do find very curious is that given the code-compile-deploy cycle still required by Scala is how it can really be as fast to develop in as Ruby or Python? During my time as a Java Developer, it was this cycle that was the real time killer. On any non-trival project the compile cycle will start eating minutes and deployment is necessarily complicated when pushing to servers with JAR/WAR deployment systems. I can understand how this trade-off may work for infrastructure (like a message queue) where changes are slow and largely internal, but for a web-level application where change is constant, it’s going to slow you down.
March 1st, 2009 — Ruby, Ruby on Rails
I have been delighting in the power of Active Record’s Named Scopes and recently discovered is a technique for cleanly adding user-driven filtering to Active Record models using Named Scopes and a little bit of Ruby magic.
Named Scopes provide a clean way of adding finders to your Active Record Models – collecting complex finder logic into granular methods that can then be chained together to perform complex combinations of queries. Named scopes are eminently testable as each defined scope can be tested individually, as well as the actual combinations of scope-chains.
Take the following example from some recent production code:
named_scope :by_author, lambda { |*args| {:conditions =>; ["author_id = ?", args.first] }}
named_scope :by_state, lambda { |*args| { :conditions => ["state = ?", args.first || "published"]
}}
named_scope :by_date, lambda { |*args| {:conditions => ["published_at BETWEEN ? AND ? OR updated_at BETWEEN ? AND ?", args.first[0], args.first[1] || Time.now, args.first[0], args.first[1] || Time.now]
}}
As you can see, some quite complex logic can be wrapped into the named scopes, including parameters.
The scopes can be chained, which wraps everything into a single query:
Model.by_author(author_id).by_state("published").by_date(10.days.ago)
Once you have your named scopes set up, you can add some magic to dynamically chain them for user-based filtering.
What follows is from Caboose’s: The awesomest filter and sort ever
In the controller I set up some code to grab incoming parameters and pass them to the Model (in this case called BlogPost).
filter_opts = {}
filter_opts[:page] = params[:page] || 1
filter_opts[:author] = params[:user]
filter_opts[:state] = params[:state]
filter_opts[:date] = [start_date, end_date]
@blog_posts = BlogPost.find_by_filter(filter_opts)
I have removed some of the processing logic here, but the idea is that the user selects from a range of filtering options in the User Interface (selecting a date range, for example) and the controller grabs, cleans and validates these as appropriate and passes it through to the model.
The find_by_filter method is where all of the magic happens. We add the valid scopes to an array, and then chain them all together using inject.
def self.find_by_filter(opts = {})
scopes = []
scopes =>; [:by_author, opts[:author] ] if opts[:author]
scopes => [:by_state, opts[:state]] if opts[:state]
scopes => [:by_date, opts[:date]] if opts[:date]
order = opts[:order] || "published_at DESC"
page = opts[:page] || 1
scopes.inject(BlogPost) {|model,scope|
model.scopes[scope[0]].call(model, scope[1])
}.paginate(:all,
rder => order, :page => page)
end
The final line is the magic. Using inject with the model as the accumulator, basically emulates the chained call we saw earlier (by_author.by_state.by_date), but with the added advantage in this instance that only the scopes with the relevant options (defined in opts) are called by the find_by_filter.
As you can see, not only are the named scopes chained together, but I am adding paginate for good measure. Records are cleanly paginated
For more information on named scopes see
Ruby on Rails Active Record Guide.