[Ruby] [Rails] Implement image posting function

3 minute read


While creating a bulletin board site in a Rails project, I had the opportunity to implement an image posting feature.
I will leave the procedure here as a memorandum.

1. Creating an Image model

Create Model and migration file

There are two tables, posts table and ʻimage table. The post_id` column of the image table has a relation to the post table.


$ rails g model Image image_url:string post:references

Open the created migration file and check it.

db/migrate/Date and time_create_images.rb

class CreateImages < ActiveRecord::Migration[5.0]
  def change
    create_table :images do |t|
      t.string :image_url
      t.references :post, foreign_key: true


It seems that the migration file has been created without any problems.

Perform migration


$ rails db:migrate

Check Image Model


class Image < ApplicationRecord
  belongs_to :post

** belongs_to: post ** is written because the references are set in the migration file.

Add relation to existing Post Model

Add ** has_many: images **.


class Post < ApplicationRecord
  has_many :images #Add this line

With this, we were able to express a one-to-many relationship.

2. Use accepts_nested_attributes_for to enable updating of multiple models from one form

This time, I will register multiple models at once with one form so that images can be posted at the same time when posting a post.
What is needed for that

__ · accepts_nested_attributes_for__

If you use this, you will be able to register has_many related child records at once.

Preparation for handling nested forms

You will create a nested form to register the tables together. Let’s use a method called accepts_nested_attributes_for to make that possible.

Now, let’s set accepts_nested_attributes_for.
Add the settings to the Post model as follows.


class Post < ApplicationRecord
  has_many :images
  accepts_nested_attributes_for :images #Add this line

edit posts controller

Add the settings to posts_controller.rb as well.


class PostsController < ApplicationController

  def new
    @post = Post.new
    @post.images.build #Add this line

  def create
    @post = current_user.posts.build(post_params)
    if @post.save
      flash[:success] = 'I posted a message.'
      redirect_to root_url
      @posts = current_user.feel_posts.order('created_at DESC').page(params[:page]).per(10)
      flash.now[:danger] = 'Failed to post the message.'
      render 'posts/new'

  def post_params
    params.require(:post).permit(:content, :security, images_attributes: [:image_url]) #Add this line

And in params
images_attributes: [:image_url]
Was added.
The values of the parameters allowed by the nested model are described using images_attributes: in params.

Nest in a form using fields_for


<%= form_for(@post) do |f| %>
  <div class="form-group">
    <%= f.label :content, 'comment' %>
    <%= f.text_area :content, class: 'form-control', rows: 5, placeholder: 'Please enter a comment'  %>
  <div class="form-group">
    <%= f.label :security, 'Security_Level' %>
    <%= f.number_field :security, class: 'hoge', min: 0, max: 100 %>
  <%= f.fields_for :images do |i| %>  #Add to this line
    <%= i.file_field :image_url %>
  <% end %>
  <div class="text-right">
    <%= f.submit 'Post', class: 'btn btn-primary' %>
<% end %>

Now, you can register multiple models at once with one form.
Next, create an image upload function.

3. Install CarrierWave to allow you to upload images

Add the “Carrier Wave” gem to Gemfile.


gem 'carrierwave' #Image upload

Run bundle install.


$ bundle install

Creating an uploader


$ rails g uploader image

For image, set an appropriate name. This time, I named it image.
When you execute the command

create app/uploaders/image_uploader.rb

And the image uploader was created.

Model association

Add the following to /models/image.rb and specify the column name in mount_uploader.


class Image < ApplicationRecord
  belongs_to :post
  mount_uploader :image_url, ImageUploader #Add to this line

The image model has a column called image_url, which is designed to store the URL of the image.
By specifying a column in mount_uploader, Carrierwave will automatically upload the image when updating the column and save the URL of the upload destination.

Display the image saved by Carrierwave in View


   <%= link_to post.user.name, user_path(post.user) %><span class="text-muted">posted at<% post.created_at %></span>
   <p><%= post.content %></p>
   <% post.images.each do |image| %>  
     <%= image_tag image.image_url.url %>  #Show here
   <% end %>
   <p>Security_Level <%= post.security %></p>
 <div class="batton">
   <%= render 'favorites/favorite_button', post: post %>
   <% if current_user == post.user %>
     <%= link_to "Delete", post, method: :delete, data: { confirm: "Do you really want to delete this?" }, class: 'btn btn-danger btn-xs' %>
   <% end %>

The image posting function has been implemented.

At the end

You have now implemented the image posting function in your Rails project.
There are some points that can be improved, such as posting multiple images, but for the time being, it’s just a paragraph.

Thank you very much.