Bry*_*cke 24 ruby ruby-on-rails mixins
我有两个包含相同方法的模型:
def foo
# do something
end
Run Code Online (Sandbox Code Playgroud)
我应该把它放在哪里?
我知道常用代码在Rails应用程序的lib目录中.
但是如果我把它放在一个lib名为' Foo' 的新类中,并且我需要将它的功能添加到我的两个中ActiveRecord models,我是这样做的:
class A < ActiveRecord::Base
includes Foo
class B < ActiveRecord::Base
includes Foo
Run Code Online (Sandbox Code Playgroud)
然后这两个A和B将包含foo就像我在每个定义的方法就可以了?
Phi*_*oss 37
创建一个模块,您可以将其放在lib目录中:
module Foo
def foo
# do something
end
end
Run Code Online (Sandbox Code Playgroud)
然后include,您可以在每个模型类中使用该模块:
class A < ActiveRecord::Base
include Foo
end
class B < ActiveRecord::Base
include Foo
end
Run Code Online (Sandbox Code Playgroud)
在A和B车型现在有一个foo定义的方法.
如果您使用模块名称和文件名称(例如foo.rb中的Foo和foo_bar.rb中的FooBar)遵循Rails命名约定,那么Rails将自动为您加载文件.否则,您将需要使用require_dependency 'file_name'加载您的lib文件.
Aar*_*tad 14
你真的有两个选择:
如果共享功能不是每个类的核心,则使用#1,但适用于每个类.例如:
(app/lib/serializable.rb)
module Serializable
def serialize
# do something to serialize this object
end
end
Run Code Online (Sandbox Code Playgroud)
如果共享功能对于每个类是通用的并且A&B共享自然关系,则使用#2:
(app/models/letter.rb)
class Letter < ActiveRecord::Base
def cyrilic_equivilent
# return somethign similar
end
end
class A < Letter
end
class B < Letter
end
Run Code Online (Sandbox Code Playgroud)
这是我如何做到的...首先创建mixin:
module Slugged
extend ActiveSupport::Concern
included do
has_many :slugs, :as => :target
has_one :slug, :as => :target, :order => :created_at
end
end
Run Code Online (Sandbox Code Playgroud)
然后将其混合到需要它的每个模型中:
class Sector < ActiveRecord::Base
include Slugged
validates_uniqueness_of :name
etc
end
Run Code Online (Sandbox Code Playgroud)
它几乎是漂亮的!
为了完成这个例子,虽然这与问题无关,但这是我的slug模型:
class Slug < ActiveRecord::Base
belongs_to :target, :polymorphic => true
end
Run Code Online (Sandbox Code Playgroud)
例如,一种选择是将它们放在新目录中app/models/modules/.然后,您可以将其添加到config/environment.rb:
Dir["#{RAILS_ROOT}/app/models/modules/*.rb"].each do |filename|
require filename
end
Run Code Online (Sandbox Code Playgroud)
这将require是该目录中的每个文件,因此如果您在模块目录中放置如下文件:
module SharedMethods
def foo
#...
end
end
Run Code Online (Sandbox Code Playgroud)
然后你可以在模型中使用它,因为它会自动加载:
class User < ActiveRecord::Base
include SharedMethods
end
Run Code Online (Sandbox Code Playgroud)
这种方法比将这些mixin放在lib目录中更有条理,因为它们靠近使用它们的类.
如果您需要ActiveRecord :: Base代码作为常用功能的一部分,那么使用抽象类也很有用.就像是:
class Foo < ActiveRecord::Base
self.abstract_class = true
#Here ActiveRecord specific code, for example establish_connection to a different DB.
end
class A < Foo; end
class B < Foo; end
Run Code Online (Sandbox Code Playgroud)
就如此容易.此外,如果代码与ActiveRecord无关,请查找ActiveSupport::Concerns更好的方法.