উত্তর:
বিভিন্ন ধরণের বহু রকমের সম্পর্ক রয়েছে; আপনাকে নিম্নলিখিত প্রশ্নগুলি নিজেকে জিজ্ঞাসা করতে হবে:
এটি চারটি বিভিন্ন সম্ভাবনা ছেড়ে দেয়। আমি নীচে এই উপর দিয়ে হাঁটা করব।
রেফারেন্সের জন্য: বিষয়টিতে রেল ডকুমেন্টেশন । এখানে "অনেকগুলি থেকে অনেকগুলি" নামে একটি বিভাগ রয়েছে এবং অবশ্যই তারা নিজেরাই ক্লাসের পদ্ধতিতে ডকুমেন্টেশন।
এটি কোডের মধ্যে সবচেয়ে কমপ্যাক্ট।
আমি আপনার পোস্টগুলির জন্য এই প্রাথমিক স্কিমাটি দিয়ে শুরু করব:
create_table "posts", :force => true do |t|
t.string "name", :null => false
end
যে কোনও বহু-বহু সম্পর্কের জন্য আপনার একটি যোগদানের টেবিলের প্রয়োজন। এখানে তার জন্য স্কিমাটি এখানে:
create_table "post_connections", :force => true, :id => false do |t|
t.integer "post_a_id", :null => false
t.integer "post_b_id", :null => false
end
ডিফল্টরূপে, রেলগুলি এই টেবিলটিকে আমরা যে দুটি টেবিলে যোগদান করছি তার নামের সংমিশ্রণটি বলবে। তবে এটি posts_posts
এই পরিস্থিতিতে যেমন পরিণত হবে , তাই আমি post_connections
পরিবর্তে নেওয়ার সিদ্ধান্ত নিয়েছি ।
এখানে খুব গুরুত্বপূর্ণ :id => false
, ডিফল্ট id
কলাম বাদ দিতে । এর জন্য টেবিলগুলিতে যোগ ব্যতীত রেলগুলি সেই কলামটি সর্বত্র চায় has_and_belongs_to_many
। এটি উচ্চস্বরে অভিযোগ করবে।
পরিশেষে, লক্ষ্য করুন যে কলামের নামগুলি post_id
দ্বন্দ্ব রোধ করার জন্য অ-মানক (পাশাপাশি ) নয় ।
এখন আপনার মডেলটিতে, আপনাকে কেবলমাত্র এই দু'টি অ-মানক জিনিস সম্পর্কে রেলগুলি জানাতে হবে। এটি নীচের মত দেখতে হবে:
class Post < ActiveRecord::Base
has_and_belongs_to_many(:posts,
:join_table => "post_connections",
:foreign_key => "post_a_id",
:association_foreign_key => "post_b_id")
end
এবং যে সহজভাবে কাজ করা উচিত! এখানে একটি উদাহরণ আইআরবি সেশন চালানো হয়েছে script/console
:
>> a = Post.create :name => 'First post!'
=> #<Post id: 1, name: "First post!">
>> b = Post.create :name => 'Second post?'
=> #<Post id: 2, name: "Second post?">
>> c = Post.create :name => 'Definitely the third post.'
=> #<Post id: 3, name: "Definitely the third post.">
>> a.posts = [b, c]
=> [#<Post id: 2, name: "Second post?">, #<Post id: 3, name: "Definitely the third post.">]
>> b.posts
=> []
>> b.posts = [a]
=> [#<Post id: 1, name: "First post!">]
আপনি দেখতে পাবেন যে সমিতিকে বরাদ্দ করা যথাযথভাবে সারণীতে posts
রেকর্ড তৈরি করবে post_connections
।
কিছু বিষয় লক্ষণীয়:
a.posts = [b, c]
, আউটপুটটি b.posts
প্রথম পোস্টকে অন্তর্ভুক্ত করে না।PostConnection
। আপনি সাধারণত কোনও has_and_belongs_to_many
সমিতির জন্য মডেল ব্যবহার করেন না । এই কারণে, আপনি কোনও অতিরিক্ত ক্ষেত্র অ্যাক্সেস করতে পারবেন না।ঠিক এখনই ... আপনি নিয়মিত ব্যবহারকারীর পেলেন যিনি আজ আপনার সাইটে কীভাবে সুস্বাদু তা সম্পর্কে আপনার পোস্টে একটি পোস্ট করেছেন। এই মোট অচেনা লোকটি আপনার সাইটে প্রায় আসে, সাইন আপ করে এবং নিয়মিত ব্যবহারকারীর অদক্ষতা নিয়ে একটি বদনাম পোস্ট লেখেন। সর্বোপরি, elsল একটি বিপন্ন প্রজাতি!
সুতরাং আপনি আপনার ডাটাবেসে পরিষ্কার করে দিতে চাই যে পোস্ট বি পোস্টের জন্য একটি বদনাম রেন্ট that এটি করার জন্য, আপনি সমিতিতে একটি category
ক্ষেত্র যুক্ত করতে চান ।
আমরা কি প্রয়োজন আর একটি নেই has_and_belongs_to_many
, কিন্তু একটি সমন্বয় has_many
, belongs_to
, has_many ..., :through => ...
এবং জন্য একটি অতিরিক্ত মডেল টেবিল যোগদান করুন। এই অতিরিক্ত মডেলটিই আমাদের অ্যাসোসিয়েশনে অতিরিক্ত তথ্য যুক্ত করার শক্তি দেয়।
এখানে আরও একটি স্কিমা রয়েছে, যা উপরোক্তর সাথে খুব সমান:
create_table "posts", :force => true do |t|
t.string "name", :null => false
end
create_table "post_connections", :force => true do |t|
t.integer "post_a_id", :null => false
t.integer "post_b_id", :null => false
t.string "category"
end
লক্ষ্য করুন কিভাবে, এই পরিস্থিতিতে, post_connections
আছে একটি আছে id
কলাম। ( কোনও :id => false
প্যারামিটার নেই )) এটি প্রয়োজনীয়, কারণ টেবিলটি অ্যাক্সেস করার জন্য নিয়মিত অ্যাক্টিভেকর্ড মডেল থাকবে।
আমি PostConnection
মডেলটি দিয়ে শুরু করব , কারণ এটি মৃত সহজ:
class PostConnection < ActiveRecord::Base
belongs_to :post_a, :class_name => :Post
belongs_to :post_b, :class_name => :Post
end
এখানে কেবল একটি জিনিস চলছে :class_name
যা প্রয়োজনীয়, কারণ রেলগুলি অনুমান করতে পারে না post_a
বা post_b
আমরা এখানে কোনও পোস্টের সাথে কাজ করছি dealing আমাদের এটি স্পষ্ট করে বলতে হবে।
এখন Post
মডেল:
class Post < ActiveRecord::Base
has_many :post_connections, :foreign_key => :post_a_id
has_many :posts, :through => :post_connections, :source => :post_b
end
প্রথম has_many
সমিতি, আমরা যোগদানের জন্য মডেল বলতে post_connections
উপর posts.id = post_connections.post_a_id
।
দ্বিতীয় সমিতি, আমরা পাগল বলছেন যে আমরা অন্যান্য পোস্ট পৌঁছতে পারে, এই এক সাথে সংযুক্ত বেশী, আমাদের প্রথম সমিতি মাধ্যমে post_connections
, দ্বারা অনুসরণ post_b
সমিতি PostConnection
।
এখানে আরও একটি জিনিস নেই, এবং তা হ'ল আমাদের রেলগুলিকে জানাতে হবে যে এটি যে PostConnection
পোস্টের উপর নির্ভরশীল। এক বা উভয় এর যদি post_a_id
এবং post_b_id
ছিল NULL
, তাহলে সেই সংযোগ আমাদের অনেক বলতাম না, এটা কি? আমাদের Post
মডেলটিতে আমরা এটি কীভাবে করব তা এখানে :
class Post < ActiveRecord::Base
has_many(:post_connections, :foreign_key => :post_a_id, :dependent => :destroy)
has_many(:reverse_post_connections, :class_name => :PostConnection,
:foreign_key => :post_b_id, :dependent => :destroy)
has_many :posts, :through => :post_connections, :source => :post_b
end
বাক্য গঠনতে সামান্য পরিবর্তন ছাড়াও দুটি বাস্তব জিনিস এখানে আলাদা different
has_many :post_connections
একটি অতিরিক্ত আছে :dependent
প্যারামিটার। মান সহ :destroy
, আমরা রেলগুলিকে বলি যে, একবার এই পোস্টটি অদৃশ্য হয়ে গেলে, এটি এগিয়ে যেতে পারে এবং এই জিনিসগুলি ধ্বংস করতে পারে। আপনি যে বিকল্প মানটি এখানে ব্যবহার করতে পারেন তা হ'ল :delete_all
এটি দ্রুত, তবে যদি আপনি সেগুলি ব্যবহার করেন তবে কোনও ধ্বংসকারী হুককে কল করবেন না।has_many
জন্য আমরা একটি সমিতিও যুক্ত করেছি , যেগুলি আমাদের মাধ্যমে সংযুক্ত হয়েছে post_b_id
। এইভাবে, রেলগুলি সেগুলিকে খুব সুন্দরভাবে ধ্বংস করতে পারে। নোট করুন যে আমাদের :class_name
এখানে উল্লেখ করতে হবে , কারণ মডেলের শ্রেণীর নামটি আর থেকে অনুমান করা যায় না :reverse_post_connections
।এটি জায়গায় রেখে, আমি আপনার মাধ্যমে আরেকটি আইআরবি সেশন আনি script/console
:
>> a = Post.create :name => 'Eels are delicious!'
=> #<Post id: 16, name: "Eels are delicious!">
>> b = Post.create :name => 'You insensitive cloth!'
=> #<Post id: 17, name: "You insensitive cloth!">
>> b.posts = [a]
=> [#<Post id: 16, name: "Eels are delicious!">]
>> b.post_connections
=> [#<PostConnection id: 3, post_a_id: 17, post_b_id: 16, category: nil>]
>> connection = b.post_connections[0]
=> #<PostConnection id: 3, post_a_id: 17, post_b_id: 16, category: nil>
>> connection.category = "scolding"
=> "scolding"
>> connection.save!
=> true
সমিতি তৈরি করার পরে এবং বিভাগটি আলাদাভাবে সেট করার পরিবর্তে, আপনি কেবল একটি পোস্ট সংযোগ তৈরি করতে পারেন এবং এটি দিয়ে সম্পন্ন করতে পারেন:
>> b.posts = []
=> []
>> PostConnection.create(
?> :post_a => b, :post_b => a,
?> :category => "scolding"
>> )
=> #<PostConnection id: 5, post_a_id: 17, post_b_id: 16, category: "scolding">
>> b.posts(true) # 'true' means force a reload
=> [#<Post id: 16, name: "Eels are delicious!">]
এবং আমরা নিপূণভাবে করতে post_connections
এবং reverse_post_connections
সমিতির; এটি সংঘে ঝরঝরে প্রতিফলিত হবে posts
:
>> a.reverse_post_connections
=> #<PostConnection id: 5, post_a_id: 17, post_b_id: 16, category: "scolding">
>> a.reverse_post_connections = []
=> []
>> b.posts(true) # 'true' means force a reload
=> []
সাধারণ has_and_belongs_to_many
অ্যাসোসিয়েশনে, সমিতি জড়িত উভয় মডেলের সংজ্ঞা দেওয়া হয় । এবং সমিতি দ্বি-দিকনির্দেশক।
তবে এক্ষেত্রে কেবলমাত্র একটি পোস্ট মডেল রয়েছে। এবং সমিতি কেবল একবার নির্দিষ্ট করা হয়। ঠিক এই কারণেই এই নির্দিষ্ট ক্ষেত্রে, সমিতিগুলি এক-দিকনির্দেশক।
বিকল্প পদ্ধতির সাথে has_many
এবং যোগ টেবিলের জন্য একটি মডেলের ক্ষেত্রেও এটি একই।
আইআরবি থেকে সহজেই অ্যাসোসিয়েশনগুলি অ্যাক্সেস করার সময় এবং এসএকিউএল-এর দিকে তাকানো যখন লগ ফাইলে রেলগুলি উৎপন্ন করে এটি সর্বাধিক দেখা যায়। আপনি নিম্নলিখিত মত কিছু পাবেন:
SELECT * FROM "posts"
INNER JOIN "post_connections" ON "posts".id = "post_connections".post_b_id
WHERE ("post_connections".post_a_id = 1 )
অ্যাসোসিয়েশনটিকে দ্বি-দিকনির্দেশক করে তোলার জন্য, আমাদের OR
উপরের শর্তাদি post_a_id
এবং post_b_id
বিপরীতগুলি রেলগুলি তৈরি করার জন্য আমাদের একটি উপায় খুঁজে বের করতে হবে, সুতরাং এটি উভয় দিকেই দেখবে।
দুর্ভাগ্যক্রমে, আমি জানি যে এটি করার একমাত্র উপায় বরং হ্যাকি। আপনি নিজে আপনার এসকিউএল বিকল্পগুলি ব্যবহার করে উল্লেখ করতে হবে has_and_belongs_to_many
যেমন :finder_sql
, :delete_sql
ইত্যাদি এটি বেশ নয়। (আমি এখানে পরামর্শের জন্য উন্মুক্ত। কেউ?)
শিটিফের দ্বারা উত্থাপিত প্রশ্নের উত্তর দিতে:
ব্যবহারকারীদের মধ্যে অনুসরণকারী-অনুসরণকারী সম্পর্ক দ্বি-দিকনির্দেশক লুপযুক্ত সংঘের একটি ভাল উদাহরণ। একজন ব্যবহারকারীর অনেকগুলি থাকতে পারে:
এখানে ব্যবহারকারীর জন্য কোডটি কীভাবে দেখাবে:
class User < ActiveRecord::Base
# follower_follows "names" the Follow join table for accessing through the follower association
has_many :follower_follows, foreign_key: :followee_id, class_name: "Follow"
# source: :follower matches with the belong_to :follower identification in the Follow model
has_many :followers, through: :follower_follows, source: :follower
# followee_follows "names" the Follow join table for accessing through the followee association
has_many :followee_follows, foreign_key: :follower_id, class_name: "Follow"
# source: :followee matches with the belong_to :followee identification in the Follow model
has_many :followees, through: :followee_follows, source: :followee
end
ফলোয়ার.আরবি এর জন্য কোডটি এখানে রয়েছে :
class Follow < ActiveRecord::Base
belongs_to :follower, foreign_key: "follower_id", class_name: "User"
belongs_to :followee, foreign_key: "followee_id", class_name: "User"
end
সর্বাধিক গুরুত্বপূর্ণ বিষয়গুলি লক্ষণীয় হ'ল সম্ভবত শর্তাদি :follower_follows
এবং :followee_follows
ইউজারআরবি। মিলের একটি রান (অ-লুপযুক্ত) সমিতি ব্যবহারের উদাহরণ হিসাবে, একটি দলে অনেকগুলি থাকতে পারে: এর players
মাধ্যমে :contracts
। এই জন্য কোন আলাদা প্লেয়ার , যারা অনেক থাকতে পারে :teams
মাধ্যমে :contracts
পাশাপাশি (যেমন কোর্সের উপর প্লেয়ার এর কর্মজীবন)। তবে এই ক্ষেত্রে, যেখানে কেবলমাত্র একটি নামযুক্ত মডেল উপস্থিত রয়েছে (অর্থাত্ একটি ব্যবহারকারী ), নামকরণের মাধ্যমে: সম্পর্কের through: :follow
মতো করে (যেমন পোস্টগুলিতে উদাহরণস্বরূপ, বা যেমন লাইকটি সম্পন্ন করা হয়েছিল through: :post_connections
) এর বিভিন্ন ব্যবহারের ক্ষেত্রে নামকরণের সংঘর্ষ ঘটবে ( বা এতে প্রবেশের টেবিলগুলিতে প্রবেশ করুন)। :follower_follows
এবং:followee_follows
এই জাতীয় নামকরণের সংঘাত এড়াতে তৈরি করা হয়েছিল। এখন, একটি ব্যবহারকারী অনেক থাকতে পারে :followers
মাধ্যমে :follower_follows
এবং অনেক :followees
মাধ্যমে :followee_follows
।
কোনও ব্যবহারকারীর নির্ধারিত : অনুসরণকারীরা ( @user.followees
ডাটাবেসে কল দেওয়ার পরে) ক্লাসের নামগুলি প্রতিটি ক্ষেত্রে দেখতে পাবেন: "অনুসরণ করুন" যেখানে এই জাতীয় ব্যবহারকারী অনুসরণকারী (যেমন foreign_key: :follower_id
) এর মাধ্যমে: এই জাতীয় ব্যবহারকারীর : অনুসরণকারী_পাঠগুলি। কোনও ব্যবহারকারীর নির্ধারক : অনুসারীরা ( @user.followers
ডাটাবেসে একটি কল করার পরে), এখনই শ্রেণি_নামের প্রতিটি উদাহরণটি দেখতে পাবেন: "অনুসরণ করুন" যেখানে এই জাতীয় ব্যবহারকারীর অনুসরণকারী (যেমন foreign_key: :followee_id
) এর মাধ্যমে: এই জাতীয় ব্যবহারকারীর : অনুসরণকারী_পথগুলি।
কেউ যদি এখানে রেলগুলিতে কীভাবে বন্ধুত্বের সম্পর্ক তৈরি করতে হয় তা জানার চেষ্টা করতে এসেছিলেন, তবে আমি তাদের শেষ পর্যন্ত কী ব্যবহার করার সিদ্ধান্ত নিয়েছিলাম তা সম্পর্কে উল্লেখ করব, যা 'সম্প্রদায় ইঞ্জিন' কী করেছে তা অনুলিপি করে।
আপনি উল্লেখ করতে পারেন:
https://github.com/bborn/communityengine/blob/master/app/models/friendship.rb
এবং
https://github.com/bborn/communityengine/blob/master/app/models/user.rb
আরও তথ্যের জন্য.
টি এল; ডিআর
# user.rb
has_many :friendships, :foreign_key => "user_id", :dependent => :destroy
has_many :occurances_as_friend, :class_name => "Friendship", :foreign_key => "friend_id", :dependent => :destroy
..
# friendship.rb
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
@ স্টাফান কোচেন দ্বারা অনুপ্রাণিত, এটি দ্বি-দিকনির্দেশক সমিতিগুলির জন্য কাজ করতে পারে
class Post < ActiveRecord::Base
has_and_belongs_to_many(:posts,
:join_table => "post_connections",
:foreign_key => "post_a_id",
:association_foreign_key => "post_b_id")
has_and_belongs_to_many(:reversed_posts,
:class_name => Post,
:join_table => "post_connections",
:foreign_key => "post_b_id",
:association_foreign_key => "post_a_id")
end
তাহলে post.posts
&& post.reversed_posts
উভয়েরই কাজ করা উচিত, কমপক্ষে আমার পক্ষে কাজ করা উচিত।
দ্বি-দিকনির্দেশের জন্য belongs_to_and_has_many
, ইতিমধ্যে পোস্ট করা দুর্দান্ত উত্তরটি দেখুন এবং তারপরে একটি আলাদা নামের সাথে অন্য একটি সমিতি তৈরি করুন, বিদেশী কীগুলি বিপরীত হয়েছে এবং আপনি class_name
সঠিক মডেলের দিকে ফিরে এসেছেন কিনা তা নিশ্চিত করুন । চিয়ার্স।
কারও কাছে কাজের দুর্দান্ত উত্তর পেতে সমস্যা থাকলে যেমন:
(অবজেক্ট # ইনস্পেক্ট সমর্থন করে না)
=>
অথবা
NoMethodError: অপরিবর্তিত পদ্ধতি `বিভক্ত 'এর জন্য: মিশন: প্রতীক
তারপরে সমাধানটি হ'ল প্রতিস্থাপন :PostConnection
করা উচিত "PostConnection"
, অবশ্যই আপনার ক্লাসের নামটি।
:foreign_key
উপরhas_many :through
প্রয়োজন নেই, এবং আমি কিভাবে খুব কুশলী ব্যবহার করার জন্য একটি ব্যাখ্যা যোগ:dependent
জন্য প্যারামিটারhas_many
।