كيفية تجنب تكرار في has_many :من خلال العلاقة ؟
-
11-07-2019 - |
سؤال
كيف يمكنني تحقيق ما يلي ؟ لدي اثنين من نماذج (بلوق القراء) و الانضمام إلى الجدول من شأنها أن تسمح لي أن N:M العلاقة بينهما:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :blogs, :through => :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
ما أريد أن أفعله الآن هو إضافة القراء على مدونات مختلفة.الشرط ، على الرغم من أن أنا يمكن فقط إضافة القارئ إلى بلوق مرة واحدة.لذا يجب أن لا يكون أي التكرارات (نفس readerID
, نفس blogID
) في BlogsReaders
الجدول.كيف يمكنني تحقيق ذلك ؟
السؤال الثاني هو كيف يمكنني الحصول على قائمة من بلوق أن القراء ليس اشتركت بالفعل (على سبيل المثاللملء القائمة المنسدلة اختر القائمة ، والتي يمكن استخدامها لإضافة قارئ إلى آخر بلوق)?
المحلول
وماذا عن:
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blog_ids])
والقضبان يعتني بجمع هويات بالنسبة لنا مع الطرق الرابطة! :)
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ ClassMethods.html
نصائح أخرى
أبسط حل هو في صلب القضبان:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers, :uniq => true
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :blogs, :through => :blogs_readers, :uniq => true
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
ملاحظة إضافة :uniq => true
الخيار has_many
المكالمة.
كما قد ترغب في النظر في has_and_belongs_to_many
بين بلوق قارئ, إلا إذا كان لديك بعض السمات الأخرى التي ترغب في الانضمام إلى نموذج (التي لا حاليا).هذا الأسلوب أيضا :uniq
opiton.
لاحظ أن هذا لا يمنعك من إنشاء الإدخالات في الجدول, ولكنها لا تضمن عند الاستعلام جمع يمكنك الحصول على واحد فقط من كل كائن.
التحديث
في القضبان 4 طريقة للقيام بذلك هو عن طريق نطاق الكتلة.تغييرات أعلاه.
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { uniq }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { uniq }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
تحديث القضبان 5
استخدام uniq
في نطاق كتلة سوف يسبب خطأ NoMethodError: undefined method 'extensions' for []:Array
.استخدام distinct
بدلا من ذلك :
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { distinct }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
وهذا ينبغي أن تأخذ الرعاية من سؤالك الأول:
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
validates_uniqueness_of :reader_id, :scope => :blog_id
end
القضبان 5.1 الطريقة
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
class Reader < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :blogs, -> { distinct }, through: :blogs_readers
end
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
end
والجواب على هذا الرابط يوضح كيفية تجاوز "<<" طريقة لتحقيق ما كنت تبحث عن دون رفع استثناءات أو إنشاء طريقة منفصل: <لأ href = "https://stackoverflow.com/questions/1315109 / القضبان-لغة إلى تجنب التكرار في ولديها كثير من خلال "> القضبان لغة لتجنب التكرار في has_many: من خلال
وأنا أفكر شخص ما سوف يأتي جنبا إلى جنب مع إجابة أفضل من هذا.
the_reader = Reader.find(:first, :include => :blogs)
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blogs.map(&:id)])
[عدل]
ويرجى الاطلاع على الإجابة جوش أدناه. انها وسيلة للذهاب. (كنت أعرف أن هناك طريقة أفضل من هناك؛)
ويقول الجواب العليا حاليا لاستخدام uniq
في بروك:
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { uniq }, through: :blogs_readers
end
ولكن هذا جزاء العلاقة في صفيف ويمكن كسر الأشياء التي تتوقع لتنفيذ عمليات على علاقة، وليس صفيف.
إذا كنت تستخدم distinct
وتبقي على كعلاقة:
class Blog < ActiveRecord::Base
has_many :blogs_readers, dependent: :destroy
has_many :readers, -> { distinct }, through: :blogs_readers
end
وأسهل طريقة هي تسلسل العلاقة في صفيف:
class Blog < ActiveRecord::Base
has_many :blogs_readers, :dependent => :destroy
has_many :readers, :through => :blogs_readers
serialize :reader_ids, Array
end
وبعد ذلك عند تعيين قيم للقراء، كنت تطبيقها ك
blog.reader_ids = [1,2,3,4]
عند تعيين العلاقات بهذه الطريقة، يتم إزالة التكرارات تلقائيا.