shou2017.com
JP

Uploading Images in Rails 5

Sat Feb 3, 2018
Sat Aug 10, 2024

Use carrierwave to upload images.

For now, since this is just a sample, we’ll use scaffold to create an item. Later, we’ll add image:string, but you can create it here as well.

$ rails g scaffold item description:text

Add the following to the Gemfile and run bundle install.

gem 'carrierwave'

Add an image column to the items table.

$ rails g migration AddImageToItems image:string
$ rake db:migrate

Configuring CarrierWave

With CarrierWave, you can enable image upload functionality by creating a program file called an uploader. Here, since we created image, we’ll match the column name to this. The name itself is arbitrary.

$ rails g uploader image

If app/uploaders/image_uploader.rb is generated, you’re good to go.

Next, add the following code to app/models/item.rb.

class Item < ActiveRecord::Base
  mount_uploader :image, ImageUploader
end

Add code to the view and controller to upload and save images. When creating a new item, you can select a file to upload and save the URL to the table when saving the item.

Update app/views/items/_form.html.erb as follows. This allows you to select and attach an image file.

<%= form_for(@item) do |f| %>
  <% if @item.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@item.errors.count, "error") %> prohibited this item from being saved:</h2>

      <ul>
      <% @item.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end  %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :description %><br>
    <%= f.text_area :description %>
    <%= f.file_field :image %> ← Added this line.
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end  %>

Next, configure the controller.

Update items_controller as follows. Add image to the permitted keys in the strong parameters.

private
  # Use callbacks to share common setup or constraints between actions.
  def set_item
    @item = Item.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def item_params
    params.require(:item).permit(:description, :image)
  end
end

Adjusting the Appearance

Make the images visible on the index page. Update app/views/items/index.html.erb as follows.

<p id="notice"><%= notice %></p>

<h1>Listing Items</h1>

<table>
  <thead>
    <tr>
      <th>Description</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @items.each do |item| %>
      <tr>
        <td><%= item.description %></td>
        <td><%= image_tag item.image.url %></td> ← Added this line.
        <td><%= link_to 'Show', item %></td>
        <td><%= link_to 'Edit', edit_item_path(item) %></td>
        <td><%= link_to 'Destroy', item, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Item', new_item_path %>

That’s it.

However, you may encounter a NameError uninitialized-constant. I did too.

After some searching, I found that restarting Spring resolved the issue. Some people resolved it by modifying config/application.rb, but restarting is simpler if it works.

Spring is an application preloader.

Check the status.

$ spring status

Stop Spring.

$ spring stop

Start it again.

$ rails c
See Also