a0c5b34e9d
#13 - Modified to hook module ::ActionController::Flash rather than ::ActionController::Redirect |
||
---|---|---|
app | ||
lib | ||
spec/test_app | ||
vendor/assets/javascripts | ||
.gitignore | ||
Changelog.md | ||
Gemfile | ||
License | ||
paloma.gemspec | ||
README.md | ||
TODO.md |
Paloma
Paloma provides a sexy and logical way of organizing Rails javascript files. Its core feature is a powerful yet simple way to execute page-specific javascript code.
But there are more sexy features Paloma has to offer!
Advantages
- Javascript files are organized per controller just like app/views folder of Rails.
- Javascript file per controller's action.
- Choose what specific javascript codes to run per page.
- Easily make ruby variables available on your javascript files.
Quick Example
The javascript callback file /assets/javascripts/paloma/users/new.js
:
Paloma.callbacks['users']['new'] = function(params){
// This will only run after executing users/new action
alert('Hello New Sexy User');
};
The Rails controller app/controllers/users_controller.rb
:
def UsersController < ApplicationController
def new
@user = User.new
# No special function to call, the javascript callback will be executed automatically
# just for this specific action.
end
end
That's it! Simply Sexy!
Minimum Requirements
- jQuery 1.7 or higher
- Rails 3.1 or higher
Install
Without bundler:
sudo gem install paloma
With bundler, add this to your Gemfile:
gem 'paloma'
Setup
On setup, the paloma
folder will be generated in app/assets/javascripts/
containing its required files. Run:
rails g paloma:setup
Require paloma
in your application.js
:
//= require paloma
Basic Directory Structure
paloma
folder contains the javascript callbacks.
- paloma
- [controller]
- [action].js
- [other_action].js
- [other_controller]
- [action].js
- [other_action].js
- [more_action].js
- [namespace]
- [controller]
- [action].js
- [controller]
- [controller]
Generators
- Generate a controller folder containing its required files:
rails g paloma:add [controller]
**Example:**
```
rails g paloma:add users
```
**Generates:**
* /paloma
* /users
- Generate a callback file for a controller's action:
rails g paloma:add [controller] [action]
**Example:**
```
rails g paloma:add users new
```
**Generates:**
* /paloma
* /users
* new.js
- Generate multiple callback files:
rails g paloma:add [controller] [action_1] [action_2] ... [action_n]
**Example:**
```
rails g paloma:add users new create edit update
```
**Generates:**
* /paloma
* /users
* new.js
* create.js
* edit.js
* update.js
- Generate namespaced controller and callbacks:
rails g paloma:add [namespace]/[controller] [action_1] [action_2] ... [action_n]
**Example:**
```
rails g paloma:add admin/users new
```
**Generates:**
* /paloma
* /admin
* /users
* new.js
Notes:
-
You can directly run
rails g paloma:add [controller] [action]
orrails g paloma:add [namespace]/[controller] [action]
even the controller folder is not yet existing onpaloma
folder. It will be created automatically. -
Controller folder and action javascript files will automatically be created after running
rails g controller
orrails g scaffold
.
Advanced Callbacks
By default Paloma will execute the callback that matches the current controller and action if it finds one.
For instance, if the current response is from the new
action of the Users
controller, then Paloma will try to execute callbacks['users']['new']
if it exists.
You can manipulate callback behavior by using the js
command before the render
or redirect_to
command in your controllers.
-
Preventing the Callback to execute.
def destroy user = User.find params[:id] user.destroy js false end
callbacks["controller"]["destroy"]
will not be executed. -
Using other action's callback from the same controller.
def edit @user = User.find params[:id] js :new end
This will execute
callback["controllers"]["new"]
instead ofcallback["controllers"]["edit"]
. -
Using other action's callback from other controller.
def index @users = User.all js :controller => 'clients', :action => 'index' end
This will execute
callbacks["clients"]["index"]
instead ofcallbacks["controllers"]["index"]
. -
Using other action's callback from a namespaced controller.
class UsersController < ApplicationController def destroy @user = User.find params[:id] @user.destroy js :controller => 'admin/users', :action => :destroy end end
This will execute
callbacks["admin/users"]["destroy"]
instead ofcallbacks["users"]["destroy"]
.
Passing Parameters
You can also pass parameters to the callback by passing a :params
key to js
. The passed parameters
will be available on the callback by the params
object.
Example:
users_controller.rb
def destroy
user = User.find params[:id]
user.destroy
js :params => {:user_id => params[:id]}
end
/paloma/users/destroy.js
Paloma.callbacks['users']['destroy'] = function(params){
var id = params['user_id'];
alert('User ' + id + ' deleted.');
};
Default Parameters
params['controller']
- controller name without its namespace.
params['namespace']
- controller's namespace name.
params['action']
- controller's action that triggers the filter or callback.
params['controller_path']
- controller name with its namespace.
params['callback_controller']
- callback's controller name without its namespace.
params['callback_namespace']
- callback's namespace name.
params['callback_action']
- callback's action name.
params['callback_controller_path']
- callback's controller with its namespace.
Filters
This is almost similar to Rails controller filters. These are functions executed either before
, after
,
or even around
(before and after) a Paloma callback is executed.
Filters are defined on _filters.js
files in Paloma's root folder, namespace folder, or controller folder.
Syntax
filter.as('filter name').before_all().perform(function(params){
alert("I'm a before filter!");
});
filter.as('another filter').after_all().perform(function(params){
alert("I'm an after filter");
});
Specify Actions To Filter
-
For all actions.
filter.as('name').before_all() filter.as('name').after_all() filter.as('name').around_all()
-
Only for specific action/s.
filter.as('name').before('new', 'edit', 'update') filter.as('name').after('destroy') filter.as('name').around('show')
-
Except for specific action/s.
filter.as('name').except_before('new') filter.as('name').except_after('destroy', 'edit') filter.as('name').except_around('show')
Filter Inheritance
All _filters.js
inherit filters defined on the global _filters.js
file.
Controller's _filters.js
will also inherit filters defined on its namespace _filters.js
if it exists.
Execution Time
Global filters (on /paloma/_filters.js
) are executed first, then Namespace filters if any,
then Controller filters.
Before filters, as you've guessed, are executed before the callback is called. The order of execution is based on the order of declaration. After before filters, around filters are executed then the callback is finally executed. After filters are called after the callback is executed, then it will execute the around filters again.
Shared Variable Between Filter and Callback
Automatically, filters has an access to the params
object passed via the js
ruby method.
But you can also make a variable visible both on a filter and a callback using the _x
object.
Example:
on _filters.js
:
filter.as('filter name').before('new').perform(function(params){
_x.sharedVariable = "Sexy Paloma";
});
on new.js
:
Paloma.callbacks['controller']['new'] = function(params){
alert(_x.sharedVariable); // outputs "Sexy Paloma";
});
Skipping Filters
You can skip filters using the skip_*_filter
or skip_*_filters
command.
You can also specify which action or actions the filter skip is applicable using only
or except
command.
filter.skip_before_filter('filter A'); // skip 'filter A' for all actions
filter.skip_after_filters('filter A', 'filter B').only('new', 'edit'); // skip 'filter A' and 'filter B' for 'new' and 'edit' actions.
filter.skip_around_filter('filter A').except('destroy'); // skip 'filter A' for all actions except for 'destroy'.
##Locals
Locals are variables or methods which can be made locally available within a controller or a namespace. Locals can also be made available throughout the whole Paloma files (globally).
The motivation of Locals is to organize helper methods and helper variables within a namespace or controller.
-
Application-wide Locals
Defined on
paloma/_locals.js
. This contains methods and variables that are intended to be available globally. -
Namespace-wide Locals
Defiend on
paloma/namespace/_locals.js
. This contains methods and variables that are intended to be available on the specific namespace only. -
Controller-wide Locals
Defined on
paloma/controller/_locals.js
orpaloma/namespace/controller/_locals.js
. This contains methods and variables that are intended to be available on the specific controller only.
###Creating Locals
Locals can be created using the locals
object inside _filters.js
file.
Example:
locals.helperMethod = function(){
return "Hello World";
};
locals.helperVariable = "WOW!";
###Accessing Locals
Locals can be accessed in your filter and callback files using the _l
object.
Example
Paloma.callbacks['users']['new'] = function(params){
alert("Hello Sexy User");
_l.helperMethod();
console.log(_l.helperVariable);
};
###Accessing Locals From Other Controller/Namespace
Sometimes there is a need to use other's local methods and variables.
You can achieve this by using the Paloma.locals
object or its alias _L
.
Example
Paloma.callbacks['users']['new'] = function(params){
_L.otherController.helperMethod(); // accessing local helperMethod() of the otherController
_L['otherController'].helperVariable;
}
###Locals Inheritance
_locals.js
inherits locals from its parent _locals.js
, either from namespace or application-wide.
You can also override locals inherited from parents.
Example
paloma/_locals.js
contains:
locals.globalMethod = function(){ console.log("I'm from Global"); }
paloma/namespace/_locals.js
contains:
locals.namespaceMethod = function(){ console.log("I'm from Namespace"); }
locals.anotherNamespaceMethod = function(){ console.log("I'm also from Namespace"); }
paloma/namespace/controller/_locals.js
contains:
locals.controllerMethod = function(){ console.log("I'm from Controller"); }
locals.anotherNamespacedMethod = function(){ console.log("Override!"); }; // Overrides namespace local
Since controller
is under the global _local.js
and namespace _local.js
it automatically inherits all their locals.
So you can do something like this inside the controller callback files (or filter files):
Paloma.callbacks['namespace/controller']['action'] = function(params){
_l.controllerMethod(); // outputs "I'm from Controller"
_l.namespacedMethod(); // outputs "I'm from Namespace"
_l.globalMethod(); // outputs "I'm from Global"
_l.anotherNamespacedMethod(); // outputs "Override!"
};
Callback Chains
Callback chains are created after a redirect action. The chain will continue to increase its length until a render action is detected.
Example:
def first_action
redirect_to second_action_path
end
def second_action
redirect_to third_action_path
end
def third_action
render :template => 'third_action_view'
end
A request for first_action
will lead to 2 redirects until it reaches the third_action
and renders a result on the browser. When the third_action
renders its response, Paloma will execute the callbacks for all the 3 actions.
The order of execution will be [controllers]/first_action
first, then [controllers]/second_action
, and finally [controllers]/third_action
.
Gotchas
- Callbacks will not be executed if the response is
js
,json
,xml
or any other format excepthtml
. This will not work:render "something.js.erb"
Credits
- Karl Bryan Paragua
- Bianca Camille Esmero