🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

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

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 3

Ruby on Rails3はRubyによって書かれたオープンソースのウェブフレームワークです。Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

2回答

1111閲覧

Railsのsortメソッドについて

yuuki0218

総合スコア22

Ruby on Rails 5

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

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 3

Ruby on Rails3はRubyによって書かれたオープンソースのウェブフレームワークです。Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2019/11/29 08:17

背景

Rails3系からRails5系に資源のバージョンアップをする機会があり、メソッドの仕様について分からないことがあったのでご教示いただきたいです。

わからないこと

will_paginationを導入した環境でのsortメソッドについて

Rails3では

@resources = BookLibrary.paginate(:page => params[:page]) @resources.sort!{|a, b| a.code.to_i <=> b.code.to_i}

のようにしてModelから取得したインスタンスに対してsort!メソッドを使用してソートが動いていたのですが

Rails5に移行するとエラーになります。
一応下記のように破壊的をやめることで、先に進めるのですが

@resources = BookLibrary.paginate(:page => params[:page]) @resources = @resources.sort{|a, b| a.code.to_i <=> b.code.to_i}

これだとwill_paginationの方で
undefind method 'total_pages' for Array<xxxxxxxxx>
のようにエラーになります。

will_paginationのtotal_pagesメソッド内部ではwillpagination::collectionクラスに含まれる(@resources.)total_entriesの値を期待しているので、Arrayクラスで渡してしまうとエラーになってしまうという理解なのですが、なぜRails3ではsortメソッドを通ってもArrayにならないかがわかりません。sortメソッドの返り値はArrayクラスですよね?
※Rails3の環境でログに出すとsortメソッドを通った後もwillpagination::collectionを保っていました。

仕様変更であるとは思うのですが、ドキュメントを見つけられず実装に自信が持てません。

教えてほしいこと

  • なぜRails5ではsort!(破壊的メソッド)が使えなくなっているのか※Rails3では使えている。
  • Rails3ではsortメソッドを通ってもArrayクラスで返却されないのは何故か。(破壊的メソッドはインスタンスのクラスを変えないとかあるのでしょうか?)
  • will_paginationは配列で渡しても動くという記事を見かけましたが、Arrayを渡すとどうしてもtotal_pagesでエラーになります。これに対して改善のアプローチはあるでしょうか?

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

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

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

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

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

guest

回答2

0

配列の中身だけ置き換えるのはどうでしょうか?

ruby

1@resources = BookLibrary.paginate(:page => params[:page]).to_a 2@resources.replace(@resources.sort{|a, b| a.code.to_i <=> b.code.to_i})

投稿2019/11/29 09:41

編集2019/11/29 11:58
asm

総合スコア15149

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

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

yuuki0218

2019/11/29 10:36

ありがとうございます! 試してみたところ undefined method `replace' for #<BookLibrary::ActiveRecord_Relation:0x00007f3b680a9268> のエラーが出ました。 paginate通すとRelationオブジェクトになるので、だめそうですね。。
asm

2019/11/29 11:58

@resources = BookLibrary.paginate(:page => params[:page]).to_a @resources.replace(@resources.sort{|a, b| a.code.to_i <=> b.code.to_i}) ではどうでしょうか?
yuuki0218

2019/12/02 01:32

ありがとうございます。 上記のコードで試したところ、状況変わらずでした。。 以下のようにtotal_pagesのエラーが出てしまいますね。 undefined method `total_pages' for #<Array:0x00007f3b85e6a998>
guest

0

ベストアンサー

@resources = BookLibrary.order(:code).paginate(:page => params[:page])
では駄目なのでしょうか?

追記
こんなことやったことがあります。

@Models = @Relation #.to_a # ここから Will-Pagenatダマシ # group(customer_id) を含む Relation#count が総数を返さず customer_id # 毎の数を返すため、Cannot visit Customer::ActiveRecord_Relation や # ActionView::Template::Error (undefined method `total_pages' なFaitalを # 引き起こす。ので、 # view で呼ぶ will_paginate(@Models) のために # @Models に method total_pages と current_page を定義する # @models は pagenate を使わずに同じ結果となる検索を行なう。 eval "def @Models.count ; super.size ; end def @Models.total_pages ; (self.count/#{@Pagenation.to_f}).ceil ; end def @Models.current_page ;#{@page} ;end" @models = @Models.offset((@page-1)*@Pagenation).limit(@Pagenation)

とすると今回は

@resources = BookLibrary.paginate(:page => params[:page]) total_pages = @resources.total_pages @resources = @resources.sort{|a, b| a.code.to_i <=> b.code.to_i} eval "def @resources.current_page ;#{@page} ;end def @resources.total_pages; #{total_pages} ; end"

あたりでどうでしょう。。。

さらに追記
そこまでしないで良さそう
WillPagenate には @resources を渡し
データの描画には @resources_sorted = @resources.sort{|a, b| a.code.to_i <=> b.code.to_i} を使う

投稿2019/11/29 08:21

編集2019/11/29 23:53
winterboum

総合スコア23567

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

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

yuuki0218

2019/11/29 08:29

回答ありがとうございます。 orderでModel取得時にソートする方法も検討したのですが、 今回のバージョン移行の性質上sortで並び替えを行いたいと考えています。 というのも、codeの中身には数字のみではなく英字が含まれるパターンがあり、それをto_iしている影響で<=>での評価結果が正確なソート結果ではありません。 Rails5でもその結果を再現する必要がありますが、orderで並び替えてしまうと再現が難しい状況です。。
yuuki0218

2019/12/02 01:52

ありがとうございます。 なるほど、描画とpaginateそれぞれ別のインスタンスを渡す方法がありましたか。。 `@resources_sorted = @resources.sort{|a, b| a.code.to_i <=> b.code.to_i}` こちらのコードで実装したところ期待すべき結果が確認できました! ちなみにwill_paginate自体はArrayにも対応している(できる)という記事を見たことがあるのですが、 今回のようにsortメソッドを通った後のArrayでは実装できない理由とかってネットに周知されていたりするのでしょうか?(以下のエラーがでるのです。。) undefined method `total_pages' for #<Array:0x00007f3b85cf6558> total_pagesがなんなのかというところから完璧に理解していないので、初歩的な質問だったらすみません。
winterboum

2019/12/02 02:16

[will_paginate自体はArrayにも対応している(できる)という記事]は確認していないので、なんとも。 「total_pagesがなんなのか」ですが、 オブジェクト指向というのは、呼ぶ方はそれがmethodなのかpropatyなのか知る必要がない、 rubyはレシーバが何であるか、よりもそのmethodを持っているかが問題 のふたつがbackにありまして、 total_pagesという名から「全ページ数を返すmethodをActiveRecodeのrelationに追加したのだろう それはrelationのcountとparpageから計算するのだろう」 と見当をつけて、そのお騙しを定義してみた、というところです
yuuki0218

2019/12/02 02:39

分かりやすい説明ありがとうございます。 ということは、今回私はpaginateメソッドを通してrelationクラスのインスタンスを定義したものの、それはsortに通すことでArrayになっていた。 そのArrayインスタンスをViewのpaginateに渡したが、relationであれば参照できるであろう「countとparpage」のインスタンス?が無くtotal_pagesというメソッドを見つけられないという結果になっていたのですね。 [will_paginate自体はArrayにも対応している(できる)という記事]については上記の理解が無いことでの勘違いで、Arrayオブジェクトにも.paginateメソッドを通せるよ。という内容でした。 FYI: https://linuxserver.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/ruby/on-rails/will_paginate-array/ オブジェクト指向の理解が足りてないことを痛感し、とても勉強になりました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問