Ruby Framework

Ruby on Rails

Rails é o framework full-stack de Ruby construído sobre a filosofia de convenção sobre configuração. Ele decide as partes tediosas — nomes de arquivos, nomes de tabelas, rotas — para que você possa dedicar seu tempo ao produto.

intermediate15 min readUpdated 16 de set. de 2026
app/controllers/posts_controller.rb
ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: %i[show update destroy]

  def index
    @posts = Post.includes(:author).published.recent
  end

  def create
    @post = Current.user.posts.build(post_params)
    if @post.save
      redirect_to @post, notice: "Post created"
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body)
  end
end
Lançado
2004
Criado por
David Heinemeier Hansson
Linguagem
Ruby
Estilo
Convenção sobre configuração
Camada de dados
Active Record ORM
Versão
8.x

Por que importa

Por que o Rails é tão rápido para desenvolver

CRUD em uma tarde

Generators, migrations e scaffolding transformam um modelo de dados em uma aplicação funcional com banco de dados em horas, em vez de semanas.

Convenção sobre configuração

Padrões sensatos decidem nomes de arquivos, nomes de tabelas e rotas. Você os sobrescreve apenas quando seu domínio realmente precisa de algo diferente.

Gems para tudo

Autenticação, pagamentos, upload de arquivos, busca e dashboards administrativos possuem gems maduras e testadas em produção, mantidas pela comunidade.

O panorama completo

MVC, convenções, gems

O Rails dá a cada requisição o mesmo formato: uma rota, um controller, um model e uma view, nomeados da maneira que o framework já espera.

Convenção sobre configuração

Decidir

O framework faz a escolha padrão para que você nunca precise fazer. Um model Post mapeia para uma tabela posts e uma rota /posts sem configuração.

Active Record

Persistir

Models envolvem tabelas do banco de dados com associações, validações, scopes e migrations, mantendo o SQL fora do seu código cotidiano.

Recursos RESTful

Expor

resources :posts declara as sete rotas CRUD convencionais, e os controllers seguem as mesmas ações para cada recurso.

HTML5 de uma olhada

A caixa de ferramentas do Rails

Rotas RESTful

resources :posts fornece index, show, new, create, edit, update e destroy.

Active Record

Models, associações e migrations descrevem seu schema em Ruby.

MVC

Controllers coordenam, models detêm o domínio, views renderizam a resposta.

Generators

rails generate escreve models, controllers, migrations e testes para você.

Hotwire

Turbo e Stimulus adicionam interatividade sem a necessidade de uma SPA separada.

Background jobs

Active Job com Sidekiq executa tarefas lentas fora do ciclo de requisição.

Uma breve historia

Duas décadas do jeito Rails

  1. 2004

    Rails é extraído do Basecamp

    David Heinemeier Hansson extrai um framework da base de código do Basecamp e o lança como open source.

    04
  2. 2005

    Rails 1.0

    O primeiro lançamento estável torna a convenção sobre configuração uma ideia dominante no desenvolvimento web.

    05
  3. 2008

    Rails 2

    REST torna-se o estilo de roteamento padrão e recursos moldam cada controller.

    08
  4. 2010

    Rails 3 e Bundler

    Uma API mais limpa, Bundler para dependências e a fusão com Merb modernizam a stack.

    10
  5. 2016

    Rails 5 e Action Cable

    WebSockets chegam ao core, e o modo API-only foca em front-ends de página única.

    16
  6. 2021

    Rails 7 e Hotwire

    Turbo e Stimulus substituem o Turbolinks, e import maps entregam JavaScript sem um bundler.

    21
  7. 2024

    Rails 8

    Solid Queue, Solid Cache e Solid Cable rodam no banco de dados, e o Kamal simplifica o deployment.

    24

O guia completo

Ruby on Rails: Tudo que voce precisa saber

O que é Ruby on Rails?

Rails é um framework web full-stack para Ruby. Ele já vem com tudo o que uma aplicação web baseada em banco de dados precisa: um ORM, um roteador, uma camada de visualização, jobs em segundo plano, mailers, caching, WebSockets e um ambiente de testes. Em vez de escolher e conectar cada uma dessas peças manualmente, você herda uma stack coerente que foi projetada para trabalhar em conjunto.

Sua ideia central é a convenção sobre a configuração. O framework assume uma estrutura sensata — Post vive em app/models/post.rb, mapeia para uma tabela posts e é servido por PostsController — e você só escreve configurações quando decide desviar desse padrão. A equipe do Rails chama essa filosofia de omakase, a escolha do chef: confie nos padrões e você avançará mais rápido.

Essa troca é a razão pela qual o Rails impulsiona produtos desde Basecamp e GitHub até Shopify e HEY há vinte anos, e por que um único desenvolvedor ainda consegue entregar uma aplicação robusta em um único fim de semana.

Convenção sobre configuração

Todo projeto Rails possui o mesmo esqueleto, então você nunca fica na dúvida sobre onde colocar cada coisa.

app/
├── controllers/    # request handling
├── models/         # domain and persistence
├── views/          # templates
├── jobs/           # background work
├── mailers/        # email
└── javascript/     # Stimulus controllers
config/
├── routes.rb       # the URL map
└── database.yml    # connection settings
db/
└── migrate/        # schema history

A vantagem disso é a previsibilidade. Um novo desenvolvedor abre o repositório e já sabe que o model User está em app/models/user.rb e que sua tabela é users. A nomenclatura não é um debate de estilo; é uma interface da qual o framework depende.

O ciclo de requisição MVC

O Rails é um framework Model-View-Controller, e cada requisição HTTP segue o mesmo caminho:

  1. O Routing associa a URL a uma action do controller.
  2. O controller carrega ou altera dados através dos models.
  3. Os Models aplicam as regras de domínio e se comunicam com o banco de dados.
  4. Uma view renderiza a resposta, geralmente como HTML.
# config/routes.rb
Rails.application.routes.draw do
  resources :posts
  root "posts#index"
end

Uma requisição para GET /posts chega ao PostsController#index, que prepara @posts, após o qual app/views/posts/index.html.erb é renderizado. Manter cada camada focada em sua responsabilidade é o que torna um app Rails sustentável à medida que ele cresce.

A linha de comando é o framework

Você quase não toca no Rails através de arquivos de configuração. A maior parte do trabalho acontece no terminal.

rails new shop --database=postgresql
cd shop

bin/rails generate scaffold Post title:string body:text published:boolean
bin/rails generate model Comment post:references body:text
bin/rails generate controller Pages home about

bin/rails db:create db:migrate
bin/rails server

O generate escreve o model, a migration, o controller, as rotas, as views e os testes para você, e a saída do generator informa o que foi alterado. Leia cada arquivo gerado antes de mantê-lo — a maneira mais rápida de aprender Rails é estudar o que ele escreve e, em seguida, deletar o que você não precisa.

Active Record: a camada de model

O Active Record é o ORM. Uma classe de model encapsula uma tabela do banco de dados, e uma instância encapsula uma linha.

Migrations

Migrations são alterações de schema versionadas e reversíveis armazenadas em db/migrate. Elas são a única maneira suportada de alterar o banco de dados.

class CreatePosts < ActiveRecord::Migration[8.0]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.boolean :published, default: false, null: false
      t.references :author, null: false, foreign_key: { to_table: :users }
      t.timestamps
    end

    add_index :posts, %i[published created_at]
  end
end

Execute bin/rails db:migrate para aplicá-la e bin/rails db:rollback para desfazê-la. Como change é reversível, o Rails sabe como reverter as operações sem que você precise escrever um método down.

Associations

Associations descrevem relacionamentos e geram métodos convenientes.

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, through: :posts
end

class Post < ApplicationRecord
  belongs_to :author, class_name: "User", inverse_of: :posts
  has_many :comments, dependent: :destroy
  has_one_attached :cover
end

Com isso configurado, user.posts, post.author e post.comments.create(body: "...") funcionam, e dependent: :destroy mantém linhas órfãs fora do banco de dados.

Validations e scopes

Validations protegem o domínio na camada de model, por onde passa cada escrita.

class Post < ApplicationRecord
  validates :title, presence: true, length: { maximum: 120 }
  validates :body, presence: true
  validates :slug, uniqueness: true

  scope :published, -> { where(published: true) }
  scope :recent, -> { order(created_at: :desc) }

  before_validation :generate_slug, on: :create

  private

  def generate_slug
    self.slug ||= title.to_s.parameterize
  end
end

Scopes retornam relations, portanto, eles são compostíveis: Post.published.recent.limit(20) lê-se como uma frase e é executado como uma única query. Quando um scope ultrapassa uma ou duas linhas, promova-o a um método de classe para que permaneça legível.

Evitando queries N+1

O problema de performance mais comum no Rails é a query N+1: uma query para uma lista e, depois, mais uma para a association de cada linha.

# Two queries total, no matter how many posts.
posts = Post.includes(:author, :comments).recent

posts.each do |post|
  puts "#{post.title} by #{post.author.name}"
end

Use includes quando for acessar a association, preload quando quiser uma query separada, e eager_load quando também filtrar pela association. Adicione a gem bullet ao ambiente de development e ela sinalizará cada N+1 antes que chegue à produção.

Controllers e rotas RESTful

resources declara as rotas CRUD convencionais e as mapeia para ações do controller com nomes correspondentes.

# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end
end

Os controllers devem permanecer “magros” (thin). Eles carregam os dados, chamam o domínio e escolhem uma resposta. A lógica de negócio pertence aos models ou objetos de serviço, não às ações.

class PostsController < ApplicationController
  before_action :set_post, only: %i[show update destroy]

  def index
    @posts = Post.published.includes(:author).recent
  end

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to @post, notice: "Post created."
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body, :published, tag_ids: [])
  end
end

Strong parameters não são opcionais. params.require(:post).permit(...) é a fronteira que impede que um cliente defina colunas que você nunca pretendeu, como admin ou role.

Views, ERB e layouts

Views são templates ERB: HTML com Ruby incorporado. O Rails escapa a saída por padrão, o que elimina toda uma classe de bugs de cross-site scripting.

<%# app/views/posts/index.html.erb %>
<h1>Posts</h1>

<%= link_to "New post", new_post_path %>

<ul>
  <% @posts.each do |post| %>
    <li>
      <%= link_to post.title, post %>
      <span><%= pluralize(post.comments.size, "comment") %></span>
    </li>
  <% end %>
</ul>

Use <%= %> para imprimir a saída e <% %> para executar sem imprimir. Um layout em app/views/layouts/application.html.erb envolve todas as páginas, e partials — arquivos que começam com um underscore — permitem que você reutilize a marcação com render "post", post: post ou simplesmente render @posts.

Hotwire: Turbo e Stimulus

O Rails moderno adiciona interatividade sem a necessidade de uma single-page app. O Turbo intercepta links e formulários e troca fragmentos de página via rede; o Stimulus adiciona pequenos comportamentos em JavaScript onde eles são genuinamente necessários.

<%# Turbo Frames scope an update to one part of the page %>
<%= turbo_frame_tag "comments" do %>
  <%= render @post.comments %>
<% end %>
// app/javascript/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["menu"];

  toggle() {
    this.menuTarget.classList.toggle("hidden");
  }
}

Isso é aprimoramento progressivo na prática: o HTML renderizado no servidor é a base, e o JavaScript o aprimora. A maioria dos apps Rails nunca precisa de um roteador no client-side.

Assets e import maps

O Rails 7 substituiu o antigo pipeline do Sprockets por import maps por padrão e oferece o Propshaft como um asset pipeline mais simples. Você pode fixar (pin) uma biblioteca sem a necessidade de uma etapa de build com Node.

bin/importmap pin local-time
bin/rails assets:precompile

Se você prefere um bundler, bin/rails javascript:install:esbuild ou :vite altera a configuração. O princípio é o mesmo: servir o que o navegador entende e manter a toolchain fora do caminho até que você precise dela.

Background jobs

Qualquer tarefa lenta — enviar e-mail, chamar uma API, gerar um relatório — deve ficar em um job, não na requisição. O Active Job é a interface comum; o adapter decide onde os jobs são executados.

class PublishPostJob < ApplicationJob
  queue_as :default

  retry_on Net::ReadTimeout, wait: :polynomially_longer, attempts: 5

  def perform(post_id)
    Post.find(post_id).publish!
  end
end

PublishPostJob.perform_later(post.id)
# config/application.rb
config.active_job.queue_adapter = :solid_queue # or :sidekiq

O Rails 8 já vem com o Solid Queue, que armazena os jobs no banco de dados e dispensa o uso de Redis, reduzindo a complexidade de apps que rodam em um único servidor. O Sidekiq continua sendo uma escolha robusta para altos volumes.

Testes

O Rails gera testes para tudo o que cria. O Minitest já vem integrado e é rápido; o RSpec é a alternativa popular com uma sintaxe mais expressiva.

# test/models/post_test.rb
require "test_helper"

class PostTest < ActiveSupport::TestCase
  test "requires a title" do
    post = Post.new(body: "Hello")
    assert_not post.valid?
    assert_includes post.errors[:title], "can't be blank"
  end
end
# spec/models/post_spec.rb
RSpec.describe Post, type: :model do
  it "is invalid without a title" do
    expect(Post.new(body: "Hello")).not_to be_valid
  end
end

Testes de controller fazem requisições reais no processo, o que captura bugs de roteamento e parâmetros que os testes unitários deixam passar.

# test/controllers/posts_controller_test.rb
class PostsControllerTest < ActionDispatch::IntegrationTest
  test "lists published posts" do
    Post.create!(title: "Hi", body: "There", published: true)
    get posts_url
    assert_response :success
  end
end

Execute tudo com bin/rails test ou bundle exec rspec. Adicione bin/rails test:system para testes de sistema via browser quando um fluxo for importante o suficiente para ser testado de ponta a ponta.

O console do Rails

bin/rails console inicia a sua aplicação com todos os models e helpers disponíveis. É a maneira mais rápida de explorar dados, testar uma query e reproduzir um bug.

bin/rails console
bin/rails console --sandbox   # rolls back all changes on exit
Post.published.recent.limit(5)
Post.where(published: false).update_all(published: true)
Post.includes(:author).find_each { |post| puts post.title }

--sandbox funciona como uma rede de segurança enquanto você experimenta: qualquer gravação é revertida (rolled back) quando você sai.

Melhores práticas

  • Mantenha os controllers enxutos; mova a lógica de domínio para models ou service objects.
  • Utilize eager load em associações com includes e monitore os logs para evitar queries N+1.
  • Altere o banco de dados apenas através de migrations e faça o commit delas junto com o código.
  • Use strong parameters para cada operação de escrita e valide na camada de model.
  • Adicione índices no banco de dados para as colunas que você utiliza em filtros e ordenações.
  • Delegue tarefas demoradas para background jobs em vez de processá-las no ciclo de request.
  • Escreva um teste para cada bug que você corrigir e mantenha a suite de testes rápida.

Erros comuns

  • Renderizar uma lista sem includes e enviar um problema de N+1 para produção.
  • Colocar lógica de negócio em controllers até que as actions tenham centenas de linhas.
  • Usar params[:post] diretamente em vez de strong parameters.
  • Editar db/schema.rb manualmente em vez de escrever uma migration.
  • Esquecer as opções de dependent: e deixar registros órfãos para trás.
  • Recorrer a um service object ou a uma gem antes que o model realmente precise disso.
  • Executar queries pesadas em views em vez de carregar os dados no controller.

Próximos passos

O Rails ensina uma forma durável de pensar: recursos, convenções e um lugar único para cada responsabilidade. Se você gosta do modelo “batteries-included”, o Laravel aplica a mesma filosofia em PHP, enquanto o Django faz o mesmo em Python. Como o roteamento do Rails é baseado em recursos, o guia de REST APIs explica os conceitos fundamentais. E, já que a maioria dos apps Rails roda em um banco de dados relacional, aprofunde seus conhecimentos em PostgreSQL a seguir.

Na pratica

Os quatro arquivos por trás de um recurso

Alterne entre a rota, o controller, o model e a migration para ver como o Rails conecta um recurso.

config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
    member do
      post :publish
    end
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end

  root "posts#index"
end

Carregando associações

Acessar uma associação dentro de um loop gera uma query por linha. Carregue-a antecipadamente (eager load) e a página inteira executará apenas duas queries.

Preferir
posts = Post.includes(:author, :comments).recent
posts.each { |post| puts post.author.name }
Evitar
posts = Post.recent
posts.each { |post| puts post.author.name }
# one query per post: the classic N+1

Aceitando entradas

Strong parameters definem uma lista permitida do que uma requisição pode definir. Passar o hash bruto permite que um cliente atribua qualquer coluna, incluindo flags de admin.

Preferir
def post_params
  params.require(:post).permit(:title, :body, tag_ids: [])
end
Evitar
Post.new(params[:post])
# mass assignment: role and admin are fair game

Trade-offs

O Rails é a escolha padrão correta?

O Rails troca parte da liberdade pela velocidade de entrega. Esse é um ótimo negócio até que sua aplicação supere as convenções.

Strengths

  • Você entrega funcionalidades, não encanamento

    Roteamento, migrations, validação, mailers, jobs e caching estão todos incluídos e já conectados, permitindo que uma equipe pequena construa um produto grande.

  • As convenções são uma linguagem compartilhada

    Qualquer desenvolvedor Rails pode abrir qualquer app Rails e saber onde as coisas estão. Isso torna a contratação e o onboarding drasticamente mais fáceis.

  • O ecossistema de gems é profundo

    Devise, Pundit, Sidekiq, RSpec e inúmeros outros resolvem os problemas que toda aplicação eventualmente enfrenta.

Trade-offs

  • A magia esconde o framework

    A convenção parece natural até que algo não seja convencional. O debugging exige a compreensão do código-fonte do Rails, não apenas do seu código.

  • Performance exige atenção

    Um app Rails ingênuo não é lento, mas queries N+1, falta de índices e views pesadas se acumulam. Profiling é uma habilidade necessária, não opcional.

  • A stack completa é opinativa

    O Rails assume HTML, um banco de dados relacional e sua própria gestão de assets. Se sua arquitetura divergir, você lutará contra os padrões mais do que os utilizará.

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Rails?

Nosso tutorial interativo te guia por Rails passo a passo — com quizzes e codigo real que voce pode executar no navegador.