2013-10-12 08:48:18 -04:00
# Paloma
## What's New?
2013-10-12 09:12:10 -04:00
Paloma (version 3) is almost a complete rewrite of the old version.
2013-10-12 08:48:18 -04:00
It is now simpler and it also gives more flexibility to the developers. Simplicity and flexibility are achieved by replacing the old callback thingy paradigm by a combination of `Router` and `Controller` components.
All the generator shits are also gone. So developers need not to follow specific folder structure or file name. And since there's no generated files or whatsoever, you can now code in vanilla javascript or **coffescript** ! Yay!
2013-10-12 08:55:14 -04:00
**Basically, Paloma now provides a Controller for your javascript!**
2013-10-12 08:48:18 -04:00
## Advantages
* Choose what specific javascript code to run per page.
2013-01-25 22:08:50 -05:00
* Easily make ruby variables available on your javascript files.
2012-12-19 02:56:52 -05:00
2013-10-12 08:55:14 -04:00
2013-10-12 08:48:18 -04:00
## Quick Example
2012-12-19 02:56:52 -05:00
2013-10-12 08:55:14 -04:00
Paloma controller.
2012-12-19 02:56:52 -05:00
```javascript
2013-10-12 09:05:06 -04:00
var UsersController = Paloma.controller('Users');
2013-10-12 08:55:14 -04:00
// Executes when Rails User#new is rendered.
2013-10-12 09:05:06 -04:00
UsersController.prototype.new = function(){
2013-10-12 08:55:14 -04:00
alert('Hello Sexy User!' );
};
2012-12-19 02:56:52 -05:00
```
The Rails controller `app/controllers/users_controller.rb` :
```ruby
def UsersController < ApplicationController
def new
@user = User.new
end
end
```
That's it! Simply Sexy!
Minimum Requirements
-
* jQuery 1.7 or higher
* Rails 3.1 or higher
2012-12-18 04:47:24 -05:00
2013-10-12 08:55:14 -04:00
## Install
2012-12-19 02:56:52 -05:00
Without bundler:
```
sudo gem install paloma
```
2012-12-18 23:16:11 -05:00
2012-12-19 02:56:52 -05:00
With bundler, add this to your Gemfile:
```
2012-12-19 20:49:35 -05:00
gem 'paloma'
2012-12-19 02:56:52 -05:00
```
2012-12-18 23:16:11 -05:00
2012-12-19 20:49:35 -05:00
Require `paloma` in your `application.js` :
```
//= require paloma
```
2013-10-12 09:05:06 -04:00
2013-10-12 09:12:10 -04:00
## Router
2013-10-12 09:05:06 -04:00
Router is responsible for mapping Rails controller/action to its equivalent Paloma controller/action.
By default all Rails controller/action will be mapped with a Paloma controller/action with the same resource name (controller name without the `Controller` suffix).
Example:
* Response from `UsersController#new` will be mapped to `Users` Paloma controller and execute its `new` method.
2013-10-12 09:12:10 -04:00
### Mapping to other Controller
2013-10-12 09:05:06 -04:00
2013-10-12 09:12:10 -04:00
If you want to use a different Paloma Controller for a specific Rails controller, you can do the following:
```javascript
// Instead of mapping Rails UsersController to Paloma Users
// it will be mapped to AdminUsers.
Paloma.router.resource('Users', {controller: 'AdminUsers'});
```
### Redirecting
You can also redirect an action if you want it to be handled by a different method.
```javascript
// Instead of executing Paloma's `Users#new` it will execute
// `Registrations#signup` .
Paloma.router.redirect('Users#new', {to: 'Registrations#signUp');
```
2013-10-12 09:05:06 -04:00
# Controller
2013-10-12 08:55:14 -04:00
# Advanced Callbacks
2012-12-19 05:19:48 -05:00
-
2013-03-02 11:02:13 -05:00
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.
2012-12-19 05:19:48 -05:00
2013-03-02 10:11:46 -05:00
You can manipulate callback behavior by using the `js` command before the `render` or `redirect_to` command in your controllers.
2012-12-19 05:19:48 -05:00
1. Preventing the Callback to execute.
```ruby
def destroy
user = User.find params[:id]
user.destroy
2013-03-02 10:11:46 -05:00
js false
2012-12-19 05:19:48 -05:00
end
```
2013-03-02 11:02:13 -05:00
`callbacks["controller"]["destroy"]` will not be executed.
2012-12-19 05:19:48 -05:00
2. Using other action's callback from the same controller.
```ruby
def edit
@user = User.find params[:id]
2013-03-02 10:11:46 -05:00
js :new
2012-12-19 05:19:48 -05:00
end
```
2013-03-02 11:02:13 -05:00
This will execute `callback["controllers"]["new"]` instead of `callback["controllers"]["edit"]` .
2012-12-19 05:19:48 -05:00
3. Using other action's callback from other controller.
```ruby
def index
@users = User.all
2013-03-02 10:11:46 -05:00
js :controller => 'clients', :action => 'index'
2012-12-19 05:19:48 -05:00
end
```
2013-03-02 11:02:13 -05:00
This will execute `callbacks["clients"]["index"]` instead of `callbacks["controllers"]["index"]` .
2012-12-19 05:19:48 -05:00
2013-01-18 21:46:26 -05:00
4. Using other action's callback from a namespaced controller.
```ruby
class UsersController < ApplicationController
def destroy
@user = User.find params[:id]
@user .destroy
2013-03-02 10:11:46 -05:00
js :controller => 'admin/users', :action => :destroy
2013-01-18 21:46:26 -05:00
end
end
```
2013-03-02 11:02:13 -05:00
This will execute `callbacks["admin/users"]["destroy"]` instead of `callbacks["users"]["destroy"]` .
2013-01-19 08:12:40 -05:00
2012-12-19 05:28:03 -05:00
Passing Parameters
-
2013-03-02 10:11:46 -05:00
You can also pass parameters to the callback by passing a `:params` key to `js` . The passed parameters
2012-12-19 05:28:03 -05:00
will be available on the callback by the `params` object.
**Example:**
`users_controller.rb`
```ruby
def destroy
user = User.find params[:id]
user.destroy
2013-03-02 10:11:46 -05:00
js :params => {:user_id => params[:id]}
2012-12-19 05:28:03 -05:00
end
```
`/paloma/users/destroy.js`
```javascript
2013-03-02 11:02:13 -05:00
Paloma.callbacks['users']['destroy'] = function(params){
2012-12-19 05:28:03 -05:00
var id = params['user_id'];
alert('User ' + id + ' deleted.');
};
```
2012-12-19 05:36:54 -05:00
2013-03-08 23:55:52 -05:00
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.
2013-03-04 03:09:04 -05:00
## 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
```javascript
filter.as('filter name').before_all().perform(function(params){
alert("I'm a before filter!");
});
2013-03-09 21:27:31 -05:00
filter.as('another filter').after_all().perform(function(params){
2013-03-04 03:09:04 -05:00
alert("I'm an after filter");
});
```
### Specify Actions To Filter
1. For all actions.
```javascript
filter.as('name').before_all()
filter.as('name').after_all()
filter.as('name').around_all()
```
2. Only for specific action/s.
```javascript
filter.as('name').before('new', 'edit', 'update')
filter.as('name').after('destroy')
filter.as('name').around('show')
```
3. Except for specific action/s.
```javascript
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.
2013-03-04 03:22:48 -05:00
### 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` :
2013-03-08 23:01:55 -05:00
```javascript
filter.as('filter name').before('new').perform(function(params){
_x.sharedVariable = "Sexy Paloma";
});
```
2013-03-04 03:22:48 -05:00
on `new.js` :
2013-03-08 23:01:55 -05:00
```javascript
Paloma.callbacks['controller']['new'] = function(params){
alert(_x.sharedVariable); // outputs "Sexy Paloma";
});
```
2013-03-04 03:22:48 -05:00
2013-03-09 08:08:00 -05:00
### 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.
```javascript
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'.
```
2013-03-02 11:15:44 -05:00
##Locals
2013-03-02 11:02:13 -05:00
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).
2012-12-19 05:54:19 -05:00
2013-03-02 11:02:13 -05:00
The motivation of Locals is to organize helper methods and helper variables within a namespace or controller.
2012-12-19 05:54:19 -05:00
2013-03-02 11:07:45 -05:00
1. **Application-wide Locals**
2013-03-02 11:02:13 -05:00
Defined on `paloma/_locals.js` .
This contains methods and variables that are intended to be available globally.
2013-01-18 21:46:26 -05:00
2013-03-02 11:07:45 -05:00
2. **Namespace-wide Locals**
2013-03-02 11:02:13 -05:00
Defiend on `paloma/namespace/_locals.js` .
This contains methods and variables that are intended to be available on the specific namespace only.
2013-03-02 11:07:45 -05:00
3. **Controller-wide Locals**
2013-03-02 11:02:13 -05:00
Defined on `paloma/controller/_locals.js` or `paloma/namespace/controller/_locals.js` .
This contains methods and variables that are intended to be available on the specific controller only.
2012-12-19 05:54:19 -05:00
2013-03-02 11:02:13 -05:00
2013-03-02 11:15:44 -05:00
###Creating Locals
2013-03-02 11:07:45 -05:00
Locals can be created using the `locals` object inside `_filters.js` file.
2013-03-02 11:02:13 -05:00
**Example:**
2013-03-02 11:07:45 -05:00
```javascript
locals.helperMethod = function(){
return "Hello World";
};
locals.helperVariable = "WOW!";
```
2013-01-18 21:46:26 -05:00
2013-03-02 11:15:44 -05:00
###Accessing Locals
2013-03-02 11:02:13 -05:00
Locals can be accessed in your filter and callback files using the `_l` object.
2012-12-19 05:54:19 -05:00
2013-03-02 11:02:13 -05:00
**Example**
2013-03-02 11:07:45 -05:00
```javascript
Paloma.callbacks['users']['new'] = function(params){
alert("Hello Sexy User");
_l.helperMethod();
console.log(_l.helperVariable);
};
```
2013-03-02 11:02:13 -05:00
2013-03-02 11:15:44 -05:00
###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` .
2013-03-02 11:33:26 -05:00
**Example**
2013-03-02 11:15:44 -05:00
```javascript
Paloma.callbacks['users']['new'] = function(params){
_L.otherController.helperMethod(); // accessing local helperMethod() of the otherController
2013-03-02 11:17:59 -05:00
_L['otherController'].helperVariable;
2013-03-02 11:15:44 -05:00
}
```
2013-03-02 11:33:26 -05:00
###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**
2013-03-02 11:36:36 -05:00
`paloma/_locals.js` contains:
```javascript
locals.globalMethod = function(){ console.log("I'm from Global"); }
```
2013-03-02 11:33:26 -05:00
2013-03-02 11:36:36 -05:00
`paloma/namespace/_locals.js` contains:
```javascript
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:
```javascript
locals.controllerMethod = function(){ console.log("I'm from Controller"); }
locals.anotherNamespacedMethod = function(){ console.log("Override!"); }; // Overrides namespace local
```
2013-03-02 11:33:26 -05:00
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):
2013-03-02 11:36:36 -05:00
```javascript
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!"
};
```
2013-03-02 11:33:26 -05:00
2012-12-19 05:36:54 -05:00
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:**
```ruby
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.
2012-12-19 20:49:35 -05:00
The order of execution will be `[controllers]/first_action` first, then `[controllers]/second_action` , and finally `[controllers]/third_action` .
2012-12-19 05:39:30 -05:00
Gotchas
-
* Callbacks will not be executed if the response is `js` , `json` , `xml` or any other format except `html` .
This will not work: `render "something.js.erb"`
2012-12-21 15:10:43 -05:00
Credits
-
* [Karl Bryan Paragua ](http://www.daftcoder.com "Daftcoder.com" )
* Bianca Camille Esmero