ActiveRecord: Base sınıfını genişletme hakkında bazı okumalar yaptım, böylece modellerim bazı özel yöntemlere sahip olacaktı. Genişletmenin kolay yolu nedir (adım adım eğitici)?
ActiveRecord: Base sınıfını genişletme hakkında bazı okumalar yaptım, böylece modellerim bazı özel yöntemlere sahip olacaktı. Genişletmenin kolay yolu nedir (adım adım eğitici)?
Yanıtlar:
Birkaç yaklaşım vardır:
Daha fazla bilgi için ActiveSupport :: Endişe belgelerini okuyun .
Adlı bir dosya oluşturun active_record_extension.rb
içinde lib
dizine.
require 'active_support/concern'
module ActiveRecordExtension
extend ActiveSupport::Concern
# add your instance methods here
def foo
"foo"
end
# add your static(class) methods here
class_methods do
#E.g: Order.top_ten
def top_ten
limit(10)
end
end
end
# include the extension
ActiveRecord::Base.send(:include, ActiveRecordExtension)
Adlı config/initializers
dizinde bir dosya oluşturun ve dosyaya extensions.rb
aşağıdaki satırı ekleyin:
require "active_record_extension"
Toby'nin cevabına bakın .
Adlı config/initializers
dizinde bir dosya oluşturun active_record_monkey_patch.rb
.
class ActiveRecord::Base
#instance method, E.g: Order.new.foo
def foo
"foo"
end
#class method, E.g: Order.top_ten
def self.top_ten
limit(10)
end
end
Jamie Zawinski'nin Düzenli ifadeler hakkındaki ünlü alıntısı , maymun yamasıyla ilgili sorunları göstermek için yeniden tasarlanabilir.
Bazı insanlar bir sorunla karşılaştıklarında “Biliyorum, maymun yama kullanacağım” diye düşünüyorlar. Şu an iki problemleri var.
Maymun yama kolay ve hızlıdır. Ancak, kazanılan zaman ve çaba her zaman gelecekte geri alınır; bileşik ilgi ile. Bu günlerde ray yama konsolundaki bir çözümü hızlı bir şekilde prototiplemek için maymun yamalarını sınırlandırıyorum.
require
Sonunda dosyaya ihtiyacınız var environment.rb
. Bu ekstra adımı yanıtıma ekledim.
ImprovedActiveRecord
ve bundan miras almalısınız, kullanırken module
, söz konusu sınıfın tanımını güncellersiniz. Eskiden kalıtım kullandım (yıllarca Java / C ++ deneyiminin nedeni). Bugünlerde çoğunlukla modül kullanıyorum.
Refinements
, maymun yamasıyla ilgili sorunların çoğunu ele alan yeni bir özellik sunuyor ( yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice ). Bazen sizi kaderi cezbetmeye zorlayan bir özellik vardır. Ve bazen yaparsınız.
Sadece sınıfı genişletebilir ve kalıtım kullanabilirsiniz.
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
abstract_models
. Nereye koymalıyım?
self.abstract_class = true
Blogunuza AbstractModel
. Raylar şimdi modeli soyut bir model olarak tanıyacak.
AbstractModel
veritabanında aramaya başladığında vazgeçti . Kim basit bir pasör KURU şeyler bana yardımcı olacağını biliyordu! (Küfretmeye başladım ... kötüydü). Toby ve Harish teşekkürler!
Ayrıca ActiveSupport::Concern
deyim gibi daha fazla Rails çekirdek kullanabilirsiniz ve olabilir:
module MyExtension
extend ActiveSupport::Concern
def foo
end
module ClassMethods
def bar
end
end
end
ActiveRecord::Base.send(:include, MyExtension)
@Daniel yorumundan sonra [Düzenle]
Daha sonra tüm modelleriniz foo
bir örnek yöntemi olarak dahil edilen metoda ve ClassMethods
sınıf yöntemleri olarak dahil edilen metotlara sahip olacaktır. Örneğin bir FooBar < ActiveRecord::Base
sahip olacaksınız: FooBar.bar
veFooBar#foo
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
InstanceMethods
Rails 3.2'den beri kullanımdan kaldırıldığını unutmayın, yöntemlerinizi modül gövdesine koyun.
ActiveRecord::Base.send(:include, MyExtension)
Bir başlatıcı yerleştirdim ve sonra bu benim için çalıştı. Raylar 4.1.9
Rails 4 ile, modellerinizi modüler hale getirmek ve KURUTMAK için endişeleri kullanma kavramı öne çıkmıştır.
Endişeler temel olarak bir modelin benzer kodunu veya tek bir modülde birden çok model arasında gruplandırmanıza ve daha sonra bu modülü modellerde kullanmanıza izin verir. İşte bir örnek:
Bir Makale modeli, bir Olay modeli ve Yorum Modeli düşünün. Bir makalede veya bir etkinlikte çok sayıda yorum var. Bir yorum, makaleye veya etkinliğe aittir.
Geleneksel olarak, modeller şöyle görünebilir:
Yorum Modeli:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Makale Modeli:
class Article < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#return the article with least number of comments
end
end
Etkinlik Modeli
class Event < ActiveRecord::Base
has_many :comments, as: :commentable
def find_first_comment
comments.first(created_at DESC)
end
def self.least_commented
#returns the event with least number of comments
end
end
Fark edebileceğimiz gibi, hem Etkinlik hem de Makale Modeli için önemli bir kod parçası vardır. Endişeleri kullanarak, bu ortak kodu Commentable adlı ayrı bir modülde çıkarabiliriz.
Bunun için uygulama / model / endişelerde commentable.rb dosyası oluşturun.
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
# for the given article/event returns the first comment
def find_first_comment
comments.first(created_at DESC)
end
module ClassMethods
def least_commented
#returns the article/event which has the least number of comments
end
end
end
Ve şimdi modelleriniz şöyle:
Yorum Modeli:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Makale Modeli:
class Article < ActiveRecord::Base
include Commentable
end
Etkinlik Modeli
class Event < ActiveRecord::Base
include Commentable
end
Endişeleri kullanırken vurgulamak istediğim bir nokta, Endişelerin 'teknik' gruplama yerine 'alan adı tabanlı' gruplama için kullanılması gerektiğidir. Örneğin, bir etki alanı gruplaması 'Yorumlanabilir', 'Taggable' vb. Gibidir. Teknik tabanlı bir gruplandırma 'FinderMethods', 'ValidationMethods' gibi olacaktır.
İşte Modellerdeki endişeleri anlamak için çok yararlı bulduğum bir gönderinin bağlantısı .
Umarım yazma yardımcı olur :)
Aşama 1
module FooExtension
def foo
puts "bar :)"
end
end
ActiveRecord::Base.send :include, FooExtension
Adım 2
# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'
Aşama 3
There is no step 3 :)
Raylar 5, genişletmek için yerleşik bir mekanizma sağlar ActiveRecord::Base
.
Bu, ek katman sağlanarak elde edilir:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# put your extensions here
end
ve tüm modeller bundan miras kalır:
class Post < ApplicationRecord
end
Bkz. Örneğin bu blog yazısı .
Sadece bu konuya eklemek için, bu tür uzantıları nasıl test edeceğimizi araştırdım ( ActiveSupport::Concern
rotadan indim .)
Uzantılarımı test etmek için nasıl bir model ayarlayacağım.
describe ModelExtensions do
describe :some_method do
it 'should return the value of foo' do
ActiveRecord::Migration.create_table :test_models do |t|
t.string :foo
end
test_model_class = Class.new(ActiveRecord::Base) do
def self.name
'TestModel'
end
attr_accessible :foo
end
model = test_model_class.new(:foo => 'bar')
model.some_method.should == 'bar'
end
end
end
Rails 5 ile, tüm modeller ApplicationRecord'dan devralınır ve diğer uzantı kitaplıklarını dahil etmek veya genişletmek için güzel bir yol sağlar.
# app/models/concerns/special_methods.rb
module SpecialMethods
extend ActiveSupport::Concern
scope :this_month, -> {
where("date_trunc('month',created_at) = date_trunc('month',now())")
}
def foo
# Code
end
end
Özel yöntemler modülünün tüm modellerde bulunması gerektiğini varsayalım, application_record.rb dosyasına ekleyin. Bunu belirli bir model seti için uygulamak istiyorsak, ilgili model sınıflarına dahil edin.
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include SpecialMethods
end
# app/models/user.rb
class User < ApplicationRecord
include SpecialMethods
# Code
end
Modülde yöntemlerin sınıf yöntemi olarak tanımlanmasını istiyorsanız, modülü ApplicationRecord'a genişletin.
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend SpecialMethods
end
Umarım başkalarına yardım eder!
Sahibim
ActiveRecord::Base.extend Foo::Bar
bir başlatıcıda
Aşağıdaki gibi bir modül için
module Foo
module Bar
end
end