DEV Community

Chris Siku
Chris Siku

Posted on

Generate QR-code with Active Storage in Ruby on Rails 7

Image description

QR codes are an essential part of modern technology. They allow us to easily transfer information from one device to another. In this blog post, we will explore how to generate a QR code with Ruby on Rails using Active Storage and the gem "rqrcode."

Before we begin, let's make sure we have everything we need.

Create a new rails project named qr-code



rails new qr-code


Enter fullscreen mode Exit fullscreen mode

Add the rqrcode gem to the gem file by running the command below :



bundle add rqrcode


Enter fullscreen mode Exit fullscreen mode

Generate a scaffold for a Post model



rails g scaffold post title body:text


Enter fullscreen mode Exit fullscreen mode

This command generates several files that make it easy to quickly create a functional CRUD (Create, Read, Update, Delete) interface for managing Posts in our web application.

Here's what each part of the command does:

  • rails is the command to run Ruby on Rails.
  • g is short for "generate."
  • scaffold tells Rails to generate a complete set of files for a model, including a controller, views, and a migration.
  • post is the name of the model we want to generate.
  • title and body:text are attributes of the Post model. "title" is a string attribute, and "body" is a text attribute.

By generating a scaffold, we can quickly create a functional interface for managing Posts in our Rails application, saving time and effort. However, it's important to note that the generated code may not be perfect for our specific needs, and we may need to modify it to fit our requirements

Now let's install active_storage:

run the command bellow :



rails active_storage:install


Enter fullscreen mode Exit fullscreen mode

The is command is used to install and set up Active Storage in a Ruby on Rails application. Active Storage is a built-in framework for managing file uploads and attachments in Rails applications.

At this point of the project, we can now create our database, migrate all tables.



rails db:create
rails db:migrate


Enter fullscreen mode Exit fullscreen mode

Before running the server, we need to set the default URL options for the Rails action controller by specifying the host and port that the application should be running on.

To do so add the following line to your development.rb file under config/environments/



# config/environments/development.rb
config.action_controller.default_url_options = { host: "localhost:3000", port: 3000 }



Enter fullscreen mode Exit fullscreen mode

The begining of your file should look like in the following code snippet



# config/environments/development.rb
require "active_support/core_ext/integer/time"

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.
  config.action_controller.default_url_options = { host: "localhost:3000", port: 3000 }

  # In the development environment your application's code is reloaded any time
  # it changes. This slows down response time but is perfect for development

# [... more code below ...]
end


Enter fullscreen mode Exit fullscreen mode

Now you can start the application server by running the command bellow:



rails server


Enter fullscreen mode Exit fullscreen mode

Now open your browser and navigate to http://localhost:3000, you should see the interface below

Image description

If you can see the above interface in your browser, that means you are ready to start, if not, you can go back and follow all the steps for better understanding. ♻♻

  • As we have everything working, open you routes.rb file under /config/ directore and set the root path for the application:


# config/routes.rb
Rails.application.routes.draw do
  root "posts#index"
  resources :posts
end


Enter fullscreen mode Exit fullscreen mode

Go to app/models/post.rb and add the attach the qrcode to the post model



# app/models/post.rb
class Post < ApplicationRecord
  has_one_attached :qrcode, dependent: :destroy
end


Enter fullscreen mode Exit fullscreen mode

The code above Ruby on Rails ActiveRecord association method that defines a one-to-one attachment association for our post model.

The has_one_attached method is provided by the Active Storage library, and it enables attaching a single file to the post model. This attachment is stored in a separate table in the database, and the association is handled by Active Storage.

  • 👌 Good to know 👌: Overall, this code allows you to attach a single file to the post model, and ensures that the attachment is properly managed and cleaned up when needed. This is useful for cases where you need to store and manage file attachments within your Rails application.

Add the :qrcode in the strong parameters method (post_params) used to whitelist and filter the parameters passed to a create action.

  • Go to app\controllers\posts_controller.rb and make sure it looks like the following :


class PostsController < ApplicationController
# app\controllers\posts_controller.rb

# [ ... ]

  # Only allow a list of trusted parameters through.
  def post_params
    params.require(:post).permit(:title, :body, :qrcode)
  end
end


Enter fullscreen mode Exit fullscreen mode

Implement the before_commit in the Post model

  • Follow the [rqrcode] gem(https://github.com/whomwah/rqrcode) documentation to set everthing and after make sure that your post.rb file under app/models/ looks like the following :


# app/models/posts.rb
class Post < ApplicationRecord
  include Rails.application.routes.url_helpers
  has_one_attached :qrcode, dependent: :destroy

  before_commit :generate_qrcode, on: :create

  private

  def generate_qrcode
    # Get the host
    # host = Rails.application.routes.default_url_options[:host]
    host = Rails.application.config.action_controller.default_url_options[:host]

    # Create the QR code object
    # qrcode = RQRCode::QRCode.new("http://#{host}/posts/#{id}")
    qrcode = RQRCode::QRCode.new(post_url(self, host:))

    # Create a new PNG object
    png = qrcode.as_png(
      bit_depth: 1,
      border_modules: 4,
      color_mode: ChunkyPNG::COLOR_GRAYSCALE,
      color: "black",
      file: nil,
      fill: "white",
      module_px_size: 6,
      resize_exactly_to: false,
      resize_gte_to: false,
      size: 120,
    )

    # Attach the QR code to the active storage
    self.qrcode.attach(
      io: StringIO.new(png.to_s),
      filename: "qrcode.png",
      content_type: "image/png",
    )
  end
end


Enter fullscreen mode Exit fullscreen mode

For the above code snippet I define a generate_qrcode method that generates a QR code for the post and attaches it to the qrcode association using Active Storage.

Here's a brief summary of what the code does:

The Post model

  • Includes the Rails.application.routes.url_helpers module, which provides helper methods for generating URLs in Rails.

The before_commit :generate_qrcode, on: :create callback

  • Runs the generate_qrcode method before the post is committed to the database on creation.

The generate_qrcode method

  1. Generates a QR code for the post and attaches it to the qrcode association using Active Storage.

  2. Uses the Rails.application.config.action_controller.default_url_options[:host] configuration value to get the host name for the current Rails application.

  3. Generates a QR code using the RQRCode::QRCode.new method, passing in the post's URL as a string.

  4. Uses the qrcode.as_png method to generate a PNG image of the QR code.

  5. Attaches the QR code image to the qrcode association using Active Storage.

👌Good to know👌: Overall, this code generates a QR code image for a new post and attaches it to the post using Active Storage. The QR code can then be used to link to the post's URL, making it easy to share the post with others.

You can copy the above code and ajust it to your.

Here we go,

  • As now we have generated our qr-code, let's display it on the post page.

Open the _post.html.erb partial file under app/views/posts/ and add an image_tag for the qrcode as follow :



# app/views/posts/_post.html.erb
<div id="<%= dom_id post %>">
  <p>
    <strong>Title:</strong>
    <%= post.title %>
  </p>

  <p>
    <strong>Body:</strong>
    <%= post.body %>
  </p>

  <%= image_tag(url_for(post.qrcode)) %>
</div>


Enter fullscreen mode Exit fullscreen mode
  • Now save you project and create a new post on the browser. After creation you should see the qr-code displayed on the web page as the one on the image bellow :

Image description

Now you might need to test that qr-code.

  • There are several ways to test this and from your browser just
    open the site webqr and make sure your camera is filming your screen.

  • Or just use the qr-code reader of your phone.

In conclusion, generating QR codes is now an essential part of modern technology as it allows us to easily transfer information from one device to another.

In this blog post, we have learned how to generate a QR code with Ruby on Rails using Active Storage and the gem "rqrcode". By following the step-by-step guide provided in the post, we were able to create a functional CRUD interface for managing Posts in our web application, and also learned how to install and set up Active Storage in a Ruby on Rails application.

Finally, we attached a qrcode to our post model using Ruby on Rails ActiveRecord association method, added the :qrcode in the strong parameters method (post_params), and whitelisted and filtered the parameters passed to a create action.

Github : qrcode-generator

Documentation : rqrcode

Overall, this post provides an excellent guide for anyone looking to generate QR codes using Ruby on Rails.

Top comments (4)

Collapse
 
superails profile image
Yaroslav Shmarov

no point in adding the strong params here params.require(:post).permit(:title, :body, :qrcode)

Collapse
 
chrissiku profile image
Chris Siku

Thank you for that insight,
Gona check it out and update the post if neccessary

Collapse
 
k3vout profile image
Kevin S.

It works like a charm, thank you for your contribution!

Collapse
 
chrissiku profile image
Chris Siku

Thank you kevin S.