8

के साथ ठीक से काम नहीं करता है हाल ही में मैं रेल 4 और एचएबीटीएम संबंध के साथ रहस्यमय बग में भाग गया। मेरे सारे Gemfile के पहले:रेल 4 है_and_belongs_to_many कथन

source 'https://rubygems.org' 
gem 'rails', '~> 4.1.6' 
gem 'pg' 

अगला। मेरी मॉडल:

class User < ActiveRecord::Base 
end 

class Teacher < User 
    has_and_belongs_to_many :resources, foreign_key: :user_id 
end 

class Resource < ActiveRecord::Base 
    has_and_belongs_to_many :teachers, association_foreign_key: :user_id 
end 

कच्चे डीबी डेटा:

select * from resources; 
id |   created_at   |   updated_at 
----+----------------------------+---------------------------- 
    1 | 2014-10-13 08:24:07.308361 | 2014-10-13 08:24:07.308361 
    2 | 2014-10-13 08:24:07.889907 | 2014-10-13 08:24:08.156898 
    3 | 2014-10-13 08:24:08.68579 | 2014-10-13 08:24:08.884731 
    4 | 2014-10-13 08:24:09.997244 | 2014-10-13 08:24:10.205753 
(4 rows) 

select * from users; 
id |   created_at   |   updated_at   | type 
----+----------------------------+----------------------------+--------- 
13 | 2014-10-13 08:24:01.086192 | 2014-10-13 08:24:01.086192 | Teacher 
12 | 2014-10-13 08:24:00.984957 | 2014-10-13 08:24:00.984957 | Teacher 
    2 | 2014-10-13 08:23:59.950349 | 2014-10-16 08:46:02.531245 | Teacher 
(3 rows) 

select * from resources_users; 
user_id | resource_id 
---------+------------- 
     13 |   1 
     2 |   2 
     12 |   3 
     2 |   4 
(4 rows) 

अंत में बग:

➜ rails_test bundle exec rails c 
Loading development environment (Rails 4.1.6) 
2.1.2 :001 > Resource.all.includes(:teachers).map(&:teachers).map(&:to_a) 
    Resource Load (0.6ms) SELECT "resources".* FROM "resources" 
    SQL (1.3ms) SELECT "resources_users".*, "resources_users"."user_id" AS t0_r0, "resources_users"."resource_id" AS t0_r1, "users"."id" AS t1_r0, "users"."created_at" AS t1_r1, "users"."updated_at" AS t1_r2, "users"."type" AS t1_r3 FROM "resources_users" LEFT OUTER JOIN "users" ON "users"."id" = "resources_users"."user_id" AND "users"."type" IN ('Teacher') WHERE "users"."type" IN ('Teacher') AND "resources_users"."resource_id" IN (1, 2, 3, 4) 
=> [ 
[#<Teacher id: 13, created_at: "2014-10-13 08:24:01", updated_at: "2014-10-13 08:24:01", type: "Teacher">], 
[], 
[], 
[]] 

जैसा कि आप देख शिक्षकों की केवल पहली सरणी संग्रह में लौट आए। हालांकि रेल द्वारा उत्पन्न एसक्यूएल सही है और सभी डेटा देता है:

SELECT "resources_users".*, "resources_users"."user_id" AS t0_r0, "resources_users"."resource_id" AS t0_r1, "users"."id" AS t1_r0, "users"."created_at" AS t1_r1, "users"."updated_at" AS t1_r2, "users"."type" AS t1_r3 FROM "resources_users" LEFT OUTER JOIN "users" ON "users"."id" = "resources_users"."user_id" AND "users"."type" IN ('Teacher') WHERE "users"."type" IN ('Teacher') AND "resources_users"."resource_id" IN (1, 2, 3, 4); 
user_id | resource_id | t0_r0 | t0_r1 | t1_r0 |   t1_r1   |   t1_r2   | t1_r3 
---------+-------------+-------+-------+-------+----------------------------+----------------------------+--------- 
     13 |   1 | 13 |  1 | 13 | 2014-10-13 08:24:01.086192 | 2014-10-13 08:24:01.086192 | Teacher 
     2 |   2 |  2 |  2 |  2 | 2014-10-13 08:23:59.950349 | 2014-10-16 08:46:02.531245 | Teacher 
     12 |   3 | 12 |  3 | 12 | 2014-10-13 08:24:00.984957 | 2014-10-13 08:24:00.984957 | Teacher 
     2 |   4 |  2 |  4 |  2 | 2014-10-13 08:23:59.950349 | 2014-10-16 08:46:02.531245 | Teacher 
(4 rows) 

किसी को भी पहले इस तरह के समस्या का सामना किया? मैं समझ नहीं पा रहा हूं कि यहां क्या हो रहा है।

पीएस यदि आप Resource.all.includes(:teachers).map { |r| r.reload.teachers } करते हैं तो परिणाम सही है। हालांकि यह include से सभी को समझ में आता है और एन + 1 समस्या प्रदान करता है।

अपडेट: उल्लेख करने योग्य एक और खोज। अगर मैं एसटीआई को हटा देता हूं तो सब कुछ ठीक काम करता है।

+2

बस चाहता हूँ कि 'has_and_belongs_to_many' की तरह है यहाँ उल्लेख कई से अधिक रिश्तों के लिए पुराना स्कूल तरीका। एक बेहतर विकल्प है 'है_मनी: के माध्यम से'। [स्रोत] (http://aihuiong.com/post/829841945/rails-hasandbelongstomany-vs-hasmany-through) – zhurora

+0

बस यह कहना चाहते हैं कि 'has_and_belongs_to_many' के बारे में" पुराना स्कूल "नहीं है, आपको उस प्रकार के एसोसिएशन का उपयोग करना चाहिए आपके काम के लिए सबसे उपयुक्त है। बहुत सी चीजों के लिए, एचएबीटीएम बिल्कुल ठीक है। – sevenseacat

उत्तर

0

मैं pg मणि के साथ उन लोगों ActiveRecord मॉडल और रेल 4.1.6 में डेटाबेस रिकॉर्ड निर्मित और सही व्यवहार देखा:

irb(main):017:0> Resource.all.includes(:teachers).map(&:teachers).map(&:to_a) Resource Load (0.6ms) SELECT "resources".* FROM "resources" SQL (6.9ms) SELECT "resources_users".*, "resources_users"."id" AS t0_r0, "resources_users"."resource_id" AS t0_r1, "resources_users"."user_id" AS t0_r2, "users"."id" AS t1_r0, "users"."type" AS t1_r1, "users"."created_at" AS t1_r2, "users"."updated_at" AS t1_r3 FROM "resources_users" LEFT OUTER JOIN "users" ON "users"."id" = "resources_users"."user_id" AND "users"."type" IN ('Teacher') WHERE "users"."type" IN ('Teacher') AND "resources_users"."resource_id" IN (1, 2, 3, 4) => [[#<Teacher id: 13, type: "Teacher", created_at: "2015-11-05 07:02:59", updated_at: "2015-11-05 07:02:59">], [#<Teacher id: 2, type: "Teacher", created_at: "2015-11-05 07:02:20", updated_at: "2015-11-05 07:02:32">], [#<Teacher id: 12, type: "Teacher", created_at: "2015-11-05 07:03:50", updated_at: "2015-11-05 07:03:50">], [#<Teacher id: 2, type: "Teacher", created_at: "2015-11-05 07:02:20", updated_at: "2015-11-05 07:02:32">]]

0

ही रेल 4.1.6 और pg के साथ यहाँ बग, लेकिन मैं प्राप्त कर सकते हैं प्रवास में resources_usersid क्षेत्र को हटाने नहीं द्वारा सही व्यवहार: ख में

def change 
    #create_table :resources_users, id: false do |t| 
    create_table :resources_users do |t| 
    t.integer :resource_id 
    t.integer :user_id 
    end 
end 

इसके अलावा eager_load काम करता है अन्य संगठनों के मामलों में (के साथ या id में शामिल होने की मेज पर बिना) और आप एक ही SQL क्वेरी के फायदे हैं:

Resource.eager_load(:teachers).map(&:teachers).map(&:to_a) 

उत्पादन:

irb(main):002:0> Resource.eager_load(:teachers).map(&:teachers).map(&:to_a) 
SQL (1.0ms) SELECT "resources"."id" AS t0_r0, "resources"."created_at" 
AS t0_r1, "resources"."updated_at" AS t0_r2, "users"."id" AS t1_r0, 
"users"."type" AS t1_r1, "users"."created_at" AS t1_r2, 
"users"."updated_at" AS t1_r3 FROM "resources" LEFT OUTER JOIN 
"resources_users" ON "resources_users"."resource_id" = "resources"."id" 
LEFT OUTER JOIN "users" ON "users"."id" = "resources_users"."user_id" 
AND "users"."type" IN ('Teacher') 
=> [[#<Teacher id: 1, type: "Teacher", created_at: "2015-11-05 
15:02:33", updated_at: "2015-11-05 15:02:33">], [#<Teacher id: 2, type: 
"Teacher", created_at: "2015-11-05 15:02:33", updated_at: "2015-11-05 
15:02:33">], [#<Teacher id: 2, type: "Teacher", created_at: "2015-11-05 
15:02:33", updated_at: "2015-11-05 15:02:33">], [#<Teacher id: 3, type: 
"Teacher", created_at: "2015-11-05 15:02:33", updated_at: "2015-11-05 
15:02:33">]]