How to get started with Rails as a JavaScript developer

Rails does a ton of stuff, and it has the reputation of including too much magic. I thought the same too! But now, I’m kinda used to this “magic”, and I don’t find it so overwhelming anymore.

So here are a few things about Rails that might help you get started. This list assumes that you have experience with backend web development using Node.js and Express, but I suspect a lot of the information will be similar if you’re experienced with something like Python and Flask.

1. You only need be comfortable with a small part of Rails to get started and to be productive

Even after many years of using Rails, I still don’t quite know how it initializes controllers or views. But controllers and views have always worked reliably, and I can be productive with the framework without knowing these details.

That said, it is helpful to keep these four in mind:

  • Controllers let you handle and respond to requests.
  • Models let you easily work with the database.
  • Views let you generate responses, including HTML or JSON.
  • The router lets you define which controllers should be used for which URLs or conditions.

2. There are lots of files and folders in a Rails app, but there are only a few primary ones you’ll work with

  • The app/ folder is important since that’s where most of your code will live.
  • The config/routes.rb file is important, but you don’t often need to look at the other files under config/.
  • The db/ folder is important since it keeps track of what the database schema looks like, and since it keeps track of all the changes that was made to your database schema.
  • The test/ or spec/ folder, depending on if the codebase you’re working on uses Minitest or RSpec respectively, is pretty important too.

3. The bundle program is like yarn or npm

  • The Gemfile is like your package.json file.
  • The Gemfile.lock file is like your package-lock.json or yarn.lock file.
  • bundle exec is like npx.

4. In Node, you have to require each external file whenever you need it, but it’s kind of the opposite in Rails. Most files and libraries get imported automatically

  • Ruby makes it so that all constants (anything that starts with a capital letter) are public by default and can be accessed from anywhere.
  • Rails automatically loads all the libraries listed in the Gemfile. This happens in the file config/application.rb (specifically the line that includes Bundler.require). There may be some exceptions though, like if the name of the library is different from what needs to be required.
  • Rails automatically loads all the Ruby files in your app/ folder. Since each file declares a class or module, each file is accessible from every other file.

All that said, if you have to explicitly require a file that you wrote and have in your app/ folder, you might have put the file in an incorrect place!

5. The naming of things is important. Some things need to be defined as singular, and others as plural

Rails likes to follow English rules. These usually just some conventions, and you can often configure title to be different. These conventions let Rails do things by guessing, and without you needing to give it thorough instructions.

For example, ActiveRecord has a few recommendations around naming:

  • The “has many” relation should have a plural target: has_many :friends
  • The “has one” relation should have a singular target: has_one :friend
  • The “belongs to” relation should have a singular target: belongs_to :friend
  • Database tables should always be plural.
  • Models should always be singular.

So when has_many is used, Rails knows to singularize the word, turn it from snake_case to CamelCase, and then find that class. Again, that’s just a convention, so you can override it and do it differently.

I do recommend following Rails’ conventions, even if it might seem a bit arbitrary. You kinda need to fight Rails to against its conventions.

6. Rails includes a bunch of security features turned on by default. Try not to disable them!

  • Think twice and double check before using html_safe or raw. It can open you up to XSS attacks.
  • You will probably need to disable CSRF handling if you’re writing API endpoints for third parties (maybe you’re the third party if you’re making a single page app outside of Rails). But do not disable it any other time!

Bonus: Metaprogramming

Metaprogramming is a pretty big category, and it’s basically code that writes code. It first took me a long time to understand what that meant, but here’s an example in JavaScript

var foo = ["a", "b", "c"];
var obj = {};

foo.forEach(function (letter) {
  obj[letter] = function () {
    return "You called the function: " + letter + "()";

obj.a() // => "You called the function: a()"

In the example above, we didn’t define three independent functions a, b, and c. Instead, we wrote some code that defined those functions.

Similarly, Ruby lets you dynamically create methods, classes, modules, and even variables! It can be helpful, but it can also get hard to read. So I’d generally recommend against metaprogramming if you can avoid it!

(But it’s also pretty fun, so don’t let me stop you 😉)

Bonus: Monkey patching

Monkey patching is when you “re-open” some code that you don’t own, then override or add something. Here’s another example in JavaScript:

// In the browser console on
React.hello = function () { return "there" }
React.createElement = function (a, b, c) { return "no YOU createElement" }

React.hello() // "there"
React.createElement('h1', {className: 'greeting'}, 'Hello there') // "no YOU createElement"

Monkey patching is common in Ruby because you can override and extend basically anything. One of Rails’ own libraries, ActiveSupport, is the most well known, and it extends Ruby with lots of convenient features.

I generally would recommend that you avoid writing monkey patch since changes are global. You or your colleagues might run into bugs or unexpected behavior. And you generally don’t have to anyway! There’s usually a better, safer way than monkey patching.

Ruby does have a relatively unused feature called Refinements, which lets you monkey patch much more safely. There are good resources online if you are curious, including the official documentation.

Bonus: Where to put code

Models go in app/models, controllers go in app/controllers, and etc. But what goes in a model, and what goes in a controller?

  1. Most code goes into the controllers. I’d say this was the “original” way of doing things. Since the “controller” is the manager, or the doer, it kinda makes sense to put the code that does stuff here.
  2. Most code goes into the models. This has a name, “fat models, skinny controllers”, and I’d say it was a critique of the first option. Since models are easier to test, and since model methods are more reusable than controller methods, it makes sense to put code here too. (One danger of going this route is that you might end up with “god objects”—objects that are everywhere and do everything.)
  3. Most code goes elsewhere. People often call them “services” and put them in app/services. This way makes sense too, since these plain Ruby objects are small and easy to test, and since it keeps models and controllers relatively smaller too. Again, I’d say this was a critique of the second option.

So what is the right way? A lot of it will depend on what your coworkers think. But here are some tips:

  • Put code in your ActiveRecord models if it’s closely related to reading, writing, and validating database records.
  • Otherwise, try putting code in controllers, and see if someone says there’s a better place.
  • If you find that you repeated your exact logic too much, it might make sense to put it into a different class. Putting them in app/services is a pretty safe bet.

That’s kind of it! But I do want to mention one more thing (I wouldn’t necessarily call it a tip).

You can put non-ActiveRecord files in app/models. I think this is a good choice when you’re writing business logic or external services that you can model as objects. Here are some examples where each returns something like an array of GoogleResult instances:

  • Good: GoogleResult.query(term)
  • Worse:
  • Worse:
  • Worst: User.search_google(term)

The first option is the most object oriented way, and the middle two are more imperative. There are pros and cons to both kinds of approaches, but Ruby is largely an object oriented language, and I think Rails feels most natural when writing code like the first.

Bonus: Recommended resources

I learned Rails a long time ago, and I learned Ruby even longer ago, so it’s hard for me to recommend good resources for learning Rails. That said, I know that I found the Rails Guides very helpful!

There’s a framework called Sinatra that’s very similar to Express. I wouldn’t necessarily recommend it, but it might be helpful to play with it to get familiarized with the Ruby web ecosystem, but without all of the extra features that Rails comes with.

Remember there isn’t any “magic” in the Rails codebase. It’s just code that a bunch of wrote and shared with the world. You can open it up, read it, and understand it if you wanted.

That’s it for now! Hope this helps you start working with Rails.

Thanks to Noorulain for suggesting improvements!

Posted on 2022-04-18 08:54 PM -0400
© Copyright 2008–2023 Zach Ahn