質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ページネーション

Webアプリケーションにおいて、1ページに収まらないコンテンツを、各ページへのリンクを並べてアクセスしやすくする手法をページネーションと呼びます。

Q&A

解決済

1回答

2383閲覧

gem:kaminariを使用していて発生したundefined method `total_pages'というエラーを解決したい。

fleatama

総合スコア13

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ページネーション

Webアプリケーションにおいて、1ページに収まらないコンテンツを、各ページへのリンクを並べてアクセスしやすくする手法をページネーションと呼びます。

0グッド

0クリップ

投稿2020/05/19 11:12

編集2020/05/19 22:27

前提・実現したいこと

現在Railsを使用してYouTubeの動画をタイトルとURLの末尾11桁を利用して記録するWebアプリを作り、
タグ機能を実装することで登録した動画をジャンルや単語でまとめることで擬似的にYouTubeのプレイリストを作成出来るようなアプリを作ろうとしています。

そこでgem kaminariを使用してのページネーションを実現しようとしていたのですが、
プルダウン式のタグ選択機能と併用しようとしていたら上記タイトル通りのエラーが発生してしまいました。

現状の自分の知識では該当するエラーを解決出来ず、検索しても自分の環境に該当するものや近い解決手段が見付からずどうしても直接解決に至りそうなものが見つからなかったので質問させていただきました。

未定義であると言われているtotal_pagesという単語についても自分でControllerModelに記述した記憶も無く心辺りが無くておそらくgem側が用意しているものなのでは無いかと思うのですが、
コードを書き換えて色々と試してみてもエラーの内容が全く変わらず途方に暮れているところです。

また、念の為、タグによる検索機能を排除した状態で通常通りのページネーションは可能なのかと思いindex.html.erbのタグのプルダウン
を行うための該当コードをコメントアウトしてみたところページネーションは問題無く動作しました。

おそらくmovieとplaylistを繋いでいることがページネーションに引数を渡して結果を表示させる際に干渉しているのではないかと考えました。

エラーメッセージ内に記載されているActiveRecord_Relationがなんとなくリレーションに関わるものであることは分かったのですが、該当するファイルがあるvendor以下のファイルについてはあまり触ったことが無く全く理解が出来ていない状態なのでどうして良いか分からない状態です。

予想ではmovies_controller.rb内のindexアクションの記述によって改善出来るのでは無いかと考えているのですが、どのように記述を変えるべきなのか見当が付いていない状況です。

勉強不足・力不足で自力ではまだまだ足りないところが多く皆様のお力添えを頂きたいと思い質問させていただきました。

どなたかご協力いただければ幸いです。宜しくお願いしたします。

発生している問題・エラーメッセージ

NoMethodError in Movies#index undefined method `total_pages' for #<Movie::ActiveRecord_Relation:0x00007fde8d966888>

該当のソースコード

Modelはuser,playlist,movieそしてmovieとplaylistの間を繋いでリレーションを作っている中間テーブルのmovie_playlist_relationがあります。

Ruby

1# app/models/user.rb ユーザーのモデル 2 3class User < ApplicationRecord 4 devise :database_authenticatable, :registerable, 5 :recoverable, :rememberable, :validatable 6 has_many :movies, dependent: :destroy 7 has_many :playlists, dependent: :destroy 8end

Ruby

1# app/models/playlist.rb プレイリストのデータを記録するためのモデル 2 3class Playlist < ApplicationRecord 4 has_many :movie_playlist_relations, dependent: :destroy 5 has_many :movies, through: :movie_playlist_relations 6 default_scope -> { order(created_at: :desc) } 7end

Ruby:

1# app/models/movie.rb 動画を登録しタイトルとURLを記録するためのモデル 2 3class Movie < ApplicationRecord 4 has_many :movie_playlist_relations, dependent: :destroy 5 has_many :playlists, through: :movie_playlist_relations 6 default_scope -> { order(created_at: :desc) } 7end

Ruby

1# app/models/movie_playlist_relation.rb 中間テーブルのモデル 2 3class MoviePlaylistRelation < ApplicationRecord 4 belongs_to :movie 5 belongs_to :playlist 6end

Ruby

1# app/controllers/movies_controller.rb 動画を記録し記録した動画の一覧などを表示したりするためのController 2 3class MoviesController < ApplicationController 4 before_action :set_movie, only: [:show, :edit, :update, :destroy] 5 # before_action :authenticate_user! 6 7 def index 8 # この箇所をどうにかしたいと思っているが解決策が分からない。 9 @movies = Movie.page(params[:page]) 10 @movies = params[:playlist_id].present? ? Playlist.find(params[:playlist_id]).movies : Movie.all.page(params[:page]) 11 end 12 13 def show 14 @movie = Movie.find(params[:id]) 15 end 16 17 def new 18 @movie = Movie.new 19 @movie.movie_playlist_relations.build 20 end 21 22 def edit 23 end 24 25 def create 26 @movie = current_user.movies.build(movie_params) 27 url = params[:movie][:youtube_url] 28 url = url.last(11) 29 @movie.youtube_url = url 30 31 respond_to do |format| 32 if @movie.save 33 format.html { redirect_to @movie, notice: 'Movie was successfully created.' } 34 format.json { render :show, status: :created, location: @movie } 35 else 36 format.html { render :new } 37 format.json { render json: @movie.errors, status: :unprocessable_entity } 38 end 39 end 40 end 41 42 def update 43 respond_to do |format| 44 if @movie.update(movie_params) 45 format.html { redirect_to @movie, notice: 'Movie was successfully updated.' } 46 format.json { render :show, status: :ok, 47 location: @movie } 48 else 49 format.html { render :edt } 50 format.json { render json: @movie.errors, status: 51 :unprocessable_entity } 52 end 53 end 54 end 55 56 def destroy 57 @movie.destroy 58 respond_to do |format| 59 format.html { redirect_to movies_url, notice: 'Movie was successfully destroyed.' } 60 format.json { head :no_content } 61 end 62 end 63 64 private 65 66 def set_movie 67 @movie = Movie.find(params[:id]) 68 end 69 70 # def movie_params 71 # params.require(:movie).permit(:title, :youtube_url) 72 # params.require(:playlist).permit(:playlist_name, playlist_ids:[]) 73 # end 74 75 def movie_params 76 params.require(:movie).permit(:title, :youtube_url, :playlist_name, playlist_ids: []) 77 end 78end

Ruby

1# routes.rb deiviseを使用しているためuser周りのルーティングがややごちゃごちゃしてしまっているかもしれません 2 3Rails.application.routes.draw do 4 root 'static_pages#home' 5 get 'help', to:'static_pages#help' 6 get 'about', to:'static_pages#about' 7 get 'contact', to:'static_pages#contact' 8 get '/', to: 'users#index' 9 devise_for :users, :controllers => { 10 :registrations => 'users/registrations', 11 :sessions => 'users/sessions', 12 :passwords => 'users/passwords' 13 } 14 devise_scope :user do 15 # get 'user/:id', to: 'users/registrations' 16 get 'signup', to: 'users/registrations#new' 17 get 'login', to: 'devise/sessions#new' 18 post 'login', to: 'devise/sessions#create' 19 delete 'signout', to: 'devise/sessions#destroy' 20 end 21 resources :users, :only => [:index, :show] 22 resources :movies do 23 resource :playlists, only: [:create, :destroy] 24 end 25 resources :playlists 26end

ERB

1# app/views/movies/index.html.erb 2 3<p id="notice"><%= notice %></p> 4 5<h1>Movies</h1> 6 7  # ここからがタグのプルダウンをするためのコード 8 <%= form_tag movies_path, method: :get, class: 'boards__searchForm' do %> 9 <%= select_tag :playlist_id, 10 options_from_collection_for_select(Playlist.all, :id, :playlist_name, params[:playlist_id]), 11 { 12 prompt: 'プレイリストをタグで絞り込み検索', 13 onchange: 'submit(this.form);' 14 } 15 %> 16 <% end %> 17 #ここまでがタグのプルダウンをするためのコード 18 19<%= paginate @movies %> 20 21<div class="container-fluid"> 22 <div class="row"> 23 <% @movies.each do |movie| %> 24 <div class="col-md-6"> 25 <div> 26 <%= movie.title %> 27 <br> 28       # この部分がデータベースに記録されたURLの末尾11桁から動画をサムネイルで引っ張って来るためのコード 29 <iframe width="560" height="315" src="https://www.youtube.com/embed/<%= movie.youtube_url %>" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> 30 <br> 31 <%= link_to 'Show', movie %> 32 <br> 33 <%= link_to 'Edit', edit_movie_path(movie) %> 34 <br> 35 <%= link_to 'Destroy', movie, method: :delete, data: { confirm: 'Are you sure?' } %> 36 <br> 37 </div> 38 </div> 39 <% end %> 40 </div> 41</div> 42 43<br> 44 45<%= link_to 'New Movie', new_movie_path %> 46<%= paginate @movies %>

とりあえず原因となりそうなソースコードを列挙してみましたが、
原因になりそうなコードがまだ不足していたらすみません。
指摘していただければ追記させていただきます。

試したこと

kaminariの初期設定のために

$ bin/rails g kaminari:config

$ bin/rails g kaminari:views default

をして

ERB

1# app/views/kaminari/_paginator.html.erb 2 3<%# The container tag 4 - available local variables 5 current_page: a page object for the currently displayed page 6 # ここにtotal_pagesという項目がある。 7 total_pages: total number of pages 8 per_page: number of items to fetch per page 9 remote: data-remote 10 paginator: the paginator that renders the pagination tags inside 11-%> 12<%= paginator.render do -%> 13 <nav class="pagination" role="navigation" aria-label="pager"> 14 <%= first_page_tag unless current_page.first? %> 15 <%= prev_page_tag unless current_page.first? %> 16 <% each_page do |page| -%> 17 <% if page.display_tag? -%> 18 <%= page_tag page %> 19 <% elsif !page.was_truncated? -%> 20 <%= gap_tag %> 21 <% end -%> 22 <% end -%> 23 <% unless current_page.out_of_range? %> 24 <%= next_page_tag unless current_page.last? %> 25 <%= last_page_tag unless current_page.last? %> 26 <% end %> 27 </nav> 28<% end -%>

にてtotal_pagesという項目を見付けることは出来ましたがこれをどう活用して良いのか分かりませんでした。

補足情報(FW/ツールのバージョンなど)

Ruby 2.6.3
Rails 5.2.4.1
devise (4.7.1)
kaminari (1.2.0)
kaminari-actionview (1.2.0)
kaminari-activerecord (1.2.0)

参考にした記事など

リレーションやタグ関連の実装に関してはこの記事を参考にさせていただきました。

railsでタグ検索機能を実装し多対多を理解する - Qiita

動画の埋め込みに関するコードについてはこの記事を参考にしています

railsアプリに投稿されたYouTubeURLを自動的に埋め込み表示させる方法無理やり編 - Qiita

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

自己解決することが出来ました。
ただ、突然の思い付きでやってみただけでたまたまそれが噛み合って解決出来てしまった感じなので結局の所何が悪かったのか?という理屈については理解が出来ていません。今後の勉強でそれについても理解して行きたいと考えています。

では以下が解決に至った手段です。

Ruby

1# app/controllers/movies_controller.rb 2 3 def index 4 @movies = params[:playlist_id].present? ? Playlist.find(params[:playlist_id]).movies : Movie.page(params[:page]) 5 end

Ruby

1# app/controllers/movies_controller.rb 2 3 @movies = params[:playlist_id].present? ? Playlist.find(params[:playlist_id]).movies.page : Movie.page(params[:page])

とすることで解決出来た。

元々このコード自体質問の参考にした記事の中にあったものを流用していたもので自身でも理解がしっかりと出来ていなかったのでずっとこのコードについて考えていたのですが、
:の前後で実はコードがif文のように分岐しているのではないか?と考えました。

moviesではタグを選んだ場合のページが表示される、
Movie.page(params[:page])ではタグを何も選択していない状態のページが表示される。
このような分岐があるのではないかと考え思い付きでmoviesの後に.page
を挿入してみた所エラーが表示されなくなりページが表示されるようになりました。

理屈を全く理解出来ていないのでこれが根本的な解決として捉えて良いのかまだ分からないのですが、
とりあえずエラー出なくなったので解決としたいと思います。

投稿2020/05/20 06:52

fleatama

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問