Soru Radarlar, sadece "yeni" sonra başlatılır


Şu 2 modelim var

class Sport < ActiveRecord::Base
  has_many :charts, order: "sortWeight ASC"
  has_one :product, :as => :productable
  accepts_nested_attributes_for :product, :allow_destroy => true
end

class Product < ActiveRecord::Base
  belongs_to :category
  belongs_to :productable, :polymorphic => true
end

Ürün olmadan bir spor olamaz, benim sports_controller.rb Sahiptim:

def new
  @sport = Sport.new
  @sport.product = Product.new
...
end

Ürünün oluşturulmasını spor modeline taşımaya çalıştım. after_initialize:

after_initialize :create_product

def create_product
 self.product = Product.new
end

Çabucak öğrendim after_initialize Bir model her başlatıldığında çağrılır (örn. find aramak). Yani aradığım davranış bu değildi.

Neyin gerekliliğini modellemenin yolu nedir? sport sahip olmak product?

Teşekkürler


44
2018-03-07 22:42


Menşei




Cevaplar:


Mantığı kontrolöre koymak, belirttiğiniz en iyi cevap olabilir, ancak after_initialize aşağıdakileri yaparak çalışmak için:

after_initialize :add_product

def add_product
  self.product ||= Product.new
end

Bu şekilde, yalnızca ürün yoksa ürün koyar. Kontrolörde mantığa sahip olmaktan daha fazla ve / veya daha az açık olmayabilir.

Düzenle: Ryan'ın yanıtına göre, performans açısından aşağıdakiler daha iyi olacaktır:

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end

59
2018-03-08 05:10



Bu çözümü kullanmamın nedeni, benim durumumda, ürün alanının boş olabileceğidir (bu yüzden gerçekten sadece bir yaratımda sonradan bir post_initialize'e ihtiyacım var). Eğer bir fikri olan bir kişi varsa harika olurdu, teşekkürler! - yorch
@yorch Önce / sonra_create göz atın. Mantığınız çok karmaşıksa, muhtemelen bir önceki / sonraki bir kancada saklamak istemezsiniz büyülü. - bostonou
Bununla birlikte, bu yöntem optimize edilmiş değildir, büyük miktarda spor / ürün seçmeye başladığınızda, ürününüzün mevcut olup olmadığını görmek için seçtiğiniz her ilişki için seçtiğiniz bir ilişki yaptığınız için sorgularınızın çok iyi bir şekilde kullanılmadığını göreceksiniz. - YaBoyQuy
@YaBoyQuy Muhtemelen kullanmalısınız includes Sorgunuzda - Eager Yükleme bölümüne bakın api.rubyonrails.org/classes/ActiveRecord/Associations/... - bostonou
@Eric L, Sorunu ilk okuduğumda, bir Ürünle bir Sport nesnesi oluşturmanın, modele ve ona bağlı iş kurallarına yönelik bir ön koşul oluşturduğunu düşündüm. Gerçekten ise, IMO bu mantık, etki alanı katmanında görünüm / uygulama katmanında bulunmamalıdır (denetleyicileri içerir). Tüm sporların en az bir ürün içermesi gerekiyorsa, önerdiğiniz sınıf yöntemi iyi bir seçenektir. - Rudy Seidinger


elbette after_initialize :add_product, if: :new_record? burada en temiz yoldur.

Add_product işlevinin koşullu dışında kalmasını sağlayın


29
2017-10-09 09:35



Bu muhtemelen gitmek için doğru yoldur. - fatuhoku
yapar after_initialize :add_product, on: :create iş? - Justin Maxwell


Yaparsan self.product ||= Product.new her yaptığınızda hala bir ürün arayacak find çünkü sıfır olup olmadığını kontrol etmek gerekiyor. Sonuç olarak, istekli yüklemeler yapmayacaktır. Bunu yapmak için sadece yeni bir kayıt oluşturulduğunda, ürünü ayarlamadan önce yeni bir kayıt olup olmadığını kontrol edebilirsiniz.

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end

Basit bir kıyaslama ve kontrol yaptım if self.new_record? Performansı kayda değer şekilde etkilemiyor gibi görünmektedir.


27
2018-05-06 05:10



New_record çağırarak performans isabetiyle harika çalışma? ! - conciliator
Ayrıca taşımak mümkün new_record? kontrol etmek add_product yazarak after_initialize :add_product, :if => :new_record?. Bazı durumlarda daha iyi organize edilecek. - Rory O'Kane


Kullanmak yerine after_initializene dersin after_create?

after_create :create_product

def create_product
  self.product = Product.new
  save
end

Sorununuzu çözecek gibi görünüyor mu?


2
2018-03-07 22:58



Bu için new kontrolördeki yöntem .... db'ye henüz hiç bir şey kaydedilmez, after_create çağrılmayacak. - Tyler DeWitt


Çok yakınız gibi görünüyor. After_initialize çağrısıyla birlikte tamamen yapabilmeniz gerekir, ancak önce Sport modelinizin "has_one" ile bir ilişkisine sahip olup olmadığına inanıyorum: Ürününüzün belirttiği gibi, o zaman da Ürün modeliniz de "aid_to" spor yapmalıdır. Bunu Ürün modelinize ekleyin

belongs_to: :sport

Bir sonraki adımda, şimdi bir Spor modelini başlatabilirsiniz.

@sport = @product.sport.create( ... )

Bu bilgilerden yola çıkarak İlişkilendirme Temelleri Ruby on Rails Guides'den, eğer tam olarak doğru olmasaydım okuyabiliyorsunuz


1
2018-03-07 23:15



Polimorfik birliktelik bunu biraz atıyor. Bir ürün, üretilebilir bir kelimeye aittir. Bunun nedeni, bazı ürünlerin spor ve bazı filmlerin (sporla başladığım) olmasıdır. Bu, Rails'de (istemediğim Tekli Tabiat Kalıtımından başka) mirasın nasıl ele alınacağına dair benim anlayışım. Yine de fikir için teşekkürler! - Tyler DeWitt
Ah, görüyorum, modelin polimorfik doğasını fark etmemiştim ve bununla ne yapacağımı bilmiyorum fark ettim. Kendi başıma da bakmaya devam edeceğim. Bir şey bulursam size haber vereceğim. - coderates
Bu railscast Aradığınız cevabı içerdiği görülüyor. Daha önce denediğim gibi yeni sporu yaratmanın benzer bir yolunu kullanmış gibi görünüyorsun. Bu yardımcı olur umarım. - coderates
Evet, cevap mantığı kontrolöre koymak gibi görünüyor. Bazı ppl de IRC kanalında böyle söyledi - Tyler DeWitt


Örneğin, başlatma yöntemini geçersiz kılmalısınız

class Sport < ActiveRecord::Base

  # ...

  def initialize(attributes = {})
    super
    self.build_product
    self.attributes = attributes
  end

  # ...

end

Kayıt veritabanından yüklendiğinde, yöntem başlatılmaz. Ürün oluşturulduktan sonra yukarıdaki koddaki özelliklerin atanmış olduğuna dikkat edin. Bu ayar özniteliğinde, oluşturulan ürün örneğini etkileyebilir.


0
2017-09-13 10:41



Burada ayrıntılı bir dizi nedenden dolayı bunu yapmamalısınız: stackoverflow.com/questions/4376992/... - tirdadc
Hayır, başlatmayı geçersiz kılmamak için bir neden yoktur. Aksine, rayların kaynak koduna bakarsanız, başlatma işleminin geçersiz kılınması gerektiğini anlayacaksınız. Yapmanız gereken tek şey, geçersiz kılınan başlatmanızda süper aramaktır, ancak bu, tüm yakut geliştiricileri tarafından izlenmesi beklenen bir kuraldır ve geliştiriciler sessizce sizi bunu yapmanızı bekler. - Victor Nazarov
Bu karışıklık, gelecekteki sürümlerde kırılma ve bazı üçüncü taraf taşlar için sorunlara neden olabilecek bir şey olarak bunu yapmaktan çekinirim. Resmi olarak tavsiye edilmediği sürece. Genel hack / geçici çözümler için hepim ama yapıcı özellikle kırılgan bir özellik ve after_initialize basit bir alternatif sunuyor. - mahemoff