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

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

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

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

Q&A

解決済

1回答

7591閲覧

Rails 配列/ハッシュの特定の要素を抽出したい

shirou

総合スコア15

Ruby on Rails 5

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

0グッド

0クリップ

投稿2018/08/31 07:13

編集2018/08/31 08:40

前提・実現したいこと

DBより抽出したデータをrailsにて処理する際に、格納されているデータは配列なのかハッシュなのかが分からない為、適切なメソッドを利用出来ない。
また、配列であると確認出来た際に、配列に用いるメソッドを使用しても、そのメソッドに期待された結果が帰ってこない理由が分かりません...。
今回のケースでは、配列の要素を取り出すメソッドを使用した際になぜか配列まで取り出して表示されてしまっている・・どうしてこうなってしまったのか。

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

@members配列に格納されている:nameの値を抽出したいが、現状のコードでは

ruby

1おじいさん [#<Student id: 1, name: "おじいさん", grade: 3, content: "山に住んでいます", created_at: "2018-08-31 03:55:30", updated_at: "2018-08-31 03:55:30", bukatu_id: 1>]

member.namename:の値が取れたに思われたが、その後に配列そのものまで出力する結果になってしまっている

該当のソースコード

bukatucontrollerrb

1class BukatusController < ApplicationController 2 3 def index 4 @bukatus = Bukatu.all 5 end 6 7 def show 8 @bukatu = Bukatu.find(params[:id]) 9 @members = @bukatu.students 10 end 11 12end 13

studentscontrollerrb

1class StudentsController < ApplicationController 2 3 def show 4 @student = Student.find(params[:id]) 5 end 6 7 def new 8 end 9 10 def create 11 @student = Student.new(student_params) 12 if @student.save 13 flash[:notice] = "登録出来ました!" 14 redirect_to @student 15 else 16 flash[:notice] = "再度入力し直して下さい!" 17 redirect_to new_student_path 18 end 19 end 20 21 private 22 def student_params 23 params.require(:student).permit(:name, :grade, :content, :bukatu_id) 24 end 25 26end

bukaturb

1class Bukatu < ApplicationRecord 2 has_many :students 3end

studentrb

1class Student < ApplicationRecord 2 belongs_to :bukatu 3 validates :name,presence: true 4 validates :grade,presence: true 5 validates :content,presence: true 6 7end

showhtmlerb

1<h1>部員一覧</h1> 2<%= @bukatu.name %><br> 3<%= @members.each do |member| %> 4<%= member.name %> 5<% end %> 6<% console %> 7

試したこと

web_consoleにてそれぞれの変数が何を格納しているのかを確認

ruby

1>> @members 2=> #<ActiveRecord::Associations::CollectionProxy [#<Student id: 1, name: "おじいさん", grade: 3, content: "山に住んでいます", created_at: "2018-08-31 03:55:30", updated_at: "2018-08-31 03:55:30", bukatu_id: 1>]>

show.html.erbにてループで取り出している処理を直接記述すると異なる結果が帰ってくる。別のモデルの.nameの結果が帰ってきている為,@memberの帰属先を参照することに

ruby

1>> @members.name 2=> "Student"

ruby

1>> @members.class 2=> Student::ActiveRecord_Associations_CollectionProxy

ActiveRecord_Associations_CollectionProxyという謎の参照先が見つかったのでArrayメソッドは用いれないと判断。というのも

ruby

1>> @members.id 2NoMethodError: undefined method `id' for #<Student::ActiveRecord_Associations_CollectionProxy:0x00007fef0611bd98>

同じく格納されている:id.idとした結果が.nameと異なりエラーを吐くからだ。そこで

ruby

1>> @members.target 2=> [#<Student id: 1, name: "おじいさん", grade: 3, content: "山に住んでいます", created_at: "2018-08-31 03:55:30", updated_at: "2018-08-31 03:55:30", bukatu_id: 1>] 3>> @members.target.class 4=> Array

.targetを付けた所Arrayクラスに変わったので中身を確認。これで格納されている先は配列だと断定。

ruby

1>> @members.target.select { |x| x == name } 2NameError: undefined local variable or method `name' for #<#<Class:0x00007fef006e9fc8>:0x00007fef006e7e58>

selectメソッドを用いて該当するkeyから値を抽出しようと試みるもエラー

ruby

1>> @members.target.assoc(:name) 2=> nil

.assocメソッドを用いて同じことを試すもエラー。また

ruby

1>> @members.target.find(:name) 2=> #<Enumerator: [#<Student id: 1, name: "おじいさん", grade: 3, content: "山に住んでいます", created_at: "2018-08-31 03:55:30", updated_at: "2018-08-31 03:55:30", bukatu_id: 1>]:find(:name)>

findメソッドを用いると先頭に<Enumerator:が出現し、結局name:の値を取り出すことは叶わず。

ruby

1>> @members[:name] 2TypeError: no implicit conversion of Symbol into Integer

仮に保存されている形式がhashと仮定して、値を抜き取ってもシンボルを数値に変換できないと予想外のエラー。

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

Rails.5.2.0

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

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

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

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

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

guest

回答1

0

ベストアンサー

配列そのものまで出力してしまっているのは、
show.html.erb

erb

1<%= @members.each do |member| %>

の行で、出力の=を書かれていることが原因かと思います。

さて、試したことについて。素晴らしい探り方だと思います。
ひとつずつ見ていきます。

show.html.erbにてループで取り出している処理を直接記述すると異なる結果が帰ってくる。

これは=によって文字列として出力されるための差異です。

同じく格納されている:idを.idとした結果が.nameと異なりエラーを吐くからだ。

@members.nameは属性のnameではなく、Module/Class 自体の名前を返すメソッド Module#name が呼ばれています(確認していないので、誤りでしたらごめんなさい)。
@members.idは該当するメソッドがないことによるエラーです。

selectメソッドを用いて該当するkeyから値を抽出しようと試みるもエラー

Enumerable#selectはブロックの結果がtrueになる要素だけで構成された配列を返しますので、値の抽出には向きません。
エラーの原因は、ブロック内のnameが未定義であるためです。

.assocメソッドを用いて同じことを試すもエラー。

Array#assocは配列の中の要素の[0]を順に検査し、引数と同値を見つけた時点で要素を返すメソッドです。

ruby

1[[:apple, "リンゴ"], [:banana, "バナナ"], [:orange, "オレンジ"]].assoc(:banana) 2# => [:banana, "バナナ"]

findメソッドを用いると先頭に<Enumerator:が出現

Enumerable#findは要素を検査していき、ブロックの結果が真になった最初の要素を返します。
ブロックが与えられなかった場合は要素を検査する前のEnumeratorが返ります。
引数はブロックの結果が真になる要素が無かった場合にcallされるものです。

シンボルを数値に変換できないと予想外のエラー。

Array#[]delegaterecordsを通して呼ばれています。
@members.records[:name]と同義です。
Array#[]は引数を暗黙的に数値変換します(to_intという厳密な変換です)。
:nameto_intできる対象ではないため、このエラーが発生したのだと思います。

@membersからのnameの取り出し方ですが、

ruby

1@members.pluck(:name)

するのが良いのではないでしょうか。
参考: pluckの功罪(不要なDBアクセスを避けるために)|jkr_2255さん

投稿2018/09/01 01:08

編集2018/09/01 01:24
rigani_c

総合スコア69

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

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

shirou

2018/09/01 05:46

わーーなんと丁寧な回答でしょう!!ありがとうございます!! 配列そのものまで出力してしまっている原因がマイナーエラーで情けないですが・・。 関連付けしたモデルが持つカラムを `.name`とすることで要素を取り出す際は、繰り返し文でないと単一の要素としてではなく、Module#nameが呼ばれてしまうとは驚きでした。 頂いた回答を拝見しますと、なぜRubyでは動きそうなコードがRailsだとつまづくのだろうと今まで頭にあったのですが、メソッドより帰ってきた引数を見れば指定の方法が異なるのだよーとRailsは教えてくれていたのですね・・! `.pluck`メソッドは初めて目にしました。早速試して実行してみます! お時間ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問