Saya telah melakukan beberapa bacaan tentang cara memperluas ActiveRecord: Kelas dasar sehingga model saya akan memiliki beberapa metode khusus. Apa cara mudah untuk memperpanjangnya (tutorial langkah demi langkah)?
Saya telah melakukan beberapa bacaan tentang cara memperluas ActiveRecord: Kelas dasar sehingga model saya akan memiliki beberapa metode khusus. Apa cara mudah untuk memperpanjangnya (tutorial langkah demi langkah)?
Jawaban:
Ada beberapa pendekatan:
Baca dokumentasi ActiveSupport :: Concern untuk lebih jelasnya.
Buat file yang disebut active_record_extension.rb
di lib
direktori.
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)
Buat file di config/initializers
direktori bernama extensions.rb
dan tambahkan baris berikut ke file:
require "active_record_extension"
Lihat jawaban Toby .
Buat file di config/initializers
direktori yang disebut 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
Kutipan terkenal tentang ekspresi Reguler oleh Jamie Zawinski dapat bertujuan kembali untuk mengilustrasikan masalah yang terkait dengan patch-monyet.
Beberapa orang, ketika dihadapkan dengan masalah, berpikir "Saya tahu, saya akan menggunakan tambalan monyet." Sekarang mereka memiliki dua masalah.
Penambalan monyet mudah dan cepat. Tetapi, waktu dan upaya yang dihemat selalu diambil kembali di masa depan; dengan bunga majemuk. Hari ini saya membatasi patch monyet untuk dengan cepat membuat prototipe solusi di konsol rel.
require
file di akhir environment.rb
. Saya telah menambahkan langkah ekstra ini untuk jawaban saya.
ImprovedActiveRecord
dan mewarisinya, saat Anda menggunakan module
, Anda memperbarui definisi kelas yang dimaksud. Saya dulu menggunakan warisan (karena pengalaman Java / C ++ bertahun-tahun). Saat ini saya lebih banyak menggunakan modul.
Refinements
yang mengatasi sebagian besar masalah dengan patch monyet ( yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice ). Terkadang ada fitur yang hanya memaksa Anda untuk menggoda nasib. Dan terkadang Anda melakukannya.
Anda bisa memperpanjang kelas dan cukup menggunakan warisan.
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
abstract_models
. Di mana saya harus meletakkannya?
self.abstract_class = true
ke AbstractModel
. Rails sekarang akan mengenali model tersebut sebagai model abstrak.
AbstractModel
di database. Siapa yang tahu penyetel sederhana akan membantu saya KERING! (Saya mulai merasa ngeri ... itu buruk). Terima kasih Toby dan Harish!
Anda juga dapat menggunakan ActiveSupport::Concern
dan menjadi lebih idiom inti Rails seperti:
module MyExtension
extend ActiveSupport::Concern
def foo
end
module ClassMethods
def bar
end
end
end
ActiveRecord::Base.send(:include, MyExtension)
[Sunting] mengikuti komentar dari @daniel
Maka semua model Anda akan foo
memasukkan metode sebagai metode instance dan metode yang ClassMethods
dimasukkan sebagai metode kelas. Misalnya pada FooBar < ActiveRecord::Base
Anda akan memiliki: FooBar.bar
danFooBar#foo
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
InstanceMethods
sudah usang sejak Rails 3.2, cukup masukkan metode Anda ke dalam modul body.
ActiveRecord::Base.send(:include, MyExtension)
inisialisasi dan kemudian ini bekerja untuk saya. Rails 4.1.9
Dengan Rails 4, konsep menggunakan kekhawatiran untuk memodulasi dan KERING model Anda telah menjadi sorotan.
Kekhawatiran pada dasarnya memungkinkan Anda untuk mengelompokkan kode yang serupa dari suatu model atau melintasi beberapa model dalam satu modul dan kemudian menggunakan modul ini dalam model. Berikut ini sebuah contoh:
Pertimbangkan model Artikel, model Acara dan Model Komentar. Artikel atau acara memiliki banyak komentar. Komentar adalah milik artikel atau acara.
Secara tradisional, modelnya mungkin terlihat seperti ini:
Model komentar:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Model artikel:
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
Model Peristiwa
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
Seperti yang dapat kita perhatikan, ada potongan kode penting yang umum untuk Peristiwa dan Model Artikel. Dengan menggunakan kekhawatiran, kami dapat mengekstrak kode umum ini dalam modul yang terpisah, Commentable.
Untuk ini, buat file commentable.rb di app / model / concern.
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
Dan sekarang model Anda terlihat seperti ini:
Model komentar:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Model artikel:
class Article < ActiveRecord::Base
include Commentable
end
Model Peristiwa
class Event < ActiveRecord::Base
include Commentable
end
Satu hal yang saya ingin soroti saat menggunakan Kekhawatiran adalah bahwa Kekhawatiran harus digunakan untuk pengelompokan 'berbasis domain' daripada pengelompokan 'teknis'. Misalnya, pengelompokan domain seperti 'Commentable', 'Taggable' dll. Pengelompokan berbasis teknis akan seperti 'FinderMethods', 'ValidationMethods'.
Berikut ini tautan ke pos yang menurut saya sangat berguna untuk memahami masalah dalam Model.
Semoga Langgan membantu :)
Langkah 1
module FooExtension
def foo
puts "bar :)"
end
end
ActiveRecord::Base.send :include, FooExtension
Langkah 2
# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'
Langkah 3
There is no step 3 :)
Rails 5 menyediakan mekanisme bawaan untuk memperpanjang ActiveRecord::Base
.
Ini dicapai dengan memberikan lapisan tambahan:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# put your extensions here
end
dan semua model mewarisi dari yang itu:
class Post < ApplicationRecord
end
Lihat misalnya blogpost ini .
Hanya untuk menambah topik ini, saya menghabiskan waktu mencari cara untuk menguji ekstensi tersebut (saya pergi jalan ActiveSupport::Concern
.)
Inilah cara saya menyiapkan model untuk menguji ekstensi saya.
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
Dengan Rails 5, semua model diwarisi dari ApplicationRecord & ini memberikan cara yang bagus untuk memasukkan atau memperluas perpustakaan ekstensi lainnya.
# 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
Misalkan modul metode khusus harus tersedia di semua model, sertakan dalam file application_record.rb. Jika kami ingin menerapkan ini untuk serangkaian model tertentu, maka sertakan dalam kelas model masing-masing.
# 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
Jika Anda ingin agar metode yang didefinisikan dalam modul sebagai metode kelas, perluas modul ke ApplicationRecord.
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend SpecialMethods
end
Semoga ini bisa membantu orang lain!
saya sudah
ActiveRecord::Base.extend Foo::Bar
dalam penginisialisasi
Untuk modul seperti di bawah ini
module Foo
module Bar
end
end