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

Rails插件分类

    博客分类:
  • Ruby
阅读更多
原文地址:A taxonomy of Rails plugins

Rails开发人员的一个最大的障碍是学习写插件的基础原则。Ruby的动态性和它所提供的代码重用的多种技术让写插件更复杂。
幸运的是,如果你可以写Rails程序,简单的按照一些基本的模式你也可以写插件。

本文的目的就是使用流行插件常用模式的例子来揭开写插件的神秘面纱。

为什么写插件?

写插件可以:
1,让代码分享更有效,无论是在不同的项目间抑或在同一项目里
2,允许你发布通用代码给社区
3,通过测试一次和重用多次来节省时间和增加你的信心
4,以一个健壮的方式分享功能性,特别是在ActiveRecord里使用名字空间时

使用

管理

Rails通过script/plugin install提供安装脚本,以及创建新插件的generator: script/generate plugin。它们将与URL一起工作,
当尝试插件时会节省时间。你可以在Rails wiki阅读关于安装和管理插件的更多信息。

创建

Rails提供一个generator来创建插件。执行如下命令:
script/generate plugin acts_as_

这将在vendor/plugins/acts_as_目录生成一些文件,给你一些存根来让你填充。你将注意到生成一些用来安装、卸载和测试的文件
以及一些rake任务。许多插件不需要引入rake任务,并且安装和卸载插件时你可以做任何事情:也许你想让你的插件引入数据库表
(例如taggable插件需要数据库表来存储tags),或者你可能想在script/plugin install时检查依赖。

Rubyisms

下面Ruby提供的任一工具和技术都被插件用来扩展功能性:
1,Mixins:使用模块来引入或扩展类
2,打开一个类或模块定义并且添加或覆盖方法
3,通过回调和钩子来动态扩展:method_missing,Class#inherited,Module#const_missing,Module#included
4,通过代码生成来动态扩展:eval,class_eval,instance_eval

这些技术形成两种分类:
1,使用模块和类来扩展已有的类和提供新特性
2,使用自省来让一般代码适用于特殊情况

当写一个插件时考虑什么需要被扩展是很重要的。如果需要使用复杂的元编程来让你的插件适用于应用程序,则需要注意确保
同步不会产生不预期的结果。

扩展ActiveRecord

扩展ActiveRecord类的最流行的技术是通过使用模块和一个acts_as_类方法。大部分插件将它们自己分成包含类方法和实例方法
的两个模块,这让方法将在哪里使用很清晰。

添加新代码到ActiveRecord

为了使用你的新的acts_as_插件来扩展ActiveRecord::Base,最常见的技术是简单的添加如下内容到插件的init.rb文件:
ActiveRecord::Base.send(:include, MyPlugin)

你也可以使用class_eval来达到同样的效果。下面的例子来自acts_as_rateable
ActiveRecord::Base.class_eval do
  include FortiusOne::Acts::Rateable
end

注意使用公司名来为作者的插件创建一个名字空间。
下一步是使用持有acts_as_方法的模块来扩展ActiveRecord::Base。下面也是来自acts_as_rateable:
module FortiusOne
  module Acts
    module Rateable

      def self.included(mod)
        mod.extend(ClassMethods)
      end

      module ClassMethods
        def acts_as_rateable(options = {})
        end
      end

这样,任何ActiveRecord类都可以在类定义里使用acts_as_rateable。这样做将把提供的任何options发送到插件的ClassMethods
模块的acts_as_rateable方法里。

管理options

大部分插件在它们的acts_as_方法里使用extend和include来给接受的类提供类方法和实例方法。这也是options被处理的地方。
Options通常通过使用哈希来处理:
def acts_as_taggable(options = {})

如果options被类方法和实例方法同时使用,则write_inheritable_attribute和class_inheritable_reader可以用来节省设置。
下面是一个修改过的acts_as_state_machine
def acts_as_state_machine(opts)
  self.extend(ClassMethods)
  raise NoInitialState unless opts[:initial]
  write_inheritable_attribute :initial_state, opts[:initial]
  class_inheritable_reader :initial_state

如此多的插件使用write_inheritable_attribute而不是cattr_方法有一个原因。考虑如果initial_state是一个类变量会发生什
么:其他使用该插件的对象将包含对同样的initial_state的引用。插件一般为不同的、可重用的代码,所以initial_state的一
个副本(而不是一个引用)是需要的。

重用一套关联和回调

acts_as_taggable_on_steroids阐述了插件的一个简单使用:
module ClassMethods
  def acts_as_taggable(options = {})
    has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag
    has_many :tags, :through => :taggings
    before_save :save_cached_tag_list
    after_save :save_tags

你可以看到,作者从插件的类方法里调用关联和回调。这是可以的,因为acts_as_taggable方法运行于接受类的定义里。

我发现我自己使用同样的技术来定义复杂而重用的关联(特别是重用多态has_many关联的情况)。

例如,我在一个基于组的使用回调和多态has_many关联的安全系统上工作。我写了一个插件来替代添加代码到每个需要基于组
的安全的类中。比较一下下面的代码:
class Contact < ActiveRecord::Base
  acts_as_restricted
end

原始代码:
class Contact < ActiveRecord::Base
  has_many :restrictions, :as => :restricted, :dependent => :destroy, :extend => ...
  before_save :auto_groups
  after_create :save_groups
  ...

该代码可以在我所有的项目间重用了,并且新的类可以“限制为”仅仅添加acts_as_restricted到类定义中。
这可以帮助节省时间--特别是当客户仍在犹豫什么应该被限制时。

结构

我宁愿通过为每个模块创建单独的文件来组织我的插件结构。这在acts_as_solr中阐述了,它为类方法使用一个单独的文件。

模块可以被类方法,实例方法和singleton方法使用。尽管可能看起来区分类方法和singleton方法很难,有些插件作者使用
这来阐明他们的代码。既然singleton方法适用于特殊的对象而不是一些对象,你可以根据需要高效的添加新方法到一个类的
特殊实例。

或者,对于acts_as_rateable,SingletonMethods模块用来区分添加到ActiveRecord的方法和那些添加到接受者的方法。
在这里finders被添加。

扩展ActionController和ActionView
ActiveRecord插件使用的同样的技术被用来扩展ActionController和ActionView。UploadProgress插件扩展了ActionView和
ActionController来添加它自己的helpers和controller功能性:
ActionController::Base.send(:include, UploadProgress)
ActionView::Base.send(:include, UploadProgress::UPloadProgressHelper)

这样Controllers可以通过调用定义在UploadProgress::ClassMethods中的upload_status_for来使用插件。

最佳实践
1,为良好设计的插件避开对include的任意使用
2,仔细的结构化你的插件来确保它们很容易理解和测试
3,确保你使用write_inheritable_attribute和class_inheritable_reader这样你不会以引用设置而不是创建新的告终
4,将写测试作为设计过程中的一部分,不仅是因为插件可能写起来慢,而且当使用mongrel/webrick时它们不能重新加载
5,确保生成的SQL不会导致注射攻击:escape用户输入(我已经找到了生成原始SQL而不用escape变量的开源插件)
6,仔细考虑元编程代码的隐含意义,对eval和eval-like方法保持警惕。

下一步
本文将使用插件被如何测试的例子来继续。

引用
acts_as_rateable
acts_as_state_machine
acts_as_taggable_on_steroids
acts_as_solr
Rails Plugin Directory
Rails Wiki on plugins
分享到:
评论

相关推荐

    Rails插件收集

    1. Rails插件的作用和分类:介绍不同类型的Rails插件,如Devise用于身份验证,CanCanCan处理权限控制,Bootstrap-Sass为视图添加响应式设计等。 2. 如何查找和选择Rails插件:介绍GitHub、RubyGems等平台,讲解如何...

    Ruby-Rails的异常通知插件

    Exception Notification是一款非常实用的Rails插件,它能够自动捕获并报告应用在运行过程中出现的各种异常情况,帮助开发者及时获取错误信息,提高问题解决效率。 Exception Notification插件的核心功能是在Rack或...

    Rails 3 in Action

    第十七章讲解了 **Rails 引擎**,这是一种可以被其他 Rails 应用作为插件使用的独立 Rails 应用。 - **Rails 引擎**: - 类似于插件,但更加强大和灵活。 - 可以提供额外的功能,如电子商务模块、论坛系统等。 #...

    Ruby-一个简单的RubyonRails插件用来创建和管理一个面包屑导航

    在这个特定的场景中,我们关注的是一个名为 "Breadcrumbs on Rails" 的插件,它提供了一种简单的方式来创建和管理面包屑导航在你的 Rails 应用程序中。 面包屑导航是一种用户界面元素,它帮助用户理解他们在网站或...

    Ruby on Rails入门例子

    Rails社区活跃,拥有丰富的插件和gem(Ruby的包管理器),如Devise用于身份验证,CanCanCan进行权限控制,Paperclip或Carrierwave用于文件上传等。这些gem极大扩展了Rails的功能,加速了开发进程。 在本教程中,你...

    Ruby-ActsAsTaggableOnRails应用程序标签插件允许自定义标签在动态环境中

    Ruby-ActsAsTaggableOn 是一个非常流行的Rails插件,用于在动态环境中实现自定义标签功能。这个插件使得在你的Rails应用中添加标签系统变得简单高效,它提供了灵活的接口来管理和操作标签数据。 首先,让我们深入...

    agile-web-development-with-rails_2

    - **模块化改进:** 支持插件系统,允许开发者轻松扩展和定制Rails的功能。 - **社区贡献:** Rails 2更加注重社区的反馈和贡献,这使得框架能够更快地响应用户需求并修复问题。 #### 五、实战案例分析 本书通过...

    awesome-rails-gem-zh_CN, Rails 常用 Gem 列表 - Awesome Rails Gem 中文版.zip

    12. **Kaminari** 和 **WillPaginate**:分页插件,帮助处理大量数据的显示。 13. **Ransack**:提供强大的搜索和过滤功能,让用户可以根据需要自定义搜索条件。 14. **SimpleForm** 和 **Formtastic**:简化Rails...

    rails_admin_jstree:Rails Admin的树形插件

    RailsAdminJstree是一款专为Rails管理界面RailsAdmin设计的扩展插件,它引入了树形视图功能,使得在后台管理系统中可以更方便地处理层级关系的数据。RailsAdmin是一款强大的Ruby on Rails gem,用于快速构建后台管理...

    Ruby-ForemRails3和Rails4论坛引擎

    5. **可扩展性**:Forem的设计允许开发者通过编写插件或者扩展来增加新的功能,例如集成社交媒体分享、添加积分系统等。 6. **自定义主题和样式**:Forem支持CSS和模板的自定义,可以根据需求调整论坛的外观和布局...

    WEB无插件开发包_20200616源码.zip

    为了构建无插件的Web应用,后端技术也非常重要,可能使用的有Node.js、Django、Ruby on Rails或者Spring Boot等,它们能够处理HTTP请求、数据库交互和服务器端逻辑。 文件包可能还包括一个或多个构建工具,如...

    lines-engine:Lines是Rails的可自定义博客框架。 它旨在使发布变得简单而美观

    3. **分类与标签**:对文章进行分类和打标签,方便用户浏览和搜索。 4. **评论系统**:集成评论功能,可能支持社交媒体登录和垃圾评论过滤。 5. **SEO优化**:提供元标签编辑,优化搜索引擎索引。 6. **社交分享**:...

    rabel:一个基于Ruby on Rails框架的开源Web论坛

    - **灵活扩展**:Rails框架提供了丰富的插件和gem(Ruby的库),使得Rabel可以轻松添加新的功能或集成其他服务。 **4. 安装与部署** 要运行Rabel,首先需要安装Ruby环境,然后通过RubyGems安装Rails。接着克隆Rabel...

    discourse-fontawesome:一个 Discourse 插件,可以轻松添加字体很棒的图标

    4. **Ruby on Rails**:尽管主要讨论的是 JavaScript 插件,但了解 Rails 框架的基本概念对于整体理解 Discourse 的运作是必要的。 5. **Git 版本控制**:"master" 分支的提及意味着要熟悉 Git 的工作流程,包括克隆...

    rglossa:Ruby on Rails 版本的 Glossa 系统,用于语料库搜索和结果管理

    4. **可扩展性**:作为 gem,rglossa 可以方便地与其他 Rails 应用集成,或者通过插件机制扩展其功能。 **JavaScript 在 rglossa 中的角色** 虽然主要基于 Ruby on Rails,但 `rglossa` 还利用了 JavaScript 来增强...

    jquery_string_helper:一些字符串助手方法的 Jquery 插件

    我们使用相同的 Ruby on Rails Active 支持字符串辅助方法来简化字符串操作。 #A Jquery Plugins For Some String Helper methods like Camelize, Underscore, Dasherize, Classify, Ordinalize, ForeignKey 所有...

    RoR News-crx插件

    为了创建RoR News-crx插件,开发者可能使用了Ruby on Rails(RoR)框架,这是一个流行的开源Web开发框架,以其MVC(模型-视图-控制器)架构和“约定优于配置”的理念而闻名。Rails支持快速开发,使得创建这样的扩展...

    cosmosys_rm:cosmoSys Redmine插件

    为了安装和使用cosmoSys RM插件,用户通常需要熟悉Ruby on Rails框架,以及Redmine的插件管理和部署流程。这可能涉及到解压文件、将插件代码放入Redmine的指定目录、运行数据库迁移、重启Redmine服务等一系列步骤。 ...

Global site tag (gtag.js) - Google Analytics