LoginSignup
2
0

More than 3 years have passed since last update.

carrierwave&accepts_nested_attributes_forメゾットを用いて、複数画像をアップロード

Last updated at Posted at 2019-06-04

今回の流れ

1.[自前に作成]carrierwaveの導入、tweetモデルを作る
2.複数画像投稿ができるtweet_imagesモデルを作る。
3.tweet_imagesモデルで投稿する複数画像をtweetと一緒にtweet/showのページで表示させます。
qiita.png

完成図

ezgif.com-video-to-gif.gif

accepts_nested_attributes_forとは

ネストした属性を使用すると、親を通じて関連レコードに属性を保存できます。 デフォルトではネストされた属性の更新は無効になっており、
#accepts_nested_attributes_forクラスメソッドを使用して有効にすることができます。 ネストした属性を有効にすると、モデルに属性ライターが定義されます。
以下より抜粋↓
(https://translate.google.com/translate?hl=ja&sl=en&u=https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html&prev=search)

私にはあまり理解できませんでした…。例を挙げて考えてみます。
サッカーチームが3つあるとします。
(サッカー少年たちの頭が割れちゃいました。申し訳ございません。)
image.png
チームのモデルを「teamモデル」とすると、カラムとして、
・チーム名・活動場所・チームカラー
などを登録できます!
しかし、teamモデルのみでは、各チームのメンバー、一人一人の名前や詳細情報を登録することはできません。

そこで、accepts_nested_attributes_forメゾットの登場です。
memberモデルで複数のメンバーを登録し、accepts_nested_attributes_forメゾットで
teamモデルと紐づければ、各チームのメンバーを登録できます!

では、さっそく本題を始めます。

自前にcarrierwaveの導入と、tweetモデルを作っておいた前提で進みます。

tweet_imagesのdbを作る

rails g model TweetImage
db/migrate***create_tweet_images.rb
class CreateTweetImages < ActiveRecord::Migration[5.1]
  def change
    create_table :tweet_images do |t|
      t.string :image
      t.integer :tweet_id
      t.timestamps
    end
  end
end
rails db:migrate

モデルを作る

tweet.rb
 #追加
 has_many :tweet_images, :dependent => :destroy
 accepts_nested_attributes_for :tweet_images, allow_destroy: true
tweet_image.rb
class TweetImage < ApplicationRecord
  mount_uploader :image, ImageUploader
  belongs_to :tweet
end

コントローラを編集

tweets_controller.rb
  def new
    @tweet = Tweet.new
#追加。今回は一度に3枚投稿したいので、3timesとしました。
    3.times{@tweet.tweet_images.build}
  end

  def show
#追加
    @tweet_images = @tweet.tweet_images
    @tweet_image = TweetImage.new
  end

  private
  def tweet_params
#追加
    params.require(:tweet).permit(:body, :image, :title, :url, :area, :means, :description, tweet_images_attributes: [:image])
  end
end

ルーティング

routes.rb
#追加
  resources :tweets do
    resources :tweet_images

view

tweetのshowページで表示させます。
今回は、bootstrapのカルーセルを使って表示させました。
image.png

tweet_new.html.erb
<body>
  <div class="container">
    <%= form_for(@tweet, :url => { controller:'tweets', action:'create'},class:"form-horizontal")do |f| %>
#省略

    <div class="form-group">
      <%= f.label :サブ画像 %>
      <%= f.fields_for :tweet_images do |i| %>
      <%= i.file_field :image, class:"form-control-file" %>
      <% end %>
      <span id="help8" class="form-text text-muted">
        販売したい実際の果物のサブ写真を撮影し、選択してください
      </span>
    </div>

#省略
      <div class="action">
        <%= f.submit "送信", class: "btn-gradient-radius" %>
      </div>
      <% end %>
      <a class="link_option", href="/tweets/index">戻る</a>
    </div>
    </body>
tweet_show.html.erb
      <div class="card cont pb-2 mb-1">
          <%= @tweet.title %><br>
          <div id="carouselexample" class="carousel slide" data-ride="carousel" style="width:300px, height:300px" data-interval="2000">
            <ol class="carousel-indicators">
              <li data-target="#carouselexample" data-slide-to="0" class="active"></li>
              <li data-target="#carouselexample" data-slide-to="1"></li>
              <li data-target="#carouselexample" data-slide-to="2"></li>
            </ol>

            <div class="carousel-inner">
              <div class="carousel-item active">
                <%= image_tag @tweet_images[0].image.to_s,width:300,height:300,class: "tweet_image rounded" %>
              </div>
              <div class="carousel-item">
                <%= image_tag @tweet_images[1].image.to_s,width:300,height:300,class: "tweet_image rounded" %>
              </div>
              <div class="carousel-item">
                <%= image_tag @tweet_images[2].image.to_s,width:300,height:300,class: "tweet_image rounded" %>
              </div>
            </div>


            <a class="carousel-control-prev" href="#carouselexample" data-slide="prev">
              <span class="carousel-control-prev-icon" aria-hidden="true"></span>
              <span class="sr-only">Previous</span>
            </a>

            <!-- 次の画像へ進むための矢印ポインタ -->
            <a class="carousel-control-next" href="#carouselexample" data-slide="next">
              <span class="carousel-control-next-icon" aria-hidden="true"></span>
              <span class="sr-only">Next</span>
            </a>
          </div>
        </div>

ただ単に表示させたい場合は、

tweets/show.html.erb
 <% @tweet_images.each do |t| %>
 <%= image_tag t.image.to_s,width:300,height:300%>
 <% end %>

と書けば表示できます!

なにか質問やミスがありましたら、コメント頂けると嬉しいです!
見ていただき、ありがとうございました。

参考にさせていただいた記事

(https://qiita.com/sinagaki58/items/a0d59cc41c6824bb5f67)
(https://qiita.com/shizuma/items/5bfcf6c1e855b959e135)

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0