Ruby on Rails'te bir ayarlayıcı yöntemini geçersiz kılmanın doğru yolu nedir?


184

Ruby on Rails 3.2.2 kullanıyorum ve aşağıdaki benim sınıf özniteliği için bir ayarlayıcı yöntemi geçersiz kılmak için "uygun" / "doğru" / "emin" bir yol olup olmadığını bilmek istiyorum.

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self[:attribute_name] = value
end

Yukarıdaki kod beklendiği gibi çalışıyor. Ancak, yukarıdaki kodu kullanarak, gelecekte sorunları olacak mı yoksa en azından hangi sorunları "beklemeliyim" Ruby on Rails ile "/" olabilir "bilmek istiyorum . Bir ayarlayıcı yöntemini geçersiz kılmanın doğru yolu bu değilse, doğru yol nedir?


Not : Kodu kullanırsam

attr_accessible :attribute_name

def attribute_name=(value)
  ... # Some custom operation.

  self.attribute_name = value
end

Aşağıdaki hatayı alıyorum:

SystemStackError (stack level too deep):
  actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70

4
'' Uygun '/' doğru '/' emin '' uygulanan terminolojiyi seviyorum. 3 yol verdiğinizde, yanlış yorumlama yapılmamasını sağlar. Aferin!
Jay

5
@Jay - "İncelik İtalyanlığı"; -)
Backo

2
Açıkça söylemek gerekirse, "yığın seviyesi çok derin", özyinelemeli bir çağrının ... kendi çağrısının olduğu gerçeğinden bahsediyor.
Nippysaurus

Yanıtlar:


295

================================================== ========================= Güncelleme: 19 Temmuz 2017

Şimdi Rails belgeleri de şu şekilde kullanılmasını öneriyor super:

class Model < ActiveRecord::Base

  def attribute_name=(value)
    # custom actions
    ###
    super(value)
  end

end

================================================== =========================

Orijinal Yanıt

Modellere erişirken bir tablonun sütunları için ayarlayıcı yöntemlerini geçersiz kılmak istiyorsanız, bunu yapmanın yolu budur.

class Model < ActiveRecord::Base
  attr_accessible :attribute_name

  def attribute_name=(value)
    # custom actions
    ###
    write_attribute(:attribute_name, value)
    # this is same as self[:attribute_name] = value
  end

end

Rails belgelerindeki Varsayılan erişimcileri geçersiz kılma konusuna bakın .

Dolayısıyla, ilk yönteminiz Ruby on Rails Modelleri'ndeki sütun ayarlayıcılarını geçersiz kılmanın doğru yoludur. Bu erişimciler, tablonun sütunlarına modelin nitelikleri olarak erişmek için Rails tarafından zaten sağlanmıştır. Buna ActiveRecord ORM eşlemesi diyoruz.

Ayrıca attr_accessible, modelin üst kısmındaki erişimcilerle hiçbir ilgisi olmadığını unutmayın. Tamamen farklı bir işlevselliğe sahiptir ( bu soruya bakın )

Ancak saf Ruby'de, bir sınıf için erişimciler tanımladıysanız ve ayarlayıcıyı geçersiz kılmak istiyorsanız, aşağıdaki gibi örnek değişkenini kullanmanız gerekir:

class Person
  attr_accessor :name
end

class NewPerson < Person
  def name=(value)
    # do something
    @name = value
  end
end

Ne yaptığını anladıktan sonra bunu anlamak daha kolay olacaktır attr_accessor. Kod attr_accessor :namebu iki yönteme eşdeğerdir (alıcı ve ayarlayıcı)

def name # getter
  @name
end

def name=(value) #  setter
  @name = value
end

Ayrıca, ikinci yöntemin başarısız olması, çünkü bu yöntemin attribute_name=içinde aynı yöntemi çağırdığınızda sonsuz bir döngüye neden olacaktır .


9
Rails 4 için attr_accessibleartık orada olmadığı için atlayın ve çalışmalı
zigomir

11
Neden aramıyorsunuz super?
Nathan Lilienthal

1
Erişimciler ve yazarlar dinamik olarak yaratıldığı superiçin işe yaramayabileceği izlenimindeydim . Ama öyle değil gibi görünüyor. Sadece kontrol ettim ve benim için çalışıyor. Ayrıca, bu soru aynı sormak
rubyprince

4
İle büyük bir yakaladım write_attribute. Dönüşümler atlanacak. Unutmayın write_attributehemen hemen her zaman istenmeyen edilecek tarihleri ile saat dilimi dönüşümleri atlayacak.
Tim Scott

2
süper de işe yarayacak, ancak bize istemeyebileceğiniz bazı nedenler var. Örneğin mongoid taşında, getter yöntemini süper yaparsanız diziye itemeyeceğiniz bir hata vardır. Bu nedenle, bellekte diziyi yönetmenin bir yolu var. Ayrıca @name, üzerine yazdığınız yöntemi çağırmak yerine ayarlanan değeri döndürür. Ancak yukarıdaki çözümde her ikisi de gayet iyi çalışacaktır.
newdark-it

44

superAnahtar kelimeyi kullanın :

def attribute_name=(value)
  super(value.some_custom_encode)
end

Tersine, okuyucuyu geçersiz kılmak için:

def attribute_name
  super.some_custom_decode
end

1
Yöntem çağrısını aynı adla sınırlı tuttuğu için kabul edilen IMO'dan daha iyi yanıt. Bu
Andrew Schwartz

Getter yönteminin geçersiz kılınması , bu değişiklik nedeniyle Rails 4.2'de tehlikeli hale geldi: github.com/rails/rails/commit/… Daha önce form yardımcıları, alanın unypecast değerini çağırır ve özel alıcıyı çağırmaz. Şimdi yönteminizi çağırıyorlar ve böylece değeri nasıl geçersiz kıldığınıza bağlı olarak formlarınızda kafa karıştırıcı sonuçlar üretecekler.
Brendon Muir

16

Raylarda 4

Eğer var diyelim yaş Tablonuzdaki niteliği

def age=(dob)   
    now = Time.now.utc.to_date
    age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
    super(age) #must add this otherwise you need to add this thing and place the value which you want to save. 
  end

Not: Ray 4'teki yeni gelenler için modelde attr_accessible belirtmeniz gerekmez . Bunun yerine, permit yöntemini kullanarak özniteliklerinizi denetleyici düzeyinde beyaz listeye almanız gerekir .


3

(En azından ActiveRecord ilişki koleksiyonları için) aşağıdaki desen çalışır bulduk:

has_many :specialties

def specialty_ids=(values)
  super values.uniq.first(3)
end

(Bu, geçirilen dizideki yinelenmeyen ilk 3 girdiyi alır.)


0

attr_writerAttr_writer ayarlayıcısının üzerine yazmak için kullanma : attribute_name

  def attribute_name=(value)
    # manipulate value
    # then send result to the default setter
    super(result)
  end
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.