質問失礼致します。
rails6でレッスンを投稿して募集できる機能を作ろうとしているのですが、子モデルの画像を呼び出したく、lesson_controllerでshowアクション内では呼び出せるのですが、index内で呼び出すことができません。
プログラミング初心者のため、初歩的なミスかもしれませんがお教えいただけますと嬉しいです。お手を煩わせてしまいすみません。
schema.rb
ruby
create_table "lesson_images", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "image" t.integer "lesson_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end create_table "lessons", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "title", null: false t.text "explain", null: false t.integer "price", null: false t.bigint "saler_id" t.bigint "buyer_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.bigint "user_id" end
lesson.rb
ruby
class Lesson < ApplicationRecord belongs_to :user has_many :lesson_images, dependent: :destroy end
lesson_image.rb
ruby
class LessonImage < ApplicationRecord belongs_to :lesson mount_uploader :image, ImageUploader end
routes.rb
ruby
Rails.application.routes.draw do root to: 'toppages#index' devise_for :users, controllers: { :registrations => 'users/registrations', :sessions => 'users/sessions', :passwords => 'users/passwords' } get 'users/show' => 'users#show' resources :users, only: [:show, :index] resources :messages, only: [:create] resources :rooms, :only => [:create, :show, :index] resources :lessons end
lesson_controller.rb
ruby
class LessonsController < ApplicationController before_action :ensure_current_user, :only => [:edit, :update] before_action :set_lesson, :only => [:show, :edit, :update] def index @lessons = Lesson.includes(:lesson_images).page(params[:page]).per(5) end def show @user = User.find_by(id: @lesson.user_id) @lesson_images = @lesson.lesson_images end def new @lesson = Lesson.new @lesson_images = @lesson.lesson_images.build end def create @lesson = Lesson.new(lesson_params) if @lesson.save redirect_to lessons_path else render :new end end def edit end def update if @lesson.update(lesson_params) redirect_to lesson_path else render :edit end end def destroy lesson = Lesson.find(params[:id]) if lesson.user_id == current_user.id if lesson.destroy redirect_to lessons_path, notice: "削除が完了しました" else redirect_to lessons_path, alert: "削除が失敗しました" end end end private def lesson_params params.require(:lesson).permit(:title,:explain,:price,lesson_images_attributes: [:id, :lesson_id, :image]).merge(user_id: current_user.id) end def ensure_current_user lesson = Lesson.find(params[:id]) if lesson.user_id != current_user.id redirect_to action: :index end end def set_lesson @lesson = Lesson.find(params[:id]) end end
index.html.erb
ruby
<div class="row row-cols-1 row-cols-md-3 g-4"> <div class="col"> <div class="card"> <% @lessons.each do |lesson| %> <p><a href="/lessons/<%= lesson.id %>"><%= lesson.title %></a></p> <p><%= lesson.price %></p> <p><%= lesson.explain %></p> <p><%= lesson.user_id %>さん</p> <% if lesson.lesson_image.image.blank? %> <%= image_tag "" %> <% else %> <%= image_tag lesson.lesson_images.image.url %> <% end %> <%= paginate @lessons %> <% end %> </div> </div> </div>
show.html.erb
ruby
<p><%= @lesson.title %></p> <p><%= @lesson.price %></p> <p><%= @lesson.explain %></p> <p><%= @lesson.user_id %></p> <% @lesson_images.each do |lesson_image| %> <% if lesson_image.image.blank? %> <%= image_tag "" %> <% else %> <%= image_tag lesson_image.image.url %> <% end %> <% end %> <% if user_signed_in? %> <%= link_to "編集", edit_lesson_path %> <%= link_to '削除', lesson_path(@lesson.id),method: :delete %> <% end %>
image_uploader.rb
ruby
class ImageUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick # Choose what kind of storage to use for this uploader: storage :file # storage :fog # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # Provide a default URL as a default if there hasn't been a file uploaded: def default_url(*args) # # For Rails 3.1+ asset pipeline compatibility: # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) 'default_lesson.png' # "/images/fallback/" + [version_name, "default.png"].compact.join('_') end # Process files as they are uploaded: # process scale: [200, 300] # # def scale(width, height) # # do something # end # Create different versions of your uploaded files: # version :thumb do process resize_to_fit: [300, 300] # end # Add an allowlist of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_allowlist %w(jpg jpeg png) end # Override the filename of the uploaded files: # Avoid using model.id or version_name here, see uploader/store.rb for details. # def filename # "something.jpg" if original_filename # end end
エラー文
undefined method `lesson_image' for #<Lesson id: 1, title: "テスト1", explain: "これはテストです1", price: 1000, saler_id: nil, buyer_id: nil, created_at: "2021-11-23 03:14:01.001941000 +0000", updated_at: "2021-11-23 03:14:01.001941000 +0000", user_id: nil> Did you mean? lesson_images lesson_images=
試したこと
▷lesson_image.imageに画像が保存されていない場合にエラーを吐いているのかと思い、if文で保存されていない場合は画像を表示しなくてもエラーを吐きました。
▷またアップローダーがうまくマウントできないのかと思い、画像ではなくidのみを呼び出した際もエラーがでました。
@lessonsのなかに全てのデータが入ってしまっていて特定のパラメーターを呼び出せていないからlesson_imageが認識されていないのかとおもったのですが、each文で取り出す際にひとつひとつ呼び出せるものではないのでしょうか?
それとも子モデルの呼び出しにはなにか特殊な方法が必要だったりするのでしょうか?
お手数をおかけしますが、よろしくお願いいたします。
まだ回答がついていません
会員登録して回答してみよう