[RUBY] [Rails] I tried to implement a transaction that combines multiple DB processes

Introduction

I was developing an app with Rails and implemented the process of creating data for multiple tables at the same time. In that process, I learned that there is a concept of transaction that makes both processes absent when either process fails, so I will write about transaction and the implemented contents as a memorandum and output.

What is transaction

Looking up the definition of the word "transaction" [Processing, handling, treatment, business, trading, buying and selling, newsletter, bulletin, minutes] It comes out like this.

In IT and programming "Indivisible things that combine multiple processes into one"

It seems that it can be defined as.

This article is a very easy-to-understand summary of the concept of transactions, and I used it as a reference.

What is a "transaction"? I tried to talk about it in a super easy way!

transaction method usage

--Treat multiple processes as one set process --If even one process fails, the transaction as a whole will fail. --If it fails, it means that all the processing was not done.

The basic syntax is like this


model.transaction do
  #Access processing to the table
  #Access processing to the table
end
  #Processing when transaction processing is successful
rescue => e
  #Processing when transaction processing fails

As a caveat, "use a method that raises an exception when processing fails".

If a transaction fails in any one of the included processes, it determines that all the processes in the transaction have not been performed, but the condition for not doing so is "an exception occurs".

Let's actually implement it.

Implementation

The app we were developing this time had a user grouping function. Therefore, it is assumed that the user who created the group automatically becomes the user who belongs to the group when creating a new group. Therefore, when creating a group, consider using a transaction to avoid unexpected behavior.

The table structure looks like this. スクリーンショット 2020-07-07 19.57.10.png

At the same time as creating the groups table instance, I wanted to create a group_users table (intermediate table between users table and groups table) with the id of the logged-in user as the user_id column.

  1. Create groups table instance
  2. Create a group_users table instance

If either process of 1 or 2 fails for some reason, transaction is used in the create action of the groups controller so that both processes have not been processed.

groups_controller.rb


#Excerpt from the create action part
#Variable current_user contains an instance of the logged-in user

  def create
    @group = Group.new(group_params)

    #Apply transaction(Create group and create intermediate table at the same time)
    # save!And create!When"!Please note that "" is attached!
    @group.transaction do
      @group.save!
      current_user.group_users.create!(group_id: @group.id, permission: true)
    end
    #Processing when transaction is successful
      flash[:success] = 'Created a new group'
      redirect_to @group
    rescue => e
    #Processing when transaction fails
      flash.now[:danger] = 'Group creation failed'
      render :new
  end

Note that both processes in this transaction are marked with a "!" And use a method that raises an exception when table data creation fails!

If the following is implemented without using transaction, there is a concern that an unmanned group will be created if the creation of the group_users table fails for some reason.

groups_controller.rb



#When not using transaction

def create
  @group = Group.new(group_params)

  if @group.save
    current_user.group_users.create(group_id: @group.id, permission: true)
    flash[:success] = 'Created a new group'
    redirect_to @group
  else
    flash.now[:danger] = 'Group creation failed'
    render :new: 
  end
end

Finally

Thank you for reading the article! I managed to implement it while investigating this time, but honestly I do not have a deep understanding of transactions. If you have any mistakes or better description methods, please feel free to comment. I used the following article as a reference. Thank you very much.

Recommended Posts

[Rails] I tried to implement a transaction that combines multiple DB processes
I tried to make a Web API that connects to DB with Quarkus
I tried to implement a server using Netty
[Rails] I tried to create a mini app with FullCalendar
I tried using Hotwire to make Rails 6.1 scaffold a SPA
[Rails] I tried to implement batch processing with Rake task
I tried to implement a buggy web application in Kotlin
[Rails] I tried to implement "Like function" using rails and js
I tried to implement the image preview function with Rails / jQuery
I tried to build a simple application using Dockder + Rails Scaffold
I tried to make a group function (bulletin board) with Rails
I tried to introduce CircleCI 2.0 to Rails app
I tried to implement the Iterator pattern
I tried to implement ModanShogi with Kinx
How to implement a slideshow using slick in Rails (one by one & multiple by one)
Rails API mode I tried to implement the keyword multiple search function using arrays and iterative processing.
I tried to easily put CentOS-7 in a PC that I no longer need
I tried to implement polymorphic related in Nogizaka.
[First environment construction] I tried to create a Rails 6 + MySQL 8.0 + Docker environment on Windows 10.
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
[Rails] I tried to raise the Rails version from 5.0 to 5.2
I tried to organize the session in Rails
java I tried to break a simple block
[Rails / JavaScript / Ajax] I tried to create a like function in two ways.
I tried to develop a man-hour management tool
I tried to develop a DUO3.0 study website.
I tried to implement deep learning in Java
I tried to create a LINE clone app
How to implement a like feature in Rails
I tried to develop a website to record expenses.
I tried to break a block with java (1)
I tried using Wercker to create and publish a Docker image that launches GlassFish 5.
I tried to make a message function of Rails Tutorial extension (Part 1): Create a model
I want to use PowerMock in a class that combines parameterized tests and ordinary tests
A story I was addicted to when getting a key that was automatically tried on MyBatis
I tried to implement file upload with Spring MVC
How to implement a like feature in Ajax in Rails
I tried to implement TCP / IP + BIO with JAVA
I tried to implement Firebase push notification in Java
I tried to develop a ramen shop sharing website.
I tried to decorate the simple calendar a little
I want to use a little icon in Rails
I tried to create a Clova skill in Java
I tried to make a login function in Java
I tried to make FizzBuzz that is uselessly flexible
I want to define a function in Rails Console
I tried to implement Stalin sort with Java Collector
Rails6 I tried to introduce Docker to an existing application
[Java] I tried to implement Yahoo API product search
I tried to implement the Euclidean algorithm in Java
[Rails 6.0, Docker] I tried to summarize the Docker environment construction and commands necessary to create a portfolio
[Java] I tried to make a rock-paper-scissors game that beginners can run on the console.
I tried to make a message function of Rails Tutorial extension (Part 2): Create a screen to display
[Ruby on Rails] Since I finished all Rails Tutorial, I tried to implement an additional "stock function"
[Swift] I tried to implement exception handling for vending machines
I tried to implement the like function by asynchronous communication
I tried to create a java8 development environment with Chocolatey
I tried to introduce Bootstrap 4 to the Rails 6 app [for beginners]
I tried adding a separator line to TabLayout on Android
I tried to modernize a Java EE application with OpenShift.
I want to implement a product information editing function ~ part1 ~