dernekler aracılığıyla aittir


141

Aşağıdaki ilişkilendirmeler göz önüne alındığında, modelden a'nın bağlı Questionolduğunu belirtmem gerekiyor . Bu eylemi gerçekleştirmek için kullanmaya çalışıyorum .ChoiceChoicebelongs_to :question, through: :answer

class User
  has_many :questions
  has_many :choices
end

class Question
  belongs_to :user
  has_many :answers
  has_one :choice, :through => :answer
end

class Answer
  belongs_to :question
end

class Choice
  belongs_to :user
  belongs_to :answer
  belongs_to :question, :through => :answer

  validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
end

alıyorum

NameError başlatılmamış sabit User::Choice

yapmaya çalıştığımda current_user.choices

Eğer işe yaramazsa

belongs_to :question, :through => :answer

Ama bunu kullanmak istiyorum çünkü bunu yapabilmek istiyorum validates_uniqueness_of

Muhtemelen basit bir şeye bakmıyorum. Herhangi bir yardım mutluluk duyacağız.


1
Belki delege için kabul edilen cevabı değiştirmeye değer mi?
23

Yanıtlar:


60

Bir belongs_toilişkilendirmenin :throughseçeneği olamaz . Sen önbelleğe daha iyi olur question_idüzerinde Choiceve tabloya benzersiz bir dizin ekleyerek (özellikle çünkü validates_uniqueness_ofyarış koşullarına eğilimli).

Paranoyaksanız, Choiceyanıtlayıcının question_ideşleştiğini doğrulayan özel bir doğrulama ekleyin , ancak son kullanıcıya hiçbir zaman bu tür bir uyumsuzluk oluşturacak verileri gönderme fırsatı verilmemesi gibi görünmelidir.


Teşekkürler Stephen, gerçekten doğrudan question_id ile ilişkilendirmek istemedim, ama sanırım bu en kolay yol. Benim asıl düşüncem, "cevap" "soru" ya ait olduğu için, "soru" ya ulaşmak için her zaman "cevap" dan geçebilirim. Ama bunu yapmanın kolay olmadığını mı düşünüyorsun, yoksa sadece kötü bir şema olduğunu mu düşünüyorsun?
vinhboy

Benzersiz bir kısıtlama / doğrulama istiyorsanız, kapsam alanlarının aynı tabloda bulunması gerekir. Unutmayın, yarış koşulları var.
stephencelis

1
>> Son kullanıcıya hiçbir zaman bu tür bir uyumsuzluk yaratacak verileri sunma fırsatı verilmemesi gibi geliyor. - Açık bir sunucu tarafı kontrolü yapmazsanız, kullanıcının "bir şey yapma fırsatı olmadığını" asla garanti edemezsiniz.
Konstantin

376

Ayrıca yetki verebilirsiniz:

class Company < ActiveRecord::Base
  has_many :employees
  has_many :dogs, :through => :employees
end

class Employee < ActiveRescord::Base
  belongs_to :company
  has_many :dogs
end

class Dog < ActiveRecord::Base
  belongs_to :employee

  delegate :company, :to => :employee, :allow_nil => true
end

27
+1, bunu yapmanın en temiz yolu. (en azından düşünebileceğim)
Orlando

9
Bu kadar çok sorgu kullanmamak için JOIN ile bunu yapmanın bir yolu var mı?
Tallboy

1
Kendimi tanımak istiyorum. Denediğim her şey 3 seçim yaptı. Bir ilişkilendirmede "-> {katıldı: bir şey}" lambda belirtebilirsiniz. Birleştirme işten çıkartılır, ancak daha sonra yine başka bir seçim yapılır. Bunu ayarlayamadım.
Renra

2
@Tallboy Birincil anahtarlardaki birkaç mükemmel dizinlenmiş seçme sorgusu neredeyse her zaman tek bir JOIN sorgusundan daha iyidir. Birleştirmeler veritabanının çalışmasını sağlar.
Ryan McGeary

1
Allow_nil ne yapar? Çalışanın her zaman bir şirketi olmamalı mı?
aaron-kodlama

115

Sadece kullanmak has_oneyerine belongs_toGözlerinde farklı :through, örneğin:

class Choice
  belongs_to :user
  belongs_to :answer
  has_one :question, :through => :answer
end

İlgisiz, ancak veritabanınızda uygun benzersiz bir kısıtlama kullanmak yerine validates_uniqueness_of kullanmaktan çekinmeyin. Bunu yakutta yaptığınız zaman yarış koşullarınız var.


38
Bu çözüm ile büyük uyarı. Seçimi her kaydettiğinizde autosave: false, ayarlanmadığı sürece her zaman Soruları kaydeder .
Chris Nicola

@ChrisNicola lütfen ne demek istediğini açıklayabilir misin, ne demek istediğini anlamadım.
aks

Ne demek istiyordum? Düzgün benzersiz bir kısıtlama kastediyorsanız, veritabanında benzersiz olması gereken sütun / alana bir BENZERSİZ dizin eklemek demek.
Chris Nicola

4

Benim yaklaşımım veritabanı sütunları eklemek yerine sanal bir öznitelik yapmaktı.

class Choice
  belongs_to :user
  belongs_to :answer

  # ------- Helpers -------
  def question
    answer.question
  end

  # extra sugar
  def question_id
    answer.question_id
  end
end

Bu yaklaşım oldukça basittir, ancak takaslarla birlikte gelir. Rayların db'den yüklenmesini gerektirir answerve sonra question. Bu, daha sonra ihtiyacınız olan dernekleri istekli olarak yükleyerek optimize edilebilir (yani c = Choice.first(include: {answer: :question})), ancak bu optimizasyon gerekirse, stephencelis'in cevabı muhtemelen daha iyi bir performans kararıdır.

Belirli seçimler için bir zaman ve yer var ve bence bu seçim prototip yaparken daha iyi. Seyrek kullanım durumunda olduğunu bilmiyorsam üretim kodu için kullanmazdım.


1

İstediğiniz gibi birçok soru olan bir kullanıcı gibi geliyor.
Sorunun, biri Kullanıcı Seçimi olmak üzere birçok Yanıtı vardır.

Arkanda olan bu mu?

Bu çizgiler boyunca böyle bir şey modelleyebilirim:

class User
  has_many :questions
end

class Question
  belongs_to :user
  has_many   :answers
  has_one    :choice, :class_name => "Answer"

  validates_inclusion_of :choice, :in => lambda { answers }
end

class Answer
  belongs_to :question
end

1

Böylece istediğiniz davranışa sahip olamıyorsunuz ama buna benzer bir şey yapabilirsiniz. Yapabilmek istiyorsunChoice.first.question

geçmişte yaptığım şey böyle bir şey

class Choice
  belongs_to :user
  belongs_to :answer
  validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
  ...
  def question
    answer.question
  end
end

bu şekilde artık Seçim ile ilgili soruları arayabilirsiniz


-1

has_many :choicesAdında bir dernek oluşturur choices, değil choice. current_user.choicesBunun yerine kullanmayı deneyin .

Sihir hakkında bilgi için ActiveRecord :: Dernekler belgelerine bakın has_many.


1
Yardımın için teşekkürler Michael, ancak bu benim açımdan bir yazım hatası. Zaten current_user.choices yapıyorum. Bu hatanın benimle kullanıcı ve soruya ait olmak istediği bir şey var.
vinhboy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.