I cam across Sails.js a month or two ago and decided that, since I’m using AngularJS on the frontend, I might as well use Sails on the backend and keep the whole project in Javascript. Makes sense, right? It can’t be all that different writing Javascript (well, I prefer writing Coffeescript, but they’re interchangeable when it comes to this blog article) from the frontend, right? Not.

I dove into the very nice screencast on Sails and was captivated – a framework that does a lot of the work for me! This could be great. I did check – briefly – for a leading MVC framework for Node.js (akin to Rails for Ruby, Django for Python, etc.), but did not find a true leading project that stood out. Even though Sails was pre-v1, it seemed complete enough to get going.

I installed it, and got to hacking away creating a nice backend API for my project. Creating controllers and models went well. Policies seemed to work OK – I got hung up on exactly what was going on for quite some time, as I did not recognize that if a model exists, the same controller will be automatically created behind-the-scenes; however, the framework did differentiate between singular vs plural. And coming from a recent Rails background, I was rather opinionated about how I wanted it structured. So I ended up having to write all my own controllers, along with all my own routes. Very quickly my hopes of a framework that would let me build quickly fell apart.

Coupled with these challenges was the fact that although I knew Javascript fairly well, I did not know it nearly as well as Ruby, and did not know Node at all. So any time I wanted to do something like create packages, I was entering a whole new world I had absolutely no experience with. So it turned from picking up a framework that followed well-known principles to picking up a framework that followed well-known principles while learning essentially a new language.

The asynchronous nature of Node really tripped me up. I’m very much used to the blocking nature of other languages, and I find it easy to work with. For example, if I’m creating an instance of a model, which has associated models, and I need to save the parent instance before saving the associated models, I end up in callback hell. Why can’t it be as simple as making a method call, and then on the next line making the next method call? I ended up with the async.js library doing a lot of work, which clearly took away from the benefits of using node. This is not a gripe about Node – it’s a gripe about my skills (or lackthereof, in this case).

Finally, I came upon two realizations that led me switch back to Rails as the backend for my project. First, I recognized that I need to support browsers that aren’t supported by Angular, and I really, really want to keep using Angular. So I need another version of the site – which I might as well make pure HTML with no Javascript (this would allow me to also handle situations where users have Javascript turned off). My mind instantly went to Rails’ ability to respond with multiple formats; I didn’t even look into how I would handle that with Sails.

The second factor was a conversation I had with a colleague about using tools for building new projects. He brought up a few good points – first, using tools you know allows you to prototype much faster, as you’re not stuck learning something new in addition to building something that you don’t even know will be around in a few months. Secondly, the experience you have from those tools can really only be a benefit going forward – yes, in my case, Ruby is “slow”, and Rails has a lot built into it, but it’s also got a humongous community that I can tap into about how to speed up Ruby, and how I can make Rails perform much faster if necessary. I also know enough about Ruby and Rails to not be completely lost when researching, talking with others in the community, or needing to write extensions of my own or dive into the source code.

There you have it. The challenges I faced with Node, Sails, combined with the benefits of using technologies I already know led me to abandon Sails for this project, and keep going with Rails. But for those of you that are familiar with Node, and are looking for an actively-developed MVC framework, I strongly recommend you check out Sails. It’s fantastic, and it’s got a great, growing community. I just don’t have the time to learn nor to contribute (as much as I would love to); perhaps my next project will be in Sails!

I recently decided to switch to using Rails for a new project from Sails.js (I’ll detail the reasons in another post), and decided to take advantage of the latest-and-greatest. Ruby 2.0 is officially released and Rails 4 is on rc1, so I figured it’d be worth some small headaches to just jump on the bandwagon now, rather than using 3.x and attempting to port in all the nice things Rails 4 provides.

Having worked with Rails for the last year, and getting more and more comfortable with rspec as time goes on, I decided to start this project the “right way” and do TDD. To that end, I decided to start the app by installing rspec, guard and zeus to make sure I have a fast test suite. The following is the adventure these gems took me on as I attempted to get them all playing nice with Rails 4.

To finish setting up RSpec within Rubymine, we need to update the default configuration to use the new runner we just created.

Go into your Run/Debug configurations, select “Defaults”, then “Rspec”. Check the box that says “Use custom RSpec runner script:”, and in the text field that becomes editable enter the appropriate path to the runner script we created; e.g. “/path/to/my/project/script/rspec_runner.rb”.

To start, create a new run configuration by selecting “IRB Console”, and fill in the “IRB Script” line with the path to your rspec bin file. If you’re using RVM on OS X, it’ll be something like: “/Users/pragone/.rvm/gems/ruby-2.0.0-p0@example-app/bin/guard”. Set the working directory to the project’s root directory, and you’re off to the races!

The one downside is that I still haven’t found a nice way to *start* zeus within Rubymine; I still start it in the console (using our new script/start_zeus script: `ruby script/start_zeus`); after that, however, I just run the “Guard” configuration we created in the last step.

After all this, however, I still ran into problems. In the end, it was a misconfiguration in my spec_helper.rb file that was causing problems. Specifically, I had `require ‘rspec/autorun’` in there, and it should’ve been removed. I’ve attached my spec_helper.rb and Guardfile for reference here:

require 'simplecov'
SimpleCov.start
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] = 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
#config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = true
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
Capybara.javascript_driver = :webkit
#Capybara.javascript_driver = :selenium
#Capybara.server_port = 6543
config.mock_with :rspec
config.include FactoryGirl::Syntax::Methods
config.include Rails.application.routes.url_helpers
config.include RSpec::Rails::RequestExampleGroup, type: :feature
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.filter_run_excluding :slow unless ENV['SLOW_SPECS']
config.fail_fast = true
end