Rails Extended ActiveRecord:: Base
Czytałem trochę o tym, jak rozszerzyć ActiveRecord: Base class, aby moje modele miały jakieś specjalne metody. Jaki jest łatwy sposób na jego rozszerzenie (samouczek krok po kroku)?
9 answers
Istnieje kilka podejść:
Używanie Activesupport:: Concern (Preferowane)
Więcej informacji można znaleźć w dokumentacji ActiveSupport::Concern.Utwórz plik o nazwie active_record_extension.rb
w katalogu lib
.
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)
Utwórz plik w katalogu config/initializers
o nazwie extensions.rb
i dodaj do pliku następujący wiersz:
require "active_record_extension"
Dziedziczenie (Preferowane)
Monkey patching (powinno być unika)
Utwórz plik w katalogu config/initializers
o nazwie 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
Słynny cytat o wyrażeniach regularnych autorstwa Jamie Zawinski może zostać ponownie wykorzystany, aby zilustrować problemy związane z łataniem małp.
Łatanie małp jest łatwe i szybkie. Ale zaoszczędzony czas i wysiłek jest zawsze odzyskiwany kiedyś w przyszłości; z odsetkami złożonymi. W dzisiejszych czasach ograniczam łatanie małp do szybkiego prototypowania rozwiązania w konsoli rails.Niektórzy ludzie, w obliczu problemu, myślą: "wiem, użyję łatanie małp."Teraz mają dwa problemy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-27 00:35:22
Możesz po prostu rozszerzyć klasę i po prostu użyć dziedziczenia.
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-25 21:33:59
Możesz również użyć ActiveSupport::Concern
i być bardziej idiomatycznym rdzeniem Rails, takim jak:
module MyExtension
extend ActiveSupport::Concern
def foo
end
module ClassMethods
def bar
end
end
end
ActiveRecord::Base.send(:include, MyExtension)
[Edytuj] po komentarzu @ daniel
Wtedy wszystkie twoje modele będą miały metodę foo
dołączoną jako metoda instancji, a metody w ClassMethods
jako metody klasowe. Np. na FooBar < ActiveRecord::Base
będziesz miał: FooBar.bar
i FooBar#foo
Http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-09 10:27:56
W Rails 4, koncepcja wykorzystania problemów do modularyzacji i wysuszania modeli była w najciekawszych aspektach.
Obawy zasadniczo pozwalają grupować podobny kod modelu lub wielu modeli w jednym module, a następnie używać tego modułu w modelach. Oto przykład:
Rozważ Model artykułu, Model zdarzenia i model komentarza. Artykuł lub wydarzenie ma wiele komentarzy. Komentarz należy do artykułu lub wydarzenia.
Tradycyjnie modele mogą wyglądać to:
Skomentuj Model:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Model Artykułu:
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 Zdarzenia
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
Jak możemy zauważyć, istnieje znacząca część kodu wspólna zarówno dla modelu Event, jak i Article. Wykorzystując obawy możemy wyodrębnić ten wspólny kod w osobnym module Komentowalnym.
Do tego utwórz komentarz.plik rb w aplikacji / model/dotyczy.
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
A teraz twoje modele wyglądają tak:
Skomentuj Model:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Artykuł Model:
class Article < ActiveRecord::Base
include Commentable
end
Model Zdarzenia
class Event < ActiveRecord::Base
include Commentable
end
Jedną z kwestii, którą chciałbym podkreślić podczas używania obaw, jest to, że obawy powinny być używane do grupowania "opartego na domenie", a nie "technicznego". na przykład grupowanie domen jest jak 'Komentowalne',' Taggable ' itp. Grupowanie oparte na technice będzie takie jak "FinderMethods", "ValidationMethods".
Oto link do posta , który uważam za bardzo przydatny do zrozumienia problemów w modelach.
Hope the writeup pomaga:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-25 07:48:23
Krok 1
module FooExtension
def foo
puts "bar :)"
end
end
ActiveRecord::Base.send :include, FooExtension
Krok 2
# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'
Krok 3
There is no step 3 :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 14:43:31
Rails 5 zapewnia wbudowany mechanizm rozszerzania ActiveRecord::Base
.
Osiąga się to poprzez dostarczenie dodatkowej warstwy:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# put your extensions here
end
I wszystkie modele dziedziczą z tego:
class Post < ApplicationRecord
end
Zobacz np. Ten blogpost .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-24 16:03:42
Aby dodać do tego tematu, spędziłem trochę czasu pracując nad tym, jak przetestować takie rozszerzenia (poszedłem w dół trasy ActiveSupport::Concern
.)
Oto jak skonfigurowałem model do testowania moich rozszerzeń.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-31 11:22:18
W Rails 5, Wszystkie modele są dziedziczone z ApplicationRecord i daje to dobry sposób na dołączenie lub rozszerzenie innych bibliotek rozszerzeń.
# 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
Załóżmy, że moduł metod specjalnych musi być dostępny we wszystkich modelach, dołącz go do application_record.plik rb. Jeśli chcemy zastosować to dla określonego zestawu modeli, włączamy je do odpowiednich klas modeli.
# 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
Jeśli chcesz mieć metody zdefiniowane w module jako metody klasowe, rozszerz moduł do ApplicationRecord.
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend SpecialMethods
end
Mam nadzieję, że pomoże innym !Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-02 05:24:07
Mam
ActiveRecord::Base.extend Foo::Bar
In an initializer
Dla modułu jak poniżej
module Foo
module Bar
end
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-01 02:03:05