Rails:宏样式函数

时间:2009-05-29 15:09:00

标签: ruby-on-rails

在模型和控制器中,我们经常在类定义的顶部使用before_validationskip_before_filter之类的Rails宏。

这是如何实施的?如何添加自定义的?

谢谢!

2 个答案:

答案 0 :(得分:20)

它们只是标准的Ruby函数。 Ruby灵活的语法方法使它看起来比它更好。您可以通过将方法编写为普通的Ruby函数并执行以下操作之一来创建自己的:

  1. 将它放在可由您的控制器访问的位置,例如application.rb

  2. 将其放入文件中并将其输入。

  3. 通过Ruby include关键字将代码混合到一个类中。


  4. 最后一个选项对于模型类很有用,第一个选项实际上只适用于控制器

    示例


    第一种方法的一个例子如下所示。在这个例子中,我们将代码添加到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