Here at MojoTech, we are lucky to have several engineers who have used Ruby on Rails from very early on in its history. For me personally, the year 2016 will mark a full decade of using Rails for application development. In total, we have four Mojos who were using Rails in those very early days, and while we now use many different programming languages and tools, the early days of MojoTech were established as a "Rails shop".
Having this much "time in the saddle" has allowed us to see quite a lot of different Rails styles and techniques, and today I'd like to share a few tips and/or tricks that are still useful to both beginner and veteran Rails engineers.
For those of you long time Rails developers like myself, this list is not meant to be exhaustive or entirely novel and should seem like common sense things; for the Rails beginner, this list should hopefully point out some minor things you can do to benefit you on your Rails journey.
Use the environment to customize your application
All too often, I still see projects where the engineering team creates a special "staging" or "qa" Rails environment file and uses these environments on their Q/A or Staging servers.
The better practice is, in the vast majority of cases, to stick to the core 3 environments: development, test, and production. Your Q/A and/or Staging servers should be run under the Rails "production" environment to duplicate the same code paths and logic your application will actually take once released to the Production server.
Customization for settings related to the app should be done through the operating system's environment and accessed in your code via
ENV. Need to fine tune some cache settings, customize where your mailers are sent to, or use different AWS credentials? Use the
ENV as it was intended and run your Rails app under
Send development mailers to the local filesystem
I still frequently see developers frantically scrolling back through their logs or
grep-ing log output for content sent via a mailer while in development.
There is a far easier solution; configure your development environment to send mailers to the local filesystem.
The following line dropped into your
development.rb environment file will do the trick:
config.action_mailer.delivery_method = :file
Now you can easily find all the mailers your application has sent in the
./tmp/mails/ directory (by default). One file will be created for each email address sent to that contains all email content delivered to that address. This allows you to easily review any and all emails sent without scraping your logs.
Use HTTP Auth on your non-production servers
A simple thing that is often overlooked when deploying those initial Q/A or Staging servers is to "hide" these machines from Google and other search engines. Neglecting to do this can and will result in these servers being indexed on search engines, many times with precedence over what will eventually be your live production site.
The first inclination might be to add a
robots.txt file to these servers, and while this will prevent well-behaved bots from indexing the site, it won't prevent all. Again, we can prevent access to these sites from bots and the general public with a simple HTTP authentication middleware.
if ENV['USE_HTTP_AUTH'] == 'true' config.middleware.use '::Rack::Auth::Basic' do |u, p| [u, p] == ['username', 'cool_password'] end end
Take advantage of the features of your database
As applications grow and develop over time, the need to optimize certain features arise. Often times, these optimizations can be handled at the database level instead of in Ruby code.
When starting new Rails projects, our preferred default at MojoTech is to use PostgreSQL and we have several applications that use SQL views (which, of course, are not a unique feature of PostgreSQL).
A caveat to using features like views is that the default Rails schema dumper format of Ruby can not properly dump this information. I've seen engineers not realize this, and add the creation/deletion of database views in a rails migration, but not pay attention and realize this information wasn't also dumped to
Rails has an alternative schema dumper format of native SQL which can be configured via a simple configuration setting:
config.active_record.schema_format = :sql
This change will result in a
db/structure.sql files instead of a
db/schema.rb file. The file will be specific to the particular database you are using and not portable like the Ruby schema dumper format is. However, the specifics of creating your views is also database specific, and, as such, using non-portable
structure.sql is not an issue.
Automate as many things as you can from the start
We typically reference "automation" when we talk about our deployment and maintenance processes with our servers. Your aim from the beginning should be to have your "deployment" process be completely automated.
Having a consistent, fully automated process in place pays dividends on any size project. If you find yourself having to manually do any part of your setup or deployment, automate it ASAP.
Models don't need ActiveRecord
Engineers often seem to overlook the fact that Rails is just a framework on top of Ruby. At the core, you are just working in Ruby. As such, modeling the code in your app is done like any other piece of software and this means that not every model needs to inherit from ActiveRecord.
Model your application components in a way that make the most sense, not solely based on what tables you have in your database store. Ruby classes are cheap and easy, and having a file in the
app/models directory does not require that Ruby class to inherit from
ActiveRecord::Base or even have anything to do with your persistence layers.
Again, Rails is just Ruby. Utilize that and take advantage of the language features provided by Ruby. Don't be afraid of structuring your code properly using Ruby modules and classes. You can create simple objects and compositions even if they don't explicitly follow the "endorsed" Rails-pattern. There is much, much more to your software than just a "Model, Controller, Helper, or View" file.
Don't skip the documentation
This topic relates both to the consumption and creation side of documentation. When writing code, don't neglect writing good, useful documentation where it is required.
The optimistic view is that good code is self-documenting, and while this is true in many cases, there are also plenty of cases where more complex business logic is required that would benefit from documentation.
Don't also neglect to reference documentation of the third-party gems and tools you use. With Ruby being an interpreted language, we have the added benefit of directly consulting source code when 3rd-party documentation is lacking. This is an immensely valuable luxury and can be used both for learning how something works internally, but also learning new engineering techniques, data structures, and algorithms.
Here's to 10 more years
We haven't covered anything ground breaking here, just a few small tidbits and basic things that have now become routine over time. I'd love to hear what kinds of small nuggets you all might have to add to the list as well.
We've come a long way and the community has grown and changed quite a bit from the small group of us at RailsConf 2006 in Chicago or 2007 in Portland. To those who have been on this same journey, congrats on your 10th anniversary, and to those just beginning the journey in the last few years, welcome and continue to move things forward.