`
chinapkw
  • 浏览: 110919 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

write a plugin for rails

阅读更多

A few days back I posted my very first Rails plugin, Acts As Exportable. Although writing a plugin is rather easy, you must know a few tricks on how to get things going.

This article will show you how to develop a plugin that adds functionality to a controller (other plugins, e.g. for models) will follow later. In fact, I’ll explain to you how I developed my Acts As Exportable plugin.

Let’s take a basic Rails application for starters. You have setup a model with some attributes and a scaffolded controller that allows you to CRUD your items. In this tutorial I’ll be working with books. The model is named ‘Book’ and the controller ‘BooksController’. Start your web server now and add some random data to play with.

Before you dive into writing a plugin for the controller to export data to XML you should have some basic functionality in your controller first. I’ve found it easier to develop my code in the controller first, and then port it to a plugin.

So, add a new method to your BooksController that’ll export books to XML. This looks quite easy:

def export_to_xml
  books = Book.find(:all, :order => 'title')
  send_data books.to_xml,
    :type => 'text/xml; charset=UTF-8;',
    :disposition => "attachment; filename=books.xml"
end

Now, call /books/export_to_xml and you download a real XML file containing all your books! To make things a bit more complicated, we want to be able to feed this method some conditions to select books. A nice solution is to add a special method for this that defines these conditions. (You could also use them in listing books, for example.) I add a new method to the BooksController:

def conditions_for_collection
  ['title = ?', 'some title!']
end

The condition is of the same format you can feed to find. Here you could, for example, select only the books belonging to the currently logged in user.

Next, update the export_to_xml method to use these conditions

def export_to_xml
  books = Book.find(:all, :order => 'title', :conditions => conditions_for_collection)
  send_data books.to_xml,
    :type => 'text/xml; charset=UTF-8;',
    :disposition => "attachment; filename=books.xml"
end

Nice that’s it. Now, you like what you’ve made so far, and want to stuff it into a plugin and put it on your weblog. Here’s how to go about that.

Creating the plugin

First, generate the basic code for a plugin:

./script/generate plugin acts_as_exportable

This will create a new directory in vendor/plugins containing all the basic files you need. First, we’ll take a look at vendor/plugins/acts_as_exportable/lib/acts_as_exportable.rb. This is where all the magic happens.

What we want is to is add a method to ActionControllerBase that allows you to easily enable the plugin in a certain controller. So, how do you want to activate the plugin? Right, you just call ‘acts_as_exportable’ from the controller, or optionally, you add the name of the model you want to use.

acts_as_exportable
acts_as_exportable :book

The vendor/plugins/acts_as_exportable/lib/acts_as_exportable.rb contains a module that’s named after our plugin:

module ActsAsExportable
end

Next, we add a module named ‘ClassMethods’. These class methods will be added to ActionController::Base when the plugin is loaded (we’ll take care of that in a moment), and enable the functionality described above.

module ActsAsExportable
  def self.included(base)
    base.extend(ClassMethods)
  end
 
  class Config
    attr_reader :model
    attr_reader :model_id
 
    def initialize(model_id)
      @model_id = model_id
      @model = model_id.to_s.camelize.constantize
    end
 
    def model_name
      @model_id.to_s
    end
  end
 
  module ClassMethods
	  def acts_as_exportable(model_id = nil)
      # converts Foo::BarController to 'bar' and FooBarsController
      # to 'foo_bar' and AddressController to 'address'
      model_id = self.to_s.split('::').last.sub(/Controller$/, '').\
 pluralize.singularize.underscore unless model_id
 
      @acts_as_exportable_config = ActsAsExportable::Config.\
 new(model_id)
      include ActsAsExportable::InstanceMethods
    end
 
    # Make the @acts_as_exportable_config class variable easily 
    # accessable from the instance methods.
    def acts_as_exportable_config
      @acts_as_exportable_config || self.superclass.\
 instance_variable_get('@acts_as_exportable_config')
    end
  end
end

So, what happened? The first method you see extends the current class (that’s every one of your controllers with the methods from the ClassMethods module).

Every class now has the ‘acts_as_exportable’ method available. What does it do? The plugin automatically grabs the name of the model associated (by convention) with the controller you use, unless you specify something else.

Next, we create a new configuration object that contains information about the model we’re working with. Later on this can contain more detailed information like what attributes to include or exclude from the export.

Finally we include the module InstanceMethods, which we still have to define. The instance methods are only included when we enable the plugin. In our case, the instance methods include the ‘export_to_xml’ and ‘conditions_for_collection’ methods. We can simply copy/paste them into your plugin.

module InstanceMethods
  def export_to_xml
    data = Book.find(:all, :order => 'title', :conditions => conditions_for_collection)
    send_data data.to_xml,
      :type => 'text/xml; charset=UTF-8;',
      :disposition => "attachment; filename=books.xml"
  end
 
  # Empty conditions. You can override this in your controller
  def	conditions_for_collection
  end
end

Take note that we don’t want to define any default conditions, because we don’t know what model we’re using here. By adding an empty method, the method is available and no conditions are used. Another developer can define ‘conditions_for_collection’ in his controller to override the one we write here.

In the ‘export_to_xml’ there are a few changes as well. First of all, I generalized ‘books’ to ‘data’.

The most important step is yet to come. We have still application specific code in your plugin, namely the Book model. This is where the Config class and @acts_as_exportable_config come in.

We have added a class variable to the controller named @acts_as_exportable_config. By default, this variable is not accessable by instance methods, so we need a little work around:

self.class.acts_as_exportable_config

This will call the class method ‘acts_as_exportable_config’ we defined in ClassMethods and return the value of @acts_as_exportable_config.

Note that we store the configuration in each seperate controller. This allows acts_as_exportable to be used with more than one controller at the same time.

With the model name made application independent, the whole plugin code looks like:

module ActsAsExportable
  def self.included(base)
    base.extend(ClassMethods)
  end
 
  class Config
    attr_reader :model
    attr_reader :model_id
 
    def initialize(model_id)
      @model_id = model_id
      @model = model_id.to_s.camelize.constantize
    end
 
    def model_name
      @model_id.to_s
    end
  end
 
  module ClassMethods
	  def acts_as_exportable(model_id = nil)
      # converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar'
      # and AddressController to 'address'
      model_id = self.to_s.split('::').last.sub(/Controller$/, '').\
 pluralize.singularize.underscore unless model_id
 
      @acts_as_exportable_config = ActsAsExportable::Config.new(model_id)
      include ActsAsExportable::InstanceMethods
    end
 
    # Make the @acts_as_exportable_config class variable easily
    # accessable from the instance methods.
    def acts_as_exportable_config
      @acts_as_exportable_config || self.superclass.\
 instance_variable_get('@acts_as_exportable_config')
    end
  end
 
	module InstanceMethods
	  def export_to_xml
	    data = self.class.acts_as_exportable_config.model.find(:all, 
              :order => 'title', 
              :conditions => conditions_for_collection)
	    send_data data.to_xml,
	      :type => 'text/xml; charset=UTF-8;',
	      :disposition => "attachment; filename=\
 #{self.class.acts_as_exportable_config.model_name.pluralize}.xml"
	  end
 
	  # Empty conditions. You can override this in your controller
    def	conditions_for_collection
    end
  end
end

Add the following line to your BooksController and restart your web server. (Oh, and make sure to remove the export_to_xml method from the controller as well)

acts_as_exportable

Done! – Or not?

Enabling the plugin by default

We have a very nice plugin now, but it is not loaded by default! If you take a look at your plugin directory, you’ll find a file named ‘init.rb’. This file is executed when you (re)start your web server. This is the perfect place to add our class methods to the ActionController::Base. Just add the following three lines of code to ‘init.rb’:

ActionController::Base.class_eval do
  include ActsAsExportable
end

When we include our module, the ’self.included’ method is called, and the ClassMethods module is added, thus enabling the acts_as_exportable method.

That’s all! Happy plugin writing!

Feel free to comment on this post and write about any of your own plugin (for controllers) experiences

分享到:
评论

相关推荐

    APE、FLAC插件APE Plugin for Nero

    总之,"APE Plugin for Nero"为Nero用户提供了一个方便的工具,使他们能够在不牺牲音质的前提下,利用Nero的全面功能来管理和操作APE格式的音频文件。通过理解无损音频格式的原理和特性,以及如何在Nero中有效使用...

    SDL plugin for C4droid.apk

    SDL plugin for C4droid.apk

    Nagios Plugin for Cacti

    Nagios Plugin for Cacti 是一款用于集成监控系统Nagios与网络性能绘图工具Cacti的插件。这个插件旨在扩展Cacti的功能,使其能够利用Nagios的强大监控能力,提供更全面、实时的网络及服务器状态信息。 Nagios是一款...

    Veeam Rman Plugin for Oracle安装和使用手册.docx

    "VEEAM Rman Plugin for Oracle安装和使用手册" VEEAM Rman Plugin for Oracle是VEEAM公司开发的一款插件,旨在为Oracle RAC数据库提供备份和恢复解决方案。该插件可以与VEEAM Backup & Replication集成,提供了一...

    Google Plugin for Eclipse 4.3

    - **Android开发支持**:Google Plugin for Eclipse 4.3提供了完整的Android SDK集成,包括项目创建、源代码编辑、资源管理、调试器、模拟器控制等,帮助开发者高效地进行Android应用开发。 - **ADT(Android ...

    Google Plugin for Eclipse 4.2

    《Google Plugin for Eclipse 4.2:打造高效谷歌开发环境》 在软件开发领域,集成开发环境(Integrated Development Environment,简称IDE)扮演着至关重要的角色,它为开发者提供了集编码、调试、测试于一体的高效...

    google plugin for eclipse

    "Google Plugin for Eclipse" 是一款由Google开发的集成开发环境(IDE)插件,专为Eclipse设计,目的是为了方便开发者在Eclipse中进行Google相关的应用开发,如Android应用、Google App Engine应用等。这款插件提供了...

    GWT Plugin For Eclipse (1)

    GWT Plugin For Eclipse (1) Google Web Toolkit

    NetBeans debug for rails

    Rails debug plugin for netbeans ide 6.0. Zip format without subfix.

    Unity Bluetooth LE Plugin for Android.pdf

    该文档是一份关于Unity Bluetooth LE Plugin for Android的技术文档,主要针对的是在Unity中开发Android低功耗蓝牙功能。文档中介绍和解释了如何使用这个插件,提供了一些版本更新的详细信息,以及设置和安装插件的...

    JavaScript plugin for eclipse3.5 spket-1.6.18 破解版

    JavaScript plugin for eclipse3.5 spket-1.6.18 破解版

    MongoDB plugin for eclipse

    MongoDB is a kind of Nosql. with this plugin you can develope MongoDB in a UI .

    Google Plugin for Eclipse 3.5 离线安装包 part2

    Google Plugin for Eclipse 3.5 离线安装包 part2 分享给需要的人 支持eclipse 3.5 myeclipse 8.X

    python plugin for Inteij IDEA

    python plugin for Inteij IDEA

    m2maven is a plugin for maven

    This Core update site contains a single component: "Maven Integration for Eclipse (Required)". When you install this component you will be installing all of the core Wizards, the POM Editor, Maven ...

    weblogic 8.1 plugin for Eclipse 3.4

    weblogic 8.1 plugin for Eclipse 3.4 weblogic 8.1 plugin for Eclipse 3.4 weblogic 8.1 plugin for Eclipse 3.4

    google plugin for eclipse juno(4.2)

    离线安装google plugin for eclipse,由于eclipse自带的market不给力,那就选择离线安装。 下载后,打开eclipse,选择 install new software,Add,Location中定位到下载的zip文件,然后选择需要安装的组件,Next,...

    APE Plugin for Nero V1.0.0.37 刻录APE补丁

    软件简介: 使用该插件可以让Nero直接刻录APE音乐。解压nxMyAPE.dll到 C:\PROGRAM FILES\COMMON FILES\AHEAD\AUDIOPLUGINS,启动Nero...安装了ape plugin for nero,就可以像用wav、mp3刻cd一样,直接在nero里拖放就成。

    WebServer Plugin for Websphere Application Server 6.1

    这个压缩包文件“WebServer Plugin for Websphere Application Server 6.1.rar”包含了实现这一功能所需的重要组件。 首先,让我们深入了解WebServer Plugin的作用。WebServer Plugin通常部署在如Apache ...

    jQuery plugin for autocomplete - jQuery自动完成插件

    jQuery plugin for autocomplete - jQuery自动完成插件

Global site tag (gtag.js) - Google Analytics