{"id":17675556,"url":"https://github.com/ernanej/ruby-and-activerecord","last_synced_at":"2025-03-30T17:14:35.648Z","repository":{"id":230262496,"uuid":"778920733","full_name":"ErnaneJ/ruby-and-activerecord","owner":"ErnaneJ","description":"Guia prático de como utilizar o a Gem ActiveRecord do Ruby sem framework. 🚀","archived":false,"fork":false,"pushed_at":"2024-04-02T17:08:51.000Z","size":85,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-05T18:59:12.831Z","etag":null,"topics":["activerecord","ruby"],"latest_commit_sha":null,"homepage":"https://dev.to/ernanej/pt-br-guia-pratico-explorando-o-poder-da-gem-activerecord-no-ruby-sem-framework-2dfg","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ErnaneJ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-28T17:08:40.000Z","updated_at":"2024-04-04T21:15:50.000Z","dependencies_parsed_at":"2024-04-02T18:27:25.566Z","dependency_job_id":null,"html_url":"https://github.com/ErnaneJ/ruby-and-activerecord","commit_stats":null,"previous_names":["ernanej/ruby-and-activerecord"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ErnaneJ%2Fruby-and-activerecord","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ErnaneJ%2Fruby-and-activerecord/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ErnaneJ%2Fruby-and-activerecord/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ErnaneJ%2Fruby-and-activerecord/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ErnaneJ","download_url":"https://codeload.github.com/ErnaneJ/ruby-and-activerecord/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246351017,"owners_count":20763232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","ruby"],"created_at":"2024-10-24T07:22:43.736Z","updated_at":"2025-03-30T17:14:35.622Z","avatar_url":"https://github.com/ErnaneJ.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [pt-BR] Guia Prático: Explorando o Poder da Gem ActiveRecord no Ruby - Sem Framework 🚀\n\n\u003e Recentemente, tive contato com alguns novos entusiastas do Ruby que provavelmente em breve estarão explorando o Rails, dado o caminho que estão seguindo. Acredito que, uma vez que tenhamos uma compreensão básica de Ruby e a linguagem devidamente instalada, é vantajoso explorarmos o Active Record, uma poderosa gem que simplifica significativamente as operações no banco de dados. Dedico este conteúdo a vocês.\n\n## Introdução 🎉\n\nA *gem* Ruby `ActiveRecord` é uma ferramenta poderosa que oferece abstrações simplificadas para interagir com bancos de dados, permitindo uma troca fácil do *back-end* do banco de dados, por exemplo, migrando de `SQLite3` para `MySQL` sem a necessidade de alterar o código. Esta gem possui suporte integrado para abstrações de banco de dados para `SQLite3`, `MySQL` e `PostgreSQL`, e uma das suas principais vantagens é a necessidade mínima de configuração. Embora o `ActiveRecord` seja amplamente utilizado com o framework [Ruby-on-Rails](https://rubyonrails.org/), ele também pode ser empregado com o Sinatra ou até mesmo de forma independente, sem qualquer estrutura web. Aqui iremos nos concentrar em demonstrar o uso do `ActiveRecord` de forma autônoma, fora de qualquer estrutura específica. 🌟\n\n## Preparando o Projeto 🛠️\n\nPara desenvolver este tutorial de forma organizada e facilitar a compreensão e consulta posterior do conteúdo, adotarei uma certa estrutura de pastas e arquivos.\n\n### Criando uma Pasta para o Projeto 📂\n\n```bash\nmkdir ruby-and-activerecord\n```\n\n### Inicializando o Bundle 📦\n\nPara gerenciar as gems que serão utilizadas, recomenda-se o uso do Bundler. Neste tutorial utilizaremos o Gemfile para escopar as dependências do projeto. Para começar, execute o seguinte comando:\n\n```bash\nbundle init\n```\n\nIsso criará um novo Gemfile.\n\n### Instalando a Gem ActiveRecord 💎\n\nPara instalar a gem ActiveRecord, você pode utilizar a ferramenta `gem` ou o gerenciador de pacotes do seu sistema, caso esteja disponível. Por exemplo:\n\n```bash\n# Instalando com gem\ngem install activerecord\n\n# No Ubuntu\napt install ruby-activerecord\n```\n\nEntretanto, neste tutorial, utilizaremos o `Gemfile` para organizar as dependências do projeto. Para isso, execute o seguinte comando:\n\n```bash\nbundle add activerecord\n```\n\nVocê também pode adicionar diretamente ao seu `Gemfile`. Ele ficará semelhante ao conteúdo abaixo:\n\n```gemfile\n# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"activerecord\", \"~\u003e 7.1\"\n```\n\nDepois basta executar o `bundle install`.\n\n### Consultando a Documentação 📚\n\nAntes, durante ou após a leitura deste tutorial (ou qualquer outro), é altamente recomendável que você consulte e verifique as informações diretamente na documentação oficial. Você pode usar o comando `ri` ou acessar a [documentação online](https://api.rubyonrails.org/classes/ActiveRecord/Base.html).\n\nPor exemplo:\n\n```bash\nri ActiveRecord\nri ActiveRecord::Base\n```\n\n## Estabelecendo Conexão com o Banco de Dados 🎲\n\nAntes de utilizar qualquer modelo, é essencial estabelecer uma conexão com o banco de dados. Como mencionado anteriormente, há uma grande praticidade em conectar uma aplicação ao `ActiveRecord` com diferentes tipos de banco de dados, como `SQLite3`, `MySQL` ou `PostgreSQL`, por exemplo. Abaixo, apresento exemplos para três adaptadores diferentes:\n\n```ruby\nrequire 'active_record'\n\n# SQLite3\nActiveRecord::Base.establish_connection(\n  adapter: 'sqlite3',\n  database: 'test.db'\n)\n\n# MySQL\nActiveRecord::Base.establish_connection(\n  adapter: 'mysql2',\n  host: 'localhost',\n  username: 'seu_nome_de_usuario_do_banco_de_dados',\n  password: 'sua_senha_do_banco_de_dados',\n  database: 'seu_nome_do_banco_de_dados'\n)\n\n# PostgreSQL\nActiveRecord::Base.establish_connection(\n  adapter: 'postgresql',\n  host: 'localhost',\n  username: 'seu_nome_de_usuario_do_banco_de_dados',\n  password: 'sua_senha_do_banco_de_dados',\n  database: 'seu_nome_do_banco_de_dados'\n)\n```\n\nPara este tutorial, estaremos utilizando o SQLite, mas você pode optar por qualquer adaptador que desejar.\n\n### Instalando a Gem SQLite3 🪶\n\nPara utilizar o adaptador `SQLite3`, é necessário instalar a gem correspondente. Assim como fizemos anteriormente com o `ActiveRecord`, faremos o mesmo processo para instalar essa *gem*. Nosso `Gemfile` ficará assim:\n\n```ruby\n# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"activerecord\", \"~\u003e 7.1\"\ngem \"sqlite3\", \"~\u003e 1.7\"\n```\n\n### Estabelecendo Conexão com o Banco de Dados SQLite 🪶\n\nPara uma melhor organização, criaremos uma pasta de configurações e dentro dela um arquivo `initializer.rb`. Este arquivo será responsável por realizar a conexão com o banco de dados. Para simplificar o processo de configuração, também optaremos por criar um arquivo `.yaml` para armazenar as configurações do banco de dados fora do código.\n\n```ruby\n# configurations/initializer.rb\nrequire 'yaml'\nrequire 'active_record'\n\ndb_config = YAML::load(File.open(Dir.pwd + '/configurations/database.yaml'))\n\nActiveRecord::Base.establish_connection(db_config)\n```\n\nE em nosso arquivo `database.yaml` teremos as configurações da seguinte forma:\n\n```yaml\n# configurations/database.yaml\nadapter: 'sqlite3'\ndatabase: './database/database.sqlite3'\n```\n\n\u003e ℹ️ Estamos armazenando o banco de dados no caminho `./database/database.db`. Se necessário, altere esse caminho ou crie a pasta 'database' na raiz do projeto.\n\nCom isso, a conexão está estabelecida. Para testá-la, basta executar o `initializer.rb` da seguinte forma:\n\n```basg\nruby ./configurations/initializer.rb\n```\n\nSe não houver erros, estamos no caminho certo!\n\n## Criando um Modelo 🧑🏼‍💻\n\nPara criar um modelo, basta criar a classe desejada herdando de `ActiveRecord::Base`. Os nomes das tabelas são assumidos com base no nome da classe do modelo que está sendo criado. Por exemplo, um modelo chamado `User` espera ter uma tabela chamada `users`. Um modelo chamado `ProfileUser` espera uma tabela chamada `profile_users`. Ele converte tudo para minúsculas e adiciona um sublinhado entre as palavras em maiúsculas.\n\nPara uma melhor organização, criaremos uma pasta adicional na raiz do projeto, onde guardaremos todas as nossas models. Para começarmos, vamos criar uma model de User.\n\n```ruby\n# ./models/user.rb\nclass User \u003c ActiveRecord::Base\nend\n```\n\nTecnicamente, isso é tudo que você precisa fazer. Por padrão, ele mapeará os campos existentes do banco de dados para atributos no modelo. Você não precisa definir cada campo no código. No entanto, se desejar, você pode sobrescrever propriedades como o nome da tabela e a chave primária — *por sua conta e risco* 😬.\n\n```ruby\n# ./models/user.rb\nclass User \u003c ActiveRecord::Base\n  self.table_name = 'user'\n  self.primary_key = 'user_id'\nend\n```\n\n## Juntando as Peças 🛠️\n\nVamos criar um arquivo principal para reunir e usar nossos componentes enquanto experimentamos. Portanto, crie um `main.rb` na raiz do projeto e adicione o seguinte conteúdo:\n\n```ruby\n# main.rb\nrequire 'active_record'\n\nrequire './configurations/initializer.rb'\nrequire './models/user'\n\nUser.create(\n  name: 'Ernane', \n  age: 16\n)\n```\n\nObserve que estamos carregando o `ActiveRecord`, executando o `initializer.rb` para estabelecer a conexão com o banco de dados e importando nossa nova `model` de usuário. As próximas linhas são usadas para criar um usuário. Entraremos em detalhes sobre essas instruções em breve.\n\nPara executar, realizamos a mesma ação que fizemos com o initializer:\n\n```bash\nruby main.rb\n```\n\nVocê pode notar que recebeu um erro porque nossa tabela `users` não existe no banco de dados ainda. Isso ocorre porque, como mencionado, o `ActiveRecord` realiza o mapeamento dos atributos do banco de dados em métodos da classe modelo correspondente. Se a tabela não existir, ocorrerá o erro que você deve estar vendo agora.\n\nPara criar a tabela, você pode executar a criação manualmente em SQL. Por exemplo:\n\n```sql\nCREATE TABLE IF NOT EXISTS users (\n  name TEXT,\n  age INT,\n  email TEXT,\n  admin BOOLEAN,\n  tshirt_size TEXT\n);\n```\n\nOu, se quiser adiantar um pouco no conteúdo, você pode criar uma migração.\n\nPara uma melhor organização, mais uma vez, criaremos uma nova pasta chamada `migrations` dentro da nossa pasta de banco de dados. Lá, adicionaremos uma migração, que nada mais é do que um arquivo Ruby. Por exemplo, para o nosso modelo de usuário:\n\n```ruby\n# ./database/migrations/create_user_table.rb\n\nrequire './configurations/initializer.rb'\n\nclass CreateUserTable \u003c ActiveRecord::Migration[6.0]\n  def change\n    create_table :users do |t|\n      t.string :name\n      t.integer :age\n      t.string :email\n      t.boolean :admin\n      t.string :tshirt_size\n      t.timestamps\n    end\n  end\nend\n\nCreateUserTable.migrate(:up)\n```\n\nPara executar essa migração, basta usar o Ruby no seu terminal como de costume.\n\n```bash\nruby ./database/migrations/create_user_table.rb\n```\n\n\u003e Essa não é a melhor forma de lidar com migrações em um projeto. Você pode criar uma tarefa Rake para executar suas migrações, facilitando o processo. No entanto, não vou me ater a esse tópico agora, pois não é o objetivo dessa publicação.\n\n## Uso do ActiveRecord 🤩\n\nAgora que tudo está pronto, podemos executar novamente nosso arquivo principal. Como agora temos a tabela criada, o erro anterior desaparecerá e poderemos realizar nossas primeiras manipulações com o `ActiveRecord`.\n\n### Listando Colunas da Tabela 📋\n\nDepois de criar um modelo, você pode acessar as colunas como objetos vinculados ao modelo. Aqui está um exemplo que irá imprimir as colunas de uma tabela:\n\n```ruby\n# ./examples/listing_columns.rb\n\nUser.columns.each do |column|\n  puts \"#{column.name} =\u003e #{column.type}\"\nend\n```\n\n### Criando Novos Registros 🆕\n\nExistem várias maneiras de criar um novo registro:\n\n- Criar um novo objeto e chamar explicitamente o método `.save()`;\n- Usar um bloco para preencher o objeto e chamar o método `.save()`;\n- Chamar `.create()` que criará e salvará em uma única etapa;\n\n```ruby\n# ./examples/creating_new_records.rb\n\n# Criar um novo objeto de usuário e então salvá-lo para armazenar no banco de dados\nuser = User.new(name: 'ErnaneDois', age: 16, email: 'teste0@teste.com', admin: false, tshirt_size: 'M')\nuser.save\n\n# Usar um bloco para preencher o objeto e então salvar\nUser.new do |u|\n  u.name = 'ErnaneUm'\n  u.age = 18\n  u.email = 'teste1@teste.com'\n  u.admin = false\n  u.tshirt_size = 'M'\nend.save\n\n# Criar e salvar em uma única etapa com \".create()\"\nUser.create(name: 'ErnaneTres', age: 18, email: 'teste2@teste.com', admin: false, tshirt_size: 'M')\n```\n\n### Encontrando Registros 🔍\n\nExistem muitos métodos que você pode usar para consultar registros. Alguns deles incluem:\n\n- `first()`;\n- `last()`\n- `second()`, `third()`, `fourth()`, `fifth()`;\n- `all()`;\n- `where()`;\n- `find_by()`;\n- `find_by_sql()`;\n- `find_by_*()`.\n\n```ruby\n# ./examples/finding_records.rb\n\n# Obter o primeiro usuário\nprimeiro_usuario = User.first\nputs primeiro_usuario.name\n\n# Obter o último usuário\nultimo_usuario = User.last\nputs ultimo_usuario.name\n\n# Também disponível: User.second, User.third, User.fourth, User.fifth\n\n# Encontrar todos os usuários que correspondem à consulta e depois pegar o primeiro da lista\nadultos = User.where('age \u003e ?', 18)\nputs \"Adultos: #{adultos.length}\"\n\n# Obter todos os usuários\nputs \"Total de usuários: #{User.all.length}\"\n\n# Encontrar o primeiro usuário que corresponde à consulta\nusuario = User.find_by(name: 'nomeNovo')\nputs usuario.name\n\n# Obter todos os usuários e classificar\nusuarios_classificados = User.all.order(age: :desc)\nusuarios_classificados.each do |usuario|\n  puts \"#{usuario.name}: #{usuario.age}\"\nend\n\n# Você pode combinar vários campos dinamicamente em consultas find_by_*\nusuario = User.find_by_name_and_age('nomeNovo', 16)\nputs \"#{usuario.name} tem #{usuario.age} anos\"\n\n# Consultar usando SQL personalizado\nusuarios = User.find_by_sql('select * from users')\nusuarios.each do |usuario|\n  puts \"#{usuario.name} tem #{usuario.age} anos\"\nend\n```\n\nAcesse o [Guia do Ruby](https://guides.rubyonrails.org/active_record_querying.html) para obter mais informações.\n\n### Atualizando Registros 🔄\n\nPara atualizar um registro, você também tem algumas opções. Uma delas é obter o registro, modificá-lo e, em seguida, chamá-lo explicitamente. Outra opção é chamar o método `update()` para fazer a alteração e salvar em uma única ação.\n\n```ruby\n# ./examples/updating_records.rb\n\n# Atualizar modificando um objeto de usuário e chamando explicitamente \".save\"\nusuario = User.first\nusuario.name = 'novoNome'\nusuario.save\n\n# Atualizar e salvar em uma única etapa\nUser.first.update(name: 'nomeNovo')\n```\n\n### Excluindo Registros ␡\n\nPara excluir um registro, você pode acessar um registro individual ou chamar métodos para excluir todos os registros. Aqui estão alguns exemplos:\n\n```ruby\n# ./examples/deleting_records.rb\n\n# Maneira funcional, mas ineficiente, de excluir todos os registros:\nUser.all.each { |usuario| usuario.delete } # ou ainda =\u003e User.all.each(\u0026:delete)\n\n# Opção mais eficiente:\nUser.delete_all\n```\n\n### Funções de Retorno de Chamada 👀\n\nExistem vários métodos que você pode adicionar em modelo que serão acionados automaticamente quando determinadas ações forem executadas, como `criar`, `atualizar` ou `excluir` um registro, além de `consultar` um registro.\n\nSaiba mais sobre retornos de chamada em [Ruby on Rails Guides](https://guides.rubyonrails.org/active_record_callbacks.html#available-callbacks).\n\nEsses métodos de retorno de chamada podem ser classificados em diferentes categorias:\n\n#### 📍 Ação de Exclusão:\n\n- `before_destroy`;\n- `after_destroy`.\n\n#### 📍 Ações de Criação:\n\n- `before_create`;\n- `after_create`.\n\n#### 📍 Ações de Criação e Atualização:\n\n- `before_validation`;\n- `after_validation`;\n- `before_update`;\n- `after_update`;\n- `before_save`;\n- `after_save`.\n\n#### 📍 Ações de Consulta:\n\n- `after_initialize`;\n- `after_find`.\n\n#### 📍 Ações de Criação, Atualização e Exclusão:\n\n- `after_commit`;\n- `after_rollback`.\n\nAqui está um exemplo de como configurar um retorno de chamada usando blocos:\n\n```ruby\n# ./models/user.rb\n\nclass User \u003c ActiveRecord::Base\n  before_create do |u|\n    puts \"Prestes a criar o usuário: #{u.name}\"\n  end\n\n  after_create do |u|\n    puts \"Novo objeto de usuário criado: #{u.name}\"\n  end\nend\n```\n\nOutra maneira é especificar as funções de retorno de chamada a serem executadas usando `symbols`, operando em `self`:\n\n```ruby\n# ./models/user.rb\n\nclass User \u003c ActiveRecord::Base\n  before_create :before_create_callback\n  after_create :after_create_callback\n\n  def before_create_callback\n    puts \"Prestes a criar o usuário: #{self.name}\"\n  end\n\n  def after_create_callback\n    puts \"Novo objeto de usuário criado: #{self.name}\"\n  end\nend\n```\n\n```ruby\nUser.create(name: 'Ernane', age: 16) # Aciona os callbacks definidos anteriormente\n```\n\nOs retornos de chamada \"*around*\" (`around_create`, por exemplo) são um pouco mais complexos. Eles permitem que você execute código antes e depois de uma ação, podendo ser úteis para *benchmarking* de desempenho, por exemplo.\n\n```ruby\n# ./models/user.rb\n\nclass User \u003c ActiveRecord::Base\n  around_create :around_create_callback\n\n  def around_create_callback\n    puts 'Um usuário está prestes a ser criado'\n    yield # Aguarde até que o salvamento tenha ocorrido\n    puts 'Um usuário foi criado.'\n  end\nend\n```\n\n```ruby\nUser.create(name: 'Ernane', age: 16) # Aciona o callback definido anteriormente\n```\n\n### Validação de Campos ✅\n\nAo adicionar validações a um modelo, você garante que qualquer objeto salvo atenda a determinados padrões. Existem várias validações integradas disponíveis. Aqui estão alguns exemplos de validações que você pode aplicar:\n\n- Garantir que um campo esteja vazio ou não vazio;\n- Garantir que um campo contenha um valor exclusivo;\n- Garantir o comprimento de um campo;\n- Garantir que um campo seja um valor numérico;\n- Garantir que um campo corresponda a uma expressão regular;\n- Implementar funções de validação personalizadas (*o céu é o limite, ou quase*).\n\nApós aplicar as validações, você pode chamar os métodos `.valid?` e `.invalid?` no modelo para realizar as validações e gerar mensagens de erro, que podem ser acessadas no modelo. A chamada também executará as validações e gerará mensagens de erro. Ela retornará `falso` se a operação não for bem-sucedido. Você pode aprender mais sobre validações no [Guia de Validações do ActiveRecord](https://guides.rubyonrails.org/active_record_validations.html).\n\n```ruby\n# ./models/user.rb\n\nclass User \u003c ActiveRecord::Base\n\n  # ...\n\n  # Garantir que os campos de nome e idade estejam presentes\n  validates_presence_of :name, :age\n\n  # Garantir que um campo seja único\n  validates_uniqueness_of :email\n\n  # Usar uma expressão regular para limitar os valores do campo\n  validates_format_of :name, with: /\\A[a-zA-Z]+\\z/, message: \"Apenas letras são permitidas\"\n\n  # Garantir que um campo esteja vazio\n  validates_absence_of :admin\n\n  # Garantir que um valor tenha um comprimento específico\n  validates_length_of :credit_card, is: 16\n\n  # Garantir que o valor seja de um tipo específico\n  validates_numericality_of :age, only_integer: true\n\n  # Garantir um comprimento mínimo e máximo\n  validates_length_of :name, minimum: 2, maximum: 64\n  \n  # Outra forma de especificar o comprimento\n  validates_length_of :name, in: 2..64\n\n  # Garantir que o valor corresponda a um conjunto específico\n  validates_inclusion_of :tshirt_size, in: %w(PP P M G GG XG), message: \"Tamanho de camiseta inválido: %{value}\"\n\n  # ...\nend\n```\n\n```ruby\n# ./examples/validating_records.rb\n\nusuario = User.new\nusuario.email = 'test'\nusuario.admin = 1\nusuario.name = \"Ernane123\"\nusuario.age = 50.5\nusuario.tshirt_size = 'XM'\n\n# Alternativamente, use `.valid?` ou `.invalid?` para gerar erros\nunless usuario.save\n  usuario.errors.messages.each do |field, messages|\n    puts \"#{field}: #{messages}\"\n  end\nend\n```\n\nEste exemplo garantirá que os dados inseridos no objeto de usuário atendam aos critérios de validação definidos no modelo. Se houver algum erro de validação, ele será exibido na saída.\n\n### Transações em Bancos de Dados 🎲\n\nO uso de transações em bancos de dados permite executar várias operações de forma segura, garantindo que todas sejam realizadas ou nenhuma delas seja concluída. Por exemplo, ao realizar operações complexas que envolvem múltiplas atualizações ou inserções, é crucial garantir a integridade do banco de dados, evitando estados inconsistentes.\n\nVocê pode criar e executar transações em blocos de código utilizando o método `transaction` fornecido pelo `ActiveRecord`. Veja um exemplo:\n\n```ruby\n# ./examples/testing_transactions.rb\n\n# Exemplo 1: \n# - Deve tentar mudar o nome e funcionar. \n# - Deve tentar mudar a idade e deve falhar pois o valor tem que ser inteiro (validação presente no modelo). \n# - Como falhou, as alterações já realizadas, mesmo que em sucesso, serão revertidas.\n\nbegin\n  ActiveRecord::Base.transaction do\n    usuario = User.first\n    puts \"Antes 1 =\u003e\", usuario.attributes\n    usuario.name = 'novonome' # deve funcionar\n    usuario.save!\n\n    usuario.age = 50.6 # deve falhar\n    usuario.save!\n  end\nrescue ActiveRecord::RecordInvalid =\u003e e\n  puts \"\\nErro ao salvar: #{e.message}\\n\"\nend\n\n# ❌ Nada muda\nusuario = User.first\nputs \"\\nDepois 1 (nada muda) =\u003e\", usuario.attributes\n\n# Exemplo 2: \n# - Deve tentar mudar o nome e idade e funcionar. \n# - Como não falhou, as alterações persistem.\n\nActiveRecord::Base.transaction do\n  usuario = User.first\n  puts \"\\nAntes 2 =\u003e\", usuario.attributes\n  usuario.name = 'novonome' # deve funcionar\n  usuario.save!\n\n  usuario.age = 50  # deve funcionar\n  usuario.save!\nend\n\n# ✅ As alterações persistem\n# Agora nome e idade foram alterados\nusuario = User.first\nputs \"\\nDepois 2 =\u003e\", usuario.attributes\nputs \"Funciona perfeitamente.\"\n```\n\nDentro do bloco de transação, você pode capturar exceções para tratamento específico ou para permitir que a transação continue. Se necessário, você pode relançar exceções para sair da transação.\n\nAlém disso, você não está limitado a operar apenas no modelo associado ao bloco de transação. Você pode chamar o método `transaction` em qualquer modelo ou instância de modelo para iniciar uma transação específica para aquele objeto.\n\nO uso de transações é essencial para garantir a integridade e consistência dos dados em aplicações que envolvem operações críticas no banco de dados.\n\n### Relacionamentos ↔️\n\nAssociar modelos uns aos outros é um aspecto fundamental do `ActiveRecord`. Estes incluem relacionamentos como `um para um`, `um para muitos` e `muitos para muitos`.\n\nOs relacionamentos disponíveis entre os modelos são:\n\n- pertence a (`belongs_to`);\n- tem um (`has_one`);\n- tem muitos (`has_many`);\n- tem muitos através de (`has_many :through`);\n- tem um através de (`has_one :through`);\n- tem e pertence a muitos (`has_and_belongs_to_many`).\n\nHá uma espécie de '_mágica_' ✨ que acontece quando se trata da nomeação de tabelas. Você pode substituir os nomes das tabelas e os nomes das colunas de chave estrangeira, mas é recomendado seguir as convenções para evitar configurações extras. Por exemplo, se um `Perfil` pertence a um `Usuário`, ele assume que existem tabelas de usuários e perfis, e a tabela de perfis terá uma coluna `user_id`.\n\nTabelas de ligação para relacionamentos `muitos para muitos` usam o nome de ambos os modelos em ordem alfabética. Por exemplo, se um **Usuário** tem um relacionamento muitos para muitos com um **Departamento**, então a tabela de ligação é esperada para ser nomeada `departments_users` e conter colunas `user_id` e `department_id` que fazem referência às tabelas denominadas `departments` e `users`.\n\nNeste exemplo, preste atenção especial à singularidade ou pluralidade das palavras usadas nos nomes dos modelos, nomes dos relacionamentos e nomes das tabelas do banco de dados. Ao usar um relacionamento `has_and_belongs_to_many`, a tabela de ligação usa plurais de ambos os nomes em ordem alfabética.\n\n\u003e Nessa etapa será necessário criar novas tabelas para que o exemplo funcione pois precisamos de mais tabelas para relacionar. Dessa forma, você pode se aventurar criando-as manualmente ou executar a migration presente [aqui](https://github.com/ErnaneJ/ruby-and-activerecord/blob/main/database/migrations/create_profiles_posts_and_departments_tables.rb).\n\n```ruby\n# ./models/user.rb\nclass User \u003c ActiveRecord::Base\n  has_one :profile\n  has_many :posts\n  has_and_belongs_to_many :departments\nend\n```\n\n```ruby\n# ./models/post.rb\nclass Post \u003c ActiveRecord::Base\n  belongs_to :user\nend\n```\n\n```ruby\n# ./models/profile.rb\nclass Profile \u003c ActiveRecord::Base\n  belongs_to :user\nend\n```\n\n```ruby\n# ./models/department.rb\nclass Department \u003c ActiveRecord::Base\n  has_and_belongs_to_many :users\nend\n```\n\nDessa forma, podemos realizar as seguintes execuções:\n\n```ruby\n# main.rb\nusuario = User.create(name: 'Ernane')\n\n# Algumas maneiras de criar o perfil para o usuário:\nProfile.create(bio: 'ErnaneJ', user: usuario)\nusuario.profile = Profile.create(bio: 'Hello World! :)')\nusuario.create_profile(bio: 'Hello World! :)')\n\n# Algumas maneiras de adicionar um post ao usuário (relacionamento um para muitos)\nusuario.posts.create(content: 'Post de exemplo')\nPost.create(content: 'Outro post', user: usuario)\nusuario.posts.append(Post.create(content: 'Um terceiro post'))\n\n# Criar os departamentos e relacionamentos (relacionamento muitos para muitos)\nusuario.departments.create(name: 'TI')\nDepartment.create(name: 'Vendas', users: [usuario])\nusuario.departments.append(Department.create(name: 'RH'))\n\n# Obtendo os objetos relacionados\nusuario = User.find_by_name('Ernane')\nputs usuario.inspect\nputs usuario.profile.inspect\nputs usuario.post_ids.inspect\nputs usuario.posts.inspect\nputs usuario.department_ids.inspect\nputs usuario.departments.inspect\n```\n\nVocê pode ler mais sobre associações acessando o [Guides](https://guides.rubyonrails.org/association_basics.html).\n\n### Migrações 🗄️\n\nPara evitar a necessidade de escrever instruções SQL para criar, modificar e destruir esquemas de banco de dados, o ActiveRecord fornece um mecanismo para realizar migrações. Isso permite que você escreva código Ruby para especificar como deve ser a estrutura do banco de dados sem escrever SQL bruto.\n\nExistem alguns benefícios nisso. Por exemplo, como comentado anteriormente, você pode usar a mesma migração para criar o esquema de banco de dados para SQLite, MySQL e PostgreSQL, mesmo que as instruções SQL reais possam variar de banco de dados para banco de dados. Ele também permite que você execute atualizações, desmonte e reconstrua facilmente um banco de dados apenas executando os scripts de migração Ruby, que por sua vez podem ser configurados em um `Rakefile` por conveniência.\n\n#### Métodos Disponíveis 📋\n\nAo definir classes de migração, estes são alguns dos métodos disponíveis que você pode usar para executar operações de banco de dados. Você pode ler mais sobre os métodos disponíveis [aqui](https://api.rubyonrails.org/classes/ActiveRecord/Migration.html).\n\n- `create_table()`;\n- `change_table()`;\n- `rename_table()`;\n- `drop_table()`;\n- `create_join_table()`;\n- `drop_join_table()`;\n- `add_column()`;\n- `change_column()`;\n- `change_column_default()`;\n- `change_column_null()` *(permitir/proibir nulo)*;\n- `rename_column()`;\n- `remove_column()`;\n- `remove_columns()`;\n- `add_timestamps()` *(created_at e updated_at)*;\n- `remove_timestamps()`;\n- `add_foreign_key()`;\n- `remove_foreign_key()`;\n- `add_index()`;\n- `rename_index()`;\n- `remove_index()`;\n- `add_reference()`;\n- `remove_reference()`.\n\n#### Diferença Entre CHANGE() e UP()/DOWN() ⁉️\n\nNo início, pode ser um pouco confuso entender a necessidade desses dois métodos e você também pode estar se perguntando. Basicamente, se você definir migrações usando o método `change`, ele determinará automaticamente o que precisa ser feito para que as migrações `up` e `down` executem ou desfaçam as ações especificadas.\n\nSe quiser especificar uma ação que funcione apenas em uma direção ou ter mais controle, você poderá definir explicitamente os métodos `.up` e `.down`. Eu usaria o padrão, `change`, a menos que você tenha alguma necessidade especial.\n\n#### Criar e Eliminar Tabelas 🧑🏼‍💻\n\nEste exemplo mostra como fazer uma migração simples que criará uma tabela chamada `users` com alguns campos: `name`, `age`, `created_at` e `updated_at`.\n\nChame o método `migrate` da classe de migração para atualizar o banco de dados. Você deve fornecer uma direção (`:up` ou `:down`) para especificar se deseja executar as alterações ou desfazê-las. Ele determinará automaticamente quais instruções precisam ser executadas para realizar cada ação.\n\n```ruby\nclass CreateUserTable \u003c ActiveRecord::Migration[5.2]\n  def change\n    create_table :users do |table|\n      table.string :name\n      table.integer :age\n      table.timestamps\n    end\n  end\nend\n\n# Criar a tabela\nCreateUserTable.migrate(:up)\n\n# Eliminar a tabela\nCreateUserTable.migrate(:down)\n```\n\n### Usando no IRB 🖥️\n\nAo usar o Ruby on Rails, você pode acessar o console do Rails com o comando `rails console` para entrar em um ambiente interativo que permite consultar e manipular seus modelos `ActiveRecord`. No entanto, se você estiver fora do ambiente Rails, precisará requerer os módulos Ruby onde seus modelos estão definidos.\n\nVocê pode usar o argumento `-r` para exigir os módulos desejados na inicialização do IRB. Isso economiza tempo, pois você não precisa digitar os comandos `require` manualmente dentro do interpretador.\n\n```bash\nirb -r ./models\n```\n\nDessa forma, você pode iniciar o IRB com seus módulos já importados e prontos para uso.\n\nAlternativamente, como dito, você pode importar manualmente os módulos dentro do IRB digitando os comandos `require`. No entanto, criar um script com os comandos de `require` economiza tempo e esforço. Uma vez dentro do IRB, você pode usar seus modelos como de costume:\n\n```ruby\n$ irb\nirb(main):001\u003e require \"./configurations/initializer.rb\"\n# =\u003e true\nirb(main):002\u003e require \"./models/user.rb\"\n# =\u003e true\nirb(main):003\u003e User\n# =\u003e User (call 'User.connection' to establish a connection)\nirb(main):004\u003e User.last\n# =\u003e #\u003cUser:0x000000010bdb0630 ...\u003e \n```\n\nIsso permite que você execute consultas e manipulações em seus modelos `ActiveRecord` diretamente do console interativo.\n\n## Conclusão 🎉\n\nApós absorver este tutorial, você agora possui um entendimento sólido dos fundamentos do `ActiveRecord`. Agora, você deve se sentir confiante para instalar o `ActiveRecord`, explorar sua documentação e começar a utilizá-lo em seus projetos Ruby.\n\nAqui está um resumo do que foi aprendido:\n\n- Instalação e configuração inicial do ActiveRecord;\n- Definição de modelos e relacionamentos entre eles;\n- Execução de consultas para recuperar dados do banco de dados;\n- Criação e manipulação de registros no banco de dados;\n- Utilização de retornos de chamada para executar ações automáticas em modelos;\n- Realização de transações para garantir que várias operações de banco de dados sejam executadas com sucesso ou revertidas em caso de erro;\n- Criação e execução de migrações para gerenciar o esquema do banco de dados de forma programática;\n- Utilização do ActiveRecord em uma sessão interativa no IRB ou Pry.\n\nCom esses conhecimentos, você está pronto para aproveitar ao máximo o ActiveRecord em seus projetos Ruby, facilitando o trabalho com bancos de dados e simplificando o desenvolvimento de aplicativos web. Lembre-se de continuar explorando a documentação oficial e praticar com exemplos do mundo real para aprimorar suas habilidades. 🚀\n\nO [repositório](https://github.com/ErnaneJ/ruby-and-activerecord/) com os exemplos mencionados neste post está disponível e totalmente aberto a contribuições. Além disso, esta publicação também. Sinta-se à vontade!\n\nEspero que tenha gostado dessa postagem e que ela tenha te ajudado, de alguma forma, a encontrar ou que você procurava! 💙","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fernanej%2Fruby-and-activerecord","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fernanej%2Fruby-and-activerecord","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fernanej%2Fruby-and-activerecord/lists"}