It's a question I've been asking myself as I switch between different Rails applications for different clients. In my early days of working with Rails, I had a preferred selection of gems that I liked to use and that I stuck with for many Rails applications. After a few upgrade issues on a couple of applications I started to pay more attention to how I build applications with Rails. I questioned the gems that I was using and my testing practices. As I've gained more experience I've started to see that working closely to the Rails framework when building applications has some benefits that I previously overlooked.

What you're about to read isn't a silver bullet approach to building Rails applications. This is simply a guide to what I've find works for me.

Application Architecture

In the past most applications I worked on followed the old favourite of "fat model, skinny controller". Most applications tightly followed the MVC pattern and very few classes or objects were located outside of these three folders of the application. It does work, otherwise Rails wouldn't be as popular as it is, but following the MVC pattern did present one problem. Models became huge wells of code as they tried to contain the bulk of the application's code. Now I try to follow some best practices when coding but I don't strictly adhere to them, but you have to admit that a model with a 1000+ lines of code could probably be trimmed down a bit.

Since reading and watching a number of different ways in organising your Rails application, I've started to see the argument for extracting business logic into individual classes. You might be thinking of service objects or Hexagonal Rails when I say this. It's the same idea. I've started to keep classes that contain business logic in the app folder, alongside the rest of the application's objects. The reason for this is that I see the business logic as being part of the application, not a seperate layer or component of the application. I'm using Rails for my application, so I want to keep the business logic close to the rest of the application.

Gem Dependencies

Gems sure are handy. Just add to the Gemfile, install and your application has access to new functionality when it needs it. While adding gems is the easy way to add functionality to your application, you then have a dependency on that gem to stay maintained.

Before you even begin adding the gem to your Gemfile, ask yourself if it is truly necessary for your application?

In the past I would happily add a gem that I thought I needed, but now I take a different stance on it. If a gem provides just a small bit of functionality to the application, I take the time to spike a similar or better solution for the application on my own. The reason for this is that sometimes a gem won't do everything you need it too. If it can provide everything you need then great, but if it only provide most of your needs, could you add the complete functionality that you need by yourself?

Building this functionality on your own isn't always the best way to go, but if your application has specific requirements, then I say it's definitely worth looking at. Rolling your own solution to your application's requirements means that your solution could be a better fit for your application than anything else that's out there. It also means that with your own solution, you are responsible for keeping it maintained. Lastly, it keeps your Gemfile lean and the dependencies for your Rails application lean. I don't suggest you do this for everything, just the gems that you might question over their suitability for your application.

Testing

In the past I was a keen advocate of Cucumber and RSpec. That has changed over the last year. I'm finding that the testing tools that Rails provides are more than adequate for new Rails projects and sometimes better suited for smaller Rails projects.

Out of the box Rails provides Minitest through Ruby to write your tests and fixtures to organise the data you want to test against. Minitest is flexible in that you can write tests or specs depending on your preference, so I don't have any issues there. Minitest in a new Rails application is straightforward and it doesn't require any changes to your application's setup to get it working. Why even bother changing?

The real benefit I've seen though is in doing testing the Rails way is by using fixtures. They do require some initial effort to put together, but they're always there for subsequent tests runs and soon you'll start re-using fixtures for different tests and rarely have to touch them.

Rails is a database backed web application framework. Now I've seen the arguments for isolating the database from your tests, but for a framework that persists its data to the database, I think it's overkill to start stubbing out calls to the database and canning data using factories. This is why I like using fixtures. It's real data you're working with. A complete working set of test data.

Finally, an argument against using fixtures in the past was that tests took too long to run. I have to say that this is not a concern now. I have worked on a number of Rails projects using Minitest and fixtures and while their test and assertion counts run into the hundreds, I've yet to see a test suite take longer than 30 seconds. And even if your test suite is on the large side, it shouldn't be a major concern as you should have your tests automated to run as you edit your code by using something like Guard or Spork.

So What is The Rails Way?

Since I've made a few changes in how I build Rails applications, I'm definitely a more productive developer and I'm able to build new features with minimal fuss. The Rails way for me is working with the tools that Rails provides and building an application as close to the application's own models, controllers and views as you can. Simple patterns and designs are available to reduce complexity but aren't always necessary. I don't suggest you immediately think about re-writing your whole application to fit around these three suggestions, but bear them in mind for any future Rails projects that you have.