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

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

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

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

Q&A

解決済

1回答

6816閲覧

Railsのアソシエーションでの値の取り出し方

Yuinyan

総合スコア312

Ruby on Rails 4

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

0グッド

0クリップ

投稿2016/09/15 06:53

###前提・実現したいこと
Railsでアソシエーションしている先の値を取得したいです。

具体的には下記のような構成になっています。

Event.rb
has_many :tickets

Ticket.rb
belongs_to :event
has_many :registers
has_many :users, through: :registers

User.rb
has_many :registers
has_many :users, through: :registers

Register.rb
belongs_to :user
belongs_to :ticket

ユーザーとチケットの間にRegisterという中間テーブルが存在し、取引時の情報が登録されることになっています。

やりたいこと:

1.イベントから見て、どのチケットを誰が買ったかを知りたい。

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

一つ一つやっていると配列の入れ子状態が激しく、よく分からなくなってしまっています。mapやpluckを駆使してもう少しすんなりとコードを書きたいです。

###該当のソースコード

現状は、まずイベントにチケットがあるかどうかを確認し、
あった場合は、チケット毎に取引(register)があるかを確認し、さらにそこから取り出したuser_idをUserから検索しているという、何とも初心者っぽいやり方をしています。。。

Ruby

1<% if @event.tickets.exists? %> 2 <% @event.tickets.each do |t| %> 3 <% if t.registers.exists? %> 4 <% t.registers.each do |r| %> 5 <% @user = User.find(r.user_id) %> 6 <%= r.name %>(<%= link_to @user.username, user_path(@user) %>) 7 <%= r.status_flg %> 8 <% end %> 9 <% end %> 10 <% end %> 11 <% end %> 12<% end %>

###試したこと

色々調べて、下記のやり方で、そのイベントが持っているチケットの取引をもう少し簡単に取得することができました。
っが、下記のコメントアウトしている部分はpluckが使えないというエラーが出てしまい、結局Userモデルからユーザー情報を取得するところまでは至っていません。

Ruby

1 @registers = @event.tickets.pluck(:id).map do |id| 2 Register.where(ticket_id: id,status_flg: 5) 3 end 4 5# @checkedinusers = @registers.pluck(:user_id,:name).map do |id,name| 6# [User.where(id: id),name] 7# end

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

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

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

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

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

guest

回答1

0

ベストアンサー

# User.rb has_many :registers has_many :tickets, through: :registers

ですかね?
そうだとして話を進めます。

イベントから見て、どのチケットを誰が買ったかを知りたい。

ruby

1@event.tickets.map(&:users).flatten

で、いけると思います。

ruby

1@event # => #<Event id: 1, created_at: "2016-10-18 02:52:37", updated_at: "2016-10-18 02:52:37"> 2@event.tickets.empty? # => true 3@event.tickets.map(&:users).flatten # => [] 4 5 6@event # => #<Event id: 2, created_at: "2016-10-18 02:52:55", updated_at: "2016-10-18 02:52:55"> 7@event.tickets.size # => 2 8@event.tickets.first.users # => #<ActiveRecord::Associations::CollectionProxy [#<User id: 3, created_at: "2016-10-18 02:54:47", updated_at: "2016-10-18 02:54:47">]> 9@event.tickets.second.users # => #<ActiveRecord::Associations::CollectionProxy []> 10@event.tickets.map(&:users).flatten # => [#<User id: 3, created_at: "2016-10-18 02:54:47", updated_at: "2016-10-18 02:54:47">]

が、この方法ですとEventに関連するがTicketが複数あった場合SQL文も複数発行されてしまいます。
俗にN+1 Query問題というやつです。

ruby

1@event.tickets.size # => 5 2# ticket が 5つ関連ついている場合は 3@event.tickets.map(&:users).flatten 4# Ticket Load (0.2ms) SELECT "tickets".* FROM "tickets" WHERE "tickets"."event_id" = ? [["event_id", 3]] 5# User Load (0.2ms) SELECT "users".* FROM "users" INNER JOIN "registers" ON "users"."id" = "registers"."user_id" WHERE "registers"."ticket_id" = ? [["ticket_id", 3]] 6# User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "registers" ON "users"."id" = "registers"."user_id" WHERE "registers"."ticket_id" = ? [["ticket_id", 4]] 7# User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "registers" ON "users"."id" = "registers"."user_id" WHERE "registers"."ticket_id" = ? [["ticket_id", 5]] 8# User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "registers" ON "users"."id" = "registers"."user_id" WHERE "registers"."ticket_id" = ? [["ticket_id", 6]] 9# User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "registers" ON "users"."id" = "registers"."user_id" WHERE "registers"."ticket_id" = ? [["ticket_id", 7]] 10 11# User Load も 5 つ

これを削減するには includes してあげるとよいです。

ruby

1@event.tickets.includes(:users).map(&:users).flatten 2# Ticket Load (0.2ms) SELECT "tickets".* FROM "tickets" WHERE "tickets"."event_id" = ? [["event_id", 3]] 3# Register Load (0.3ms) SELECT "registers".* FROM "registers" WHERE "registers"."ticket_id" IN (3, 4, 5, 6, 7) 4# User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (3, 4, 5, 6) 5 6# Ticket がいくつ関連付いていても User Load は 1 つ

あらすてき。

投稿2016/10/18 03:19

hana-da

総合スコア1728

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

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

Yuinyan

2016/10/26 05:53

ご連絡が遅くなりすみませんでした!
Yuinyan

2016/10/26 07:46

この場合、どのチケットに誰、というもの分かるのでしょうか。 イベント1に対してチケットが2つあって、そのチケットそれぞれに誰が購入したか。 @event.tickets.includes(:users).map(&:users).flatten をやったところ、イベントがもっているチケット全ての購入者は取り出せました。それぞれ取り出すのはどうすればよいのでしょうか。
Yuinyan

2016/10/26 08:07

すみません、@ticket.usersで取れますね、、、。大変失礼しました。有難うございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問