SlideShare a Scribd company logo
1 of 46
Download to read offline
Ruby on Rails:
      Plug-in Development 101
      ...and some...




http://jimeh.me/           by Jim Myhrberg
The Basics
Helpers
Controller Methods
Controllers, Helpers & Views
The Basics
to get you started
Generate a Plug-in
      $ script/generate plugin hello_world
install.rb is executed once during installation.

init.rb is the only file included by Rails.

The lib folder is your sanctuary.

Aside from hello_world.rb, place all Ruby source files in
lib/hello_world/ to avoid naming collisions.
Example: Collecta_ruby
Single-file Plug-in

 install.rb copies collecta.yml
 to Rails’ config folder during
 installation.

 init.rb requires lib/collecta.rb,
 loads settings from installed
 collecta.yml and applies them
 to the Collecta class.

 lib/collecta.rb is the ‘heart’ of
 the plug-in.
install.rb

     require "rubygems"
     require "fileutils"

     dir = File.dirname(__FILE__)
     templates = File.join(dir, "templates")
     files = [
       File.join("config", "collecta.yml")
     ]

     files.each do |file|
       if !File.exist?(File.join(RAILS_ROOT, file))
         FileUtils.cp File.join(templates, file), File.join(RAILS_ROOT, file)
       end
     end
init.rb


    if defined? Rails
      require "collecta"
      config_file = File.join(RAILS_ROOT, "config", "collecta.yml")
      if File.exist?(config_file)
        config = YAML.load_file(config_file)
        if !config[RAILS_ENV.to_s].nil? && !config[RAILS_ENV.to_s]["api_key"].nil?
          Collecta.api_key = config[RAILS_ENV.to_s]["api_key"]
        end
      end
    end
collecta.rb

        require   "rubygems"
        require   "net/http"
        require   "uri"
        require   "cgi"
        require   "json"
        require   "xml"

        class Collecta

          @@api_key = nil
          @@api_url = "http://api.collecta.com/search"

          # rest of the class...
        end
Example: Facebooker Plus
Multi-file Plug-in

 init.rb requires all needed files
 from lib folder, and calls an init
 method too boot the plugin.

 Notice how all files are located
 under lib/facebooker_plus/.
 This avoids any naming
 collisions from other plug-ins,
 gems, or system.
init.rb
 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
Helpers
create or overload helpers
One of the simplest things to implement in a Plug-in.
action_view.rb
action_view.rb



     ActionView::Base.send(:include, FacebookerPlus::Rails::Helper)
helper.rb
helper.rb

  module FacebookerPlus
    module Rails
      module Helper

        def url_for(options = {})
          options.is_a?(Hash) ? super(options) : fb_sig_add(super(options))
        end

        def form_for(record_or_name_or_array, *args, &proc)
          args[0][:url] = fb_sig_add(args[0][:url]) if !args[0][:url].nil?
          super(record_or_name_or_array, *args, &proc)
        end

      end
    end
  end
Controller Methods
access custom methods in all controllers
Makes it easy to control different aspects of your plug-
in from within controllers.

Easily create global before/after filters which run from
your plug-in.

Create class methods to enable/disable your plugin on
a per-controller basis.
action_controller.rb
action_controller.rb

     module ::ActionController
       class Base
         def self.inherited_with_facebooker_plus(subclass)
           inherited_without_facebooker_plus(subclass)
           if subclass.to_s == "ApplicationController"
             subclass.send(:include, FacebookerPlus::Rails::Controller)
           end
         end
         class << self
           alias_method_chain :inherited, :facebooker_plus
         end
       end
     end
controller.rb
controller.rb
module FacebookerPlus
  module Rails
    module Controller
      def self.included(controller)
        controller.extend ClassMethods
      end
      def send_p3p_headers
        if !params[:fb_sig_in_iframe].blank?
          headers['P3P'] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'
        end
      end
      def url_for(options = {})
        fb_sig_add(super(options)) rescue super(options)
      end
      module ClassMethods
        def init_facebooker_plus(options = {})
          before_filter :send_p3p_headers
        end
      end
    end
  end
end
Fancy initialization
application_controller.rb



        class ApplicationController < ActionController::Base

          init_facebooker_plus(:app_class => "App")

        end
application_controller.rb



        class ApplicationController < ActionController::Base

          init_facebooker_plus(:app_class => "App")

        end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
controller.rb
 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
       end
       def set_facebooker_plus_options(options = {})
         @facebooker_plus_options = options
       end
       def apply_facebooker_options(options = {})
         if @facebooker_plus_options.has_key?(:app_class) then end
       end
       def create_session_cookie_if_needed # magic happens here
       end
       module ClassMethods
         def init_facebooker_plus(options = {})
           before_filter { |controller| controller.set_facebooker_plus_options(options) }
           before_filter :create_session_cookie_if_needed
           before_filter :apply_facebooker_options
         end
       end
     end
   end
 end
Controllers, Helpers & Views
full controllers, helpers and views in your plug-in
Very useful in some scenarios when complex
functionality is needed.

New Relic’s RPM plug-in uses it to display application
performance under http://localhost:3000/newrelic.

Decently complex to setup.
init.rb

 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
init.rb

 if defined? Rails
   if defined? Facebooker
     require 'facebooker_plus/facebooker_plus'
     require 'facebooker_plus/rails/fb_sig_add'
     require 'facebooker_plus/rails/controller'
     require 'facebooker_plus/rails/helper'
     require 'facebooker_plus/extensions/action_controller'
     require 'facebooker_plus/extensions/action_view'
     require 'facebooker_plus/extensions/session'

     FacebookerPlus::Base.init(defined?(config) ? config : nil)

   else
     STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n"
   end
 end
facebooker_plus.rb
facebooker_plus.rb
   module FacebookerPlus
     class Base
       def self.init(rails_config)

         controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers')
         helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers')
         $LOAD_PATH << controller_path
         $LOAD_PATH << helper_path

         if defined? ActiveSupport::Dependencies
           ActiveSupport::Dependencies.load_paths << controller_path
           ActiveSupport::Dependencies.load_paths << helper_path
         elsif defined? Dependencies.load_paths
           Dependencies.load_paths << controller_path
           Dependencies.load_paths << helper_path
         else
           to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old."
           return
         end

         if rails_config
           rails_config.controller_paths << controller_path
         else
           current_paths = ActionController::Routing.controller_paths
           if current_paths.nil? || current_paths.empty?
              to_stderr "WARNING: Unable to modify the routes in this version of Rails.   Developer mode not available."
           end
           current_paths << controller_path
         end

       end
       # more code here
     end
   end
facebooker_plus.rb



controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers')
helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers')
$LOAD_PATH << controller_path
$LOAD_PATH << helper_path
facebooker_plus.rb


 if defined? ActiveSupport::Dependencies
   ActiveSupport::Dependencies.load_paths << controller_path
   ActiveSupport::Dependencies.load_paths << helper_path
 elsif defined? Dependencies.load_paths
   Dependencies.load_paths << controller_path
   Dependencies.load_paths << helper_path
 else
   to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old."
   return
 end
facebooker_plus.rb


 if rails_config
   rails_config.controller_paths << controller_path
 else
   current_paths = ActionController::Routing.controller_paths
   if current_paths.nil? || current_paths.empty?
      to_stderr "WARNING: Unable to modify the routes in this version of Rails.   " +
        "Developer mode not available."
   end
   current_paths << controller_path
 end
controller.rb

 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
         view_path = File.join(File.dirname(__FILE__), "app", "views")
         if controller.public_methods.include?("append_view_path") # rails 2.1+
           controller.append_view_path(view_path)
         elsif controller.public_methods.include?("view_paths")    # rails 2.0+
           controller.view_paths << view_path
         else                                                      # rails <2.0
           controller.template_root = view_path
         end
       end
     end
   end
 end
controller.rb

 module FacebookerPlus
   module Rails
     module Controller
       def self.included(controller)
         controller.extend ClassMethods
         view_path = File.join(File.dirname(__FILE__), "app", "views")
         if controller.public_methods.include?("append_view_path") # rails 2.1+
           controller.append_view_path(view_path)
         elsif controller.public_methods.include?("view_paths")    # rails 2.0+
           controller.view_paths << view_path
         else                                                      # rails <2.0
           controller.template_root = view_path
         end
       end
     end
   end
 end
The Plug-in “app” folder
Collecta_ruby source:
          http://github.com/jimeh/collecta_ruby

          Facebooker Plus source:
          http://github.com/jimeh/facebooker_plus

          Railscasts: Making a Plug-in:
          http://railscasts.com/episodes/33-making-a-plugin




email: contact@jimeh.me — twitter: @jimeh     slideshare: http://www.slideshare.net/jimeh

More Related Content

What's hot

Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful CodeGreggPollack
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Drupal 7 — Circle theme
Drupal 7 — Circle themeDrupal 7 — Circle theme
Drupal 7 — Circle themeKirill Borzov
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slidesMasterCode.vn
 
15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-searchRazvan Raducanu, PhD
 
Plug in development
Plug in developmentPlug in development
Plug in developmentLucky Ali
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010Plataformatec
 
Synapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindiaComplaints
 
How to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSHow to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSFrank Rousseau
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right wayAnthony Hortin
 
Simple Contact Us Plugin Development
Simple Contact Us Plugin DevelopmentSimple Contact Us Plugin Development
Simple Contact Us Plugin Developmentwpnepal
 
6applets And Graphics
6applets And Graphics6applets And Graphics
6applets And GraphicsAdil Jafri
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSAntonio Peric-Mazar
 
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisSherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisAndreas Sahle
 

What's hot (20)

Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Rails 3 Beautiful Code
Rails 3 Beautiful CodeRails 3 Beautiful Code
Rails 3 Beautiful Code
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Drupal 7 — Circle theme
Drupal 7 — Circle themeDrupal 7 — Circle theme
Drupal 7 — Circle theme
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides
 
15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search15.exemplu complet eloquent view add-edit-delete-search
15.exemplu complet eloquent view add-edit-delete-search
 
Plug in development
Plug in developmentPlug in development
Plug in development
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
O que há de novo no Rails 3 - Ruby on Rails no Mundo Real - 23may2010
 
Synapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephpSynapseindia reviews sharing intro cakephp
Synapseindia reviews sharing intro cakephp
 
How to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJSHow to quickly make REST APIs with CompoundJS
How to quickly make REST APIs with CompoundJS
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Laravel tips-2019-04
Laravel tips-2019-04Laravel tips-2019-04
Laravel tips-2019-04
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
WordPress Queries - the right way
WordPress Queries - the right wayWordPress Queries - the right way
WordPress Queries - the right way
 
Simple Contact Us Plugin Development
Simple Contact Us Plugin DevelopmentSimple Contact Us Plugin Development
Simple Contact Us Plugin Development
 
Bake by cake php2.0
Bake by cake php2.0Bake by cake php2.0
Bake by cake php2.0
 
6applets And Graphics
6applets And Graphics6applets And Graphics
6applets And Graphics
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysisSherlock Markup and Sammy Semantic - drupal theming forensic analysis
Sherlock Markup and Sammy Semantic - drupal theming forensic analysis
 

Similar to Rails Plugin Development 101 (...and some...)

Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails Hung Wu Lo
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn Cleveley
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experienceBeth Soderberg
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolGordon Forsythe
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30fiyuer
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction PresentationNerd Tzanetopoulos
 
Ajax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsAjax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsRaghavan Mohan
 
Web-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxWeb-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxcelenarouzie
 
Getting started with WordPress development
Getting started with WordPress developmentGetting started with WordPress development
Getting started with WordPress developmentSteve Mortiboy
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3Javier Eguiluz
 
MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 Joe Ferguson
 
Write your first WordPress plugin
Write your first WordPress pluginWrite your first WordPress plugin
Write your first WordPress pluginAnthony Montalbano
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action packrupicon
 
Sahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeSahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeAidIQ
 
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Damien Carbery
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin developmentMostafa Soufi
 

Similar to Rails Plugin Development 101 (...and some...) (20)

Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Empowering users: modifying the admin experience
Empowering users: modifying the admin experienceEmpowering users: modifying the admin experience
Empowering users: modifying the admin experience
 
Zend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_ToolZend Framework 1.9 Setup & Using Zend_Tool
Zend Framework 1.9 Setup & Using Zend_Tool
 
Django design-patterns
Django design-patternsDjango design-patterns
Django design-patterns
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
Symfony2 Introduction Presentation
Symfony2 Introduction PresentationSymfony2 Introduction Presentation
Symfony2 Introduction Presentation
 
Ajax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorialsAjax, JSF, Facelets, Eclipse & Maven tutorials
Ajax, JSF, Facelets, Eclipse & Maven tutorials
 
Web-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docxWeb-based application development part 31MINIMIZE .docx
Web-based application development part 31MINIMIZE .docx
 
Comilla University
Comilla University Comilla University
Comilla University
 
Getting started with WordPress development
Getting started with WordPress developmentGetting started with WordPress development
Getting started with WordPress development
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3
 
MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5 MidwestPHP 2016 - Adventures in Laravel 5
MidwestPHP 2016 - Adventures in Laravel 5
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
Write your first WordPress plugin
Write your first WordPress pluginWrite your first WordPress plugin
Write your first WordPress plugin
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action pack
 
Sahana Eden - Introduction to the Code
Sahana Eden - Introduction to the CodeSahana Eden - Introduction to the Code
Sahana Eden - Introduction to the Code
 
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
Demystifying Hooks, Actions & Filters - WordCamp Belfast 2018
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin development
 

Recently uploaded

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 

Rails Plugin Development 101 (...and some...)

  • 1. Ruby on Rails: Plug-in Development 101 ...and some... http://jimeh.me/ by Jim Myhrberg
  • 3. The Basics to get you started
  • 4. Generate a Plug-in $ script/generate plugin hello_world
  • 5. install.rb is executed once during installation. init.rb is the only file included by Rails. The lib folder is your sanctuary. Aside from hello_world.rb, place all Ruby source files in lib/hello_world/ to avoid naming collisions.
  • 7. Single-file Plug-in install.rb copies collecta.yml to Rails’ config folder during installation. init.rb requires lib/collecta.rb, loads settings from installed collecta.yml and applies them to the Collecta class. lib/collecta.rb is the ‘heart’ of the plug-in.
  • 8. install.rb require "rubygems" require "fileutils" dir = File.dirname(__FILE__) templates = File.join(dir, "templates") files = [ File.join("config", "collecta.yml") ] files.each do |file| if !File.exist?(File.join(RAILS_ROOT, file)) FileUtils.cp File.join(templates, file), File.join(RAILS_ROOT, file) end end
  • 9. init.rb if defined? Rails require "collecta" config_file = File.join(RAILS_ROOT, "config", "collecta.yml") if File.exist?(config_file) config = YAML.load_file(config_file) if !config[RAILS_ENV.to_s].nil? && !config[RAILS_ENV.to_s]["api_key"].nil? Collecta.api_key = config[RAILS_ENV.to_s]["api_key"] end end end
  • 10. collecta.rb require "rubygems" require "net/http" require "uri" require "cgi" require "json" require "xml" class Collecta @@api_key = nil @@api_url = "http://api.collecta.com/search" # rest of the class... end
  • 12. Multi-file Plug-in init.rb requires all needed files from lib folder, and calls an init method too boot the plugin. Notice how all files are located under lib/facebooker_plus/. This avoids any naming collisions from other plug-ins, gems, or system.
  • 13. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 15. One of the simplest things to implement in a Plug-in.
  • 17. action_view.rb ActionView::Base.send(:include, FacebookerPlus::Rails::Helper)
  • 19. helper.rb module FacebookerPlus module Rails module Helper def url_for(options = {}) options.is_a?(Hash) ? super(options) : fb_sig_add(super(options)) end def form_for(record_or_name_or_array, *args, &proc) args[0][:url] = fb_sig_add(args[0][:url]) if !args[0][:url].nil? super(record_or_name_or_array, *args, &proc) end end end end
  • 20. Controller Methods access custom methods in all controllers
  • 21. Makes it easy to control different aspects of your plug- in from within controllers. Easily create global before/after filters which run from your plug-in. Create class methods to enable/disable your plugin on a per-controller basis.
  • 23. action_controller.rb module ::ActionController class Base def self.inherited_with_facebooker_plus(subclass) inherited_without_facebooker_plus(subclass) if subclass.to_s == "ApplicationController" subclass.send(:include, FacebookerPlus::Rails::Controller) end end class << self alias_method_chain :inherited, :facebooker_plus end end end
  • 25. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def send_p3p_headers if !params[:fb_sig_in_iframe].blank? headers['P3P'] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"' end end def url_for(options = {}) fb_sig_add(super(options)) rescue super(options) end module ClassMethods def init_facebooker_plus(options = {}) before_filter :send_p3p_headers end end end end end
  • 27. application_controller.rb class ApplicationController < ActionController::Base init_facebooker_plus(:app_class => "App") end
  • 28. application_controller.rb class ApplicationController < ActionController::Base init_facebooker_plus(:app_class => "App") end
  • 29. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 30. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 31. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 32. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 33. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods end def set_facebooker_plus_options(options = {}) @facebooker_plus_options = options end def apply_facebooker_options(options = {}) if @facebooker_plus_options.has_key?(:app_class) then end end def create_session_cookie_if_needed # magic happens here end module ClassMethods def init_facebooker_plus(options = {}) before_filter { |controller| controller.set_facebooker_plus_options(options) } before_filter :create_session_cookie_if_needed before_filter :apply_facebooker_options end end end end end
  • 34. Controllers, Helpers & Views full controllers, helpers and views in your plug-in
  • 35. Very useful in some scenarios when complex functionality is needed. New Relic’s RPM plug-in uses it to display application performance under http://localhost:3000/newrelic. Decently complex to setup.
  • 36. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 37. init.rb if defined? Rails if defined? Facebooker require 'facebooker_plus/facebooker_plus' require 'facebooker_plus/rails/fb_sig_add' require 'facebooker_plus/rails/controller' require 'facebooker_plus/rails/helper' require 'facebooker_plus/extensions/action_controller' require 'facebooker_plus/extensions/action_view' require 'facebooker_plus/extensions/session' FacebookerPlus::Base.init(defined?(config) ? config : nil) else STDERR.puts "** [FacebookerPlus] ERROR: Please load Facebooker before Facebooker Plus.n" end end
  • 39. facebooker_plus.rb module FacebookerPlus class Base def self.init(rails_config) controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers') helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers') $LOAD_PATH << controller_path $LOAD_PATH << helper_path if defined? ActiveSupport::Dependencies ActiveSupport::Dependencies.load_paths << controller_path ActiveSupport::Dependencies.load_paths << helper_path elsif defined? Dependencies.load_paths Dependencies.load_paths << controller_path Dependencies.load_paths << helper_path else to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old." return end if rails_config rails_config.controller_paths << controller_path else current_paths = ActionController::Routing.controller_paths if current_paths.nil? || current_paths.empty? to_stderr "WARNING: Unable to modify the routes in this version of Rails. Developer mode not available." end current_paths << controller_path end end # more code here end end
  • 40. facebooker_plus.rb controller_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'controllers') helper_path = File.join(facebooker_plus_root, 'lib', 'facebooker_plus', 'rails', 'app', 'helpers') $LOAD_PATH << controller_path $LOAD_PATH << helper_path
  • 41. facebooker_plus.rb if defined? ActiveSupport::Dependencies ActiveSupport::Dependencies.load_paths << controller_path ActiveSupport::Dependencies.load_paths << helper_path elsif defined? Dependencies.load_paths Dependencies.load_paths << controller_path Dependencies.load_paths << helper_path else to_stderr "ERROR: Rails version #{(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : ''} too old." return end
  • 42. facebooker_plus.rb if rails_config rails_config.controller_paths << controller_path else current_paths = ActionController::Routing.controller_paths if current_paths.nil? || current_paths.empty? to_stderr "WARNING: Unable to modify the routes in this version of Rails. " + "Developer mode not available." end current_paths << controller_path end
  • 43. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods view_path = File.join(File.dirname(__FILE__), "app", "views") if controller.public_methods.include?("append_view_path") # rails 2.1+ controller.append_view_path(view_path) elsif controller.public_methods.include?("view_paths") # rails 2.0+ controller.view_paths << view_path else # rails <2.0 controller.template_root = view_path end end end end end
  • 44. controller.rb module FacebookerPlus module Rails module Controller def self.included(controller) controller.extend ClassMethods view_path = File.join(File.dirname(__FILE__), "app", "views") if controller.public_methods.include?("append_view_path") # rails 2.1+ controller.append_view_path(view_path) elsif controller.public_methods.include?("view_paths") # rails 2.0+ controller.view_paths << view_path else # rails <2.0 controller.template_root = view_path end end end end end
  • 46. Collecta_ruby source: http://github.com/jimeh/collecta_ruby Facebooker Plus source: http://github.com/jimeh/facebooker_plus Railscasts: Making a Plug-in: http://railscasts.com/episodes/33-making-a-plugin email: contact@jimeh.me — twitter: @jimeh slideshare: http://www.slideshare.net/jimeh