在模型和控制器中,我们经常在类定义的顶部使用before_validation
,skip_before_filter
之类的Rails宏。
这是如何实施的?如何添加自定义的?
谢谢!
答案 0 :(得分:20)
它们只是标准的Ruby函数。 Ruby灵活的语法方法使它看起来比它更好。您可以通过将方法编写为普通的Ruby函数并执行以下操作之一来创建自己的:
将它放在可由您的控制器访问的位置,例如application.rb
将其放入文件中并将其输入。
通过Ruby include
关键字将代码混合到一个类中。
最后一个选项对于模型类很有用,第一个选项实际上只适用于控制器
第一种方法的一个例子如下所示。在这个例子中,我们将代码添加到ApplicationController类中(在application.rb中)并在其他控制器中使用它。
class BusinessEntitiesController < ApplicationController
nested_within :Glossary
private
# Standard controller code here ....
nested_within 提供帮助函数和变量,以帮助识别“父”资源的id。实际上它会动态解析URL,并且每个控制器都可以访问它。例如,当请求进入控制器时,会自动解析它,并将类属性@parent_resource设置为Rails查找的结果。副作用是如果父资源不存在则发回“未找到”响应。这使我们无需在每个嵌套资源中键入样板代码。
这听起来很聪明,但它只是一个标准的Ruby功能......
def self.nested_within(resource)
#
# Add a filter to the about-to-be-created method find_parent_ud
#
before_filter :find_parent_id
#
# Work out what the names of things
#
resource_name = "#{resource.to_s.tableize.singularize}"
resource_id = "#{resource_name}_id"
resource_path = "#{resource.to_s.tableize}_path"
#
# Get a reference to the find method in the model layer
#
finder = instance_eval("#{resource}.method :find_#{resource_name}")
#
# Create a new method which gets executed by the before_filter above
#
define_method(:find_parent_id) do
@parent_resource = finder.call(params[resource_id])
head :status => :not_found, :location => resource_path
unless @parent_resource
end
end
nested_within函数在ApplicationController(controllers / application.rb)中定义,因此会被自动拉入。
请注意,nested_within在控制器类的主体内执行。这会将方法find_parent_id添加到控制器。
Ruby的灵活语法和Rail的over-over-configuration的组合使得这一切看起来比实际更强大(或更凶悍)。
下次你找到一个很酷的方法时,只需在它前面留一个断点并追踪它。啊开源!
如果我可以进一步提供帮助,或者您想要了解嵌套内容代码如何工作,请告诉我。
克里斯
答案 1 :(得分:16)
克里斯的回答是正确的。但是这里是你想要编写自己的代码的地方:
添加这样的Controller方法的最简单方法是在ApplicationController
中定义它:
class ApplicationController < ActionController::Base
...
def self.acts_as_awesome
do_awesome_things
end
end
然后您可以从各个控制器访问它,如下所示:
class AwesomeController < ApplicationController
acts_as_awesome
end
对于模型,您想重新打开ActiveRecord::Base
:
module ActiveRecord
class Base
def self.acts_as_super_awesome
do_more_awesome_stuff
end
end
end
我个人会把它放在config/initializers
的文件中,以便它加载一次,这样我就知道在哪里寻找它。
然后你可以在这样的模型中访问它:
class MySuperAwesomeModel < ActiveRecord::Base
acts_as_super_awesome
end