-
Some time ago I worked on a javascript game. One of the major issues I had to overcome, was that all my data would be gone on a page reload or when closing and opening the browser. I've been doing javascript for quite some time now, but I never gave this issue much thought until that time. After searching for a solution, I came out disappointed.
I had an object named "game" that contained all the other objects, players, stars, galaxy and they all cross referenced each other (similar to any has many and belongs to associations). Ideally, this would be stored and rebuild on page load.
So I came up with my own implementation, which I'll be open sourcing today: https://github.com/viseztrance/perseverance
If you have any issue, feel free to mail me or open a ticket. However you may want to run the jasmine tests first.
-
Inheriting a legacy application doesn't really have to be a chore. Bringing everything up to date is rewarding in its own way, although writing a ton of new tests isn't the most exciting thing around.
Once everything was at a point we were comfortable with, we replaced the tightly coupled fixtures with Factory Girl. I knew there's a significant performance penalty to be paid, but it was rather shocking. At 20 minutes, the test suite took almost twice as long.
I refactored some tests, mostly replacing FactoryGirl's create method with build_stubbed for non database operations but managed to shave off only two minutes.
After some research, it looked like a user was created for every controller spec. There were legitimate cases, but most of the time this wasn't the case. So I ended up doing the following - a controller's current_user method gets stubbed by default, whereas if a current_user argument is passed it gets created as an AR object, for instance:it "does stuff", current_user: true do
# doing stuff
end
The code responsible looked similar to the following:RSpec.configure do |config|
config.before :each, type: :controller do
user = if example.options[:current_user]
FactoryGirl.create(:user)
else
FactoryGirl.build_stubbed(:user)
end
controller.stub(:current_user).and_return(user)
end
end
The tests were faster at almost 12 minutes, but they still felt slow. Rspec's "--profile" flag didn't return any major offenders and just confirmed that most of the tests were just "slow". Trying to shave a few more seconds, I tried to use the same current_user approach to restrict search indexing.
As we were using an acts_as_solr:RSpec.configure do |config|
config.before :each do
solr_models = [Model1, Model2, #..]
solr_models.each do |model|
if example.options[:search]
ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "type_t:#{model}"))
model.configuration[:if] = true
else
model.configuration[:if] = false
end
end
end
end
Not the cleanest implementation around, but it got the job done. The results were surprising to say the least. The tests took almost two and a half minutes, which is quite ok for over one thousand tests.
-
From time to time I get stumped - I just can't find a *good* name for a class, method or variable. Sometimes I search for synonyms online or ask a colleague for suggestions. However, the naming conventions used in rails makes things easier, yet they may not scale very well.
For example, a polymorphic comment association is usually named commentable, whereas for an image - imageable. Simple enough, but the fact is that I actually ended up with names such as photoable, wallable and wizzardable (I kid you not).
Right now I'm using parent, and it works great.belongs_to :parent, :polymorphic => true
However, parent.parent.post is not as informative as imageable.commentable.post, but frankly this is hardly a problem. Based on this railscasts episode, I could get the current parent inside a controller by using the following:def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
Do this for images as well, and you'll probably see a pattern. So how about we just rewrite it in the application controller:def current_parent
return @current_parent if @current_parent
params.each do |name, value|
if name =~ /(\w+)_id$/
@current_parent = $1.classify.constantize.find(value)
return @current_parent
end
end
nil
end
So using parent actually makes sense.
If your application gets large enough, or you need to fix a bug on an older project you'll probably notice one thing - you can't recall the column names. Was it name, subject, title or content, contents, description? This gets even worse if you haven't wrote that code in the first place. For more than a year, on the projects I've been working on (which have been quite a few) I decided on always sticking with name for single line descriptions (varchar) and contents for the ones with multiple lines (text). There may be other fields of course, but this worked out surprisingly well.
It feels nice when a colleague writes the frontend and doesn't even need to look over the database schema. -
My first contact with nodejs was at Yahoo's open hack event that took place at Bucharest last spring. It was fun, however I just couldn't find the time to tinker with it as much as I would've liked to.
Lately this changed, and I'm actually using it for a project we're developing at work where it fits the bill quite nicely. While I'm quite familiar with javascript I'm coding in coffeescript. Initially I was reluctant on using it especially as I'm not very found of indentation based languages, but as far as backend javascript developing goes, it's a god send.
I think that the main reason I like it despite its flaws (it's just a wrapper after all) is that it almost forces good coding practices such as using short methods and avoiding deeply nested constructs.
I'm using the emacs coffee mode extension to compile my coffee files to js on each save. I imagine that most major editors have similar extensions as well.
Restarting node on each change can get a bit tiresome. To resolve this I'm using the supervisor plugin:npm install -g supervisor
And instead of starting the application with node:supervisor -p server.js
Basically the browser can now be refreshed on each coffee file change. Neat.
-
I recently wrote a sitemap gem for one of the more larger sites I have been working on, which was recently revamped.
To be fair I searched for existing solutions, but I found them lacking for one reason or another. One of the main problems that these plugins couldn't overcome was generating a different url (such as dynamic domains) based on an existing attribute.
There are some limitations as well, most notably the 50.000 urls per sitemap, but I'm planning on resolving this issue some time in the near future.
If you decide to test it I strongly believe that the docs cover the functionality pretty well. Additionally make sure using webmaster-tools that google bot can use your feed.
-
Just as I don't like mixing tabs with spaces I hate it when people type in a form using their real name without any concern for capitalization.
I could had certainly write a one liner that fixes this, but I recently started using the namecase gem which also provides some more interesting cases as well:NameCase("RON BURGUNDY") # => Ron Burgundy NameCase("MCDONALDS") # => McDonalds
-
Internet Explorer 9 was recently launched and received an overwhelming amount of positive reviews as well as a nice welcome from the developer community.
My thoughts about it remind me of a story I heard many years ago.A child's obnoxious behavior upsets his father on a daily basis. The afflicted parent would sometimes hammer a nail onto a door. After a while the curious child asked about the nails - "I've put a nail every time you made a bad deed", his father sorrowly answered. Later on, somewhat troubled, the child told his father "Look, I've thought about it and I don't want to upset you again, but for each day I behave you will take out a nail." The two were in agreement and as the days passed the parent would remove one nail after the other. One day the boy noticed that the nails were all gone. Happy, he called out his father "Look, I made it, the door doesn't have any more nails". "You're right", his father answered, "but what about the holes?"
While it's really nice that IE is once again a good browser, it's just not going to give me back all the nights I lost hacking layouts for the better half of the last decade. -
I can honestly say that the main reason for helping others is selfishness, because you see there's a certain feeling of accomplishment when helping someone with an issue that eluded me as well.
A few years ago I found my self spending quite some time on various forums. While it was mostly procrastinating I had the distinct feeling that I was actually contributing to something. After moving out from my parents house, on to the big city I met some very cool people, that had a lesser interest in an online presence and more of a hands on approach to tackle real problems. I was now reading the source code rather then browsing outdated blog posts.
One day, having a project with a tighter deadline and a long commute I was working from the comfort of my home trying to finish up. I was almost there, just needed to implement a pure javascript survey module by detecting the most common element in an array. Not a difficult task per se, but once you begin to feel tired, lousy code doesn't look that bad anymore. I took a short nap to rejuvenate my strength, but before doing so also asked a question on this new website popping up in the results all the time, named StackOverflow. Upon waking up I found a few answers, but most importantly they worked. It almost felt like cheating.
Since then I answered other people questions on SO every now and then. Reward points are being granted by doing so which feel quite nice. What didn't felt so nice was that answers to difficult questions were more unlikely to be voted up, probably because few had the knowledge to understand them, while easier common day issues would get way more attention. Suffice to say that the very system that made it so great was also its greatest fault. As post quality dropped, so did my interest.
Granted, I found many gems there, but it's time to walk away and wait for the "next thing". -
I recently worked on a project that generated some custom images using RMagick. There were several texts involved with some spanning over multiple rows. While RMagick does provide a caption method that wraps the text, I found it rather limiting. So instead I used the more powerful annotate method which allowed me to set my own font and text position.
Having just a canvas (an RMagick image for background), I started by creating a new drawing object:drawing = Magick::Draw.new
I then used a method for splitting the text into rows (stolen from a rails helper):def word_wrap(text, columns = 80)
text.split("\n").collect do |line|
line.length > columns ? line.gsub(/(.{1,#{columns}})(\s+|$)/, "\\1\n").strip : line
end * "\n"
end
Writing the actual text was easier than I initially thought.position = 80
word_wrap(my_long_text, 90).split(\n).each do |row|
drawing.annotate(canvas, 0, 0, 200, position += 20, row)
end
The text is being added at the 200, 100 coordinates, with a line height of 20. That's it. -
I just published the code that handles the screenshots of mywebsit.es.
Either use "gem install website_screenshot" or head over to github to get it. I also posted a web service demo to make implementation more straightforward.
Dependencies include ruby 1.8.6 or higher, ruby qt and curl.
Tested on Ubuntu LTS and Fedora.