mirror of
https://github.com/kbparagua/paloma
synced 2023-03-27 23:21:17 -04:00
Merge branch 'master' of github.com:kbparagua/paloma
This commit is contained in:
commit
2b23b1e43a
20 changed files with 242 additions and 64 deletions
135
README.md
135
README.md
|
@ -1,55 +1,106 @@
|
|||
paloma
|
||||
Paloma
|
||||
======
|
||||
Paloma provides a sexy way to organize javascript files using Rails' asset pipeline.
|
||||
It adds the capability to execute specific javascript code after rendering the controller's response.
|
||||
|
||||
Javascript Callback Manager for Rails 3
|
||||
Advantages
|
||||
-
|
||||
* Javascript files are organized per controller just like app/views folder of Rails.
|
||||
* Javascript file per controller's action.
|
||||
* The ability to choose what specific javascript code to run on a specific action.
|
||||
|
||||
Quick Example
|
||||
-
|
||||
The javascript callback file `paloma/users/new.js`:
|
||||
|
||||
```javascript
|
||||
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`:
|
||||
|
||||
```ruby
|
||||
def UsersController < ApplicationController
|
||||
def new
|
||||
@user = User.new
|
||||
# No special function to call, the javascript callback will be executed automatically
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
That's it! Simply Sexy!
|
||||
|
||||
Minimum Requirements
|
||||
-
|
||||
* jQuery 1.7 or higher
|
||||
* Rails 3.1 or higher
|
||||
|
||||
|
||||
Install
|
||||
-------
|
||||
Add the following line to the Gemfile:
|
||||
|
||||
gem 'paloma'
|
||||
|
||||
-
|
||||
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
|
||||
```
|
||||
|
||||
Directory Structure
|
||||
-
|
||||
`paloma` folder contains the javascript callbacks.
|
||||
|
||||
* paloma
|
||||
* [controllers]
|
||||
* [action].js
|
||||
* [other_action].js
|
||||
* [other_controllers]
|
||||
* [action].js
|
||||
* [other_action].js
|
||||
* [more_action].js
|
||||
|
||||
Usage
|
||||
-----
|
||||
>*On the first run of either of the two commands mentioned below, the __callbacks__ folder will be generated in __app/assets/javascripts/__. Inside the callbacks folder, __index.js__ will also be created.*
|
||||
-
|
||||
1. Generate a controller folder containing its required files:
|
||||
```
|
||||
rails g paloma:add [controllers]
|
||||
```
|
||||
**Example:**
|
||||
```
|
||||
rails g paloma:add users
|
||||
```
|
||||
|
||||
The following are the commands which can be executed in the terminal to generate files needed for the callbacks:
|
||||
|
||||
rails g paloma:add <controller_name>
|
||||
|
||||
>*Execute the command above to generate a folder, named as __\<controller_name\>__ which will be the container of all the callbacks that will be used within that controller. Inside this folder, __callbacks.js__ will also be generated.*
|
||||
|
||||
rails g paloma:add <controller_name>/<action_name>
|
||||
|
||||
> *This command allows the user to create the file __\<action_name\>.js__ under the __\<controller_name\> folder__.*
|
||||
**Generates:**
|
||||
* /paloma
|
||||
* /users
|
||||
|
||||
|
||||
Generated Files
|
||||
---------------
|
||||
###index.js
|
||||
Contains code for requiring all callbacks of all folders and is automatically updated when new folders and callback.js files are created
|
||||
2. Generate a callback file for a controller's action:
|
||||
```
|
||||
rails g paloma:add [controllers]/[action]
|
||||
```
|
||||
**Example:**
|
||||
```
|
||||
rails g paloma:add users/new
|
||||
```
|
||||
|
||||
# app/assets/javascripts/callbacks/index.js
|
||||
|
||||
window.Paloma = {callbacks:{}};
|
||||
//= require ./<controller_name>/callbacks
|
||||
**Generates:**
|
||||
* /paloma
|
||||
* /users
|
||||
* new.js
|
||||
|
||||
###callbacks.js
|
||||
Contains code for requiring all callbacks under the same folder <controller_name>
|
||||
|
||||
# app/assets/javascripts/callbacks/<controller_name>/callbacks.js
|
||||
|
||||
//= require_tree .
|
||||
|
||||
###\<action_name\>.js
|
||||
Actual code to be executed when callback is called
|
||||
|
||||
# app/assets/javascripts/callbacks/<controller_name>/<action_name>.js
|
||||
|
||||
Paloma.callbacks['<controller_name>/<action_name>'] = function(params){
|
||||
...
|
||||
//put your code here
|
||||
...
|
||||
};
|
||||
**Note:** You can directly run `rails g paloma:add [controllers]/[action]` even the controller folder is not yet
|
||||
existing on `paloma` folder. It will be created automatically.
|
||||
|
|
|
@ -2,19 +2,32 @@
|
|||
|
||||
<div class="callback-details" id="callback-details-<%= callback_details_id %>">
|
||||
<script type="text/javascript">
|
||||
var id = "callback-details-<%= callback_details_id %>";
|
||||
$(".callback-details[id!=" + id + "]").remove(); // Remove any callback details if any
|
||||
var id = "callback-details-<%= callback_details_id %>",
|
||||
callbacks = [];
|
||||
|
||||
// Remove any callback details if any
|
||||
$('.callback-details[id!=" + id + "]').remove();
|
||||
|
||||
|
||||
// Convert callbacks to javascript variable
|
||||
<% callbacks.each do |callback| %>
|
||||
var params = eval($('<div/>').html("(<%= callback[:params].to_json %>)").text()),
|
||||
callbackName = "<%= callback[:name] %>",
|
||||
callback = Paloma.callbacks[callbackName];
|
||||
|
||||
console.log("Paloma: Fetching [" + callbackName + "]");
|
||||
callbacks.push({
|
||||
name: '<%= callback[:name] %>',
|
||||
params: eval($('<div/>').html("(<%= callback[:params].to_json %>)").text())
|
||||
});
|
||||
<% end %>
|
||||
|
||||
|
||||
// Run Callbacks
|
||||
for (var i = 0, len = callbacks.length; i < len; i++){
|
||||
var callback = callbacks[i],
|
||||
callbackFunction = Paloma.callbacks[callback.name];
|
||||
|
||||
console.log("Paloma: Fetching [" + callback.name + "]");
|
||||
if (callback != undefined){
|
||||
console.log("Paloma: Calling [" + callbackName + "]");
|
||||
$(document).ready(function(e){ callback(params); });
|
||||
console.log("Paloma: Calling [" + callback.name + "]");
|
||||
callbackFunction(callback.params);
|
||||
}
|
||||
<% end %>
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
|
|
@ -19,7 +19,7 @@ module Paloma
|
|||
|
||||
def update_callback
|
||||
add_to_callbacks @__callback__, @__js_params__
|
||||
|
||||
|
||||
response_body[0] += view_context.render(
|
||||
:partial => "paloma/callback_hook",
|
||||
:locals => {:callbacks => session[:callbacks]})
|
||||
|
@ -30,6 +30,7 @@ module Paloma
|
|||
|
||||
|
||||
def add_to_callbacks name, params
|
||||
return true if name.nil?
|
||||
session[:callbacks] ||= []
|
||||
session[:callbacks].push({:name => name, :params => params})
|
||||
end
|
||||
|
|
|
@ -1,11 +1,65 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Rendering HTML response of controller's action ", :type => :feature do
|
||||
feature 'Callbacks' do
|
||||
|
||||
it "executes the correct javascript callback" do
|
||||
visit new_article_path
|
||||
it 'should execute articles/new callback', :js => true do
|
||||
visit new_article_path
|
||||
page.has_selector?('#from-articles-new-callback').should == true
|
||||
end
|
||||
|
||||
|
||||
it 'should execute callbacks for articles/create and articles/show', :js => true do
|
||||
visit new_article_path
|
||||
|
||||
page.has_css?('.callback-details').should == true
|
||||
fill_in 'article[title]', :with => 'sexy paloma'
|
||||
fill_in 'article[body]', :with => 'sexy paloma body'
|
||||
click_button 'Save'
|
||||
|
||||
page.has_selector?('#from-articles-create-callback').should == true
|
||||
page.has_selector?('#from-articles-show-callback').should == true
|
||||
end
|
||||
|
||||
|
||||
it 'should execute "new" callback instead of "create" after failed save', :js => true do
|
||||
visit new_article_path
|
||||
|
||||
fill_in 'article[body]', :with => 'sexy paloma body'
|
||||
click_button 'Save'
|
||||
|
||||
page.has_selector?('#from-articles-create-callback').should == false
|
||||
page.has_selector?('#from-articles-new-callback').should == true
|
||||
end
|
||||
|
||||
|
||||
it 'should have an access on the passed parameters on js_callback', :js => true do
|
||||
1.upto(30) do |i|
|
||||
Article.create :title => "Sexy Paloma #{i}", :body => "Sexy Body"
|
||||
end
|
||||
|
||||
visit articles_path
|
||||
page.has_selector?('#article-count-30').should == true
|
||||
end
|
||||
|
||||
|
||||
it 'should not execute articles/update callback', :js => true do
|
||||
article = Article.create :title => "Sexy Paloma Baby!", :body => "OMG"
|
||||
|
||||
visit edit_article_path(article)
|
||||
fill_in 'article[body]', :with => 'Updated Body'
|
||||
click_button 'Save'
|
||||
|
||||
page.has_selector?('#from-articles-update-callback').should == false
|
||||
page.has_selector?('#from-articles-show-callback').should == true
|
||||
end
|
||||
|
||||
|
||||
it 'should execute articles/edit callback after failed update', :js => true do
|
||||
article = Article.create :title => 'Sexy Paloma Baby!', :body => 'Yeah'
|
||||
|
||||
visit edit_article_path(article)
|
||||
fill_in 'article[title]', :with => ''
|
||||
click_button 'Save'
|
||||
|
||||
page.has_selector?('#from-articles-edit-callback').should == true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//= require jquery.js
|
||||
//= require jquery_ujs.js
|
||||
//= require_tree .
|
||||
//= require paloma
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Paloma.callbacks['articles/create'] = function(params){
|
||||
$('body').append($("<div id='from-articles-create-callback'></div>"));
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
Paloma.callbacks['articles/edit'] = function(params){
|
||||
$('body').append($("<div id='from-articles-edit-callback'></div>"));
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
Paloma.callbacks['articles/index'] = function(params){
|
||||
$('body').append($("<div id='article-count-" + params['article_count'] + "'></div>"));
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
Paloma.callbacks['articles/show'] = function(params){
|
||||
$('body').append($("<div id='from-articles-show-callback'></div>"));
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
Paloma.callbacks['articles/update'] = function(params){
|
||||
$('body').append($("<div id='from-articles-update-callback'></div>"));
|
||||
};
|
|
@ -1,3 +1,2 @@
|
|||
window.Paloma = {callbacks:{}};
|
||||
|
||||
//= require ./paloma
|
||||
//= require ./articles/callbacks
|
1
spec/sample_app/app/assets/javascripts/paloma/paloma.js
Normal file
1
spec/sample_app/app/assets/javascripts/paloma/paloma.js
Normal file
|
@ -0,0 +1 @@
|
|||
window.Paloma = {callbacks:{}};
|
5
spec/sample_app/app/views/articles/index.html.erb
Normal file
5
spec/sample_app/app/views/articles/index.html.erb
Normal file
|
@ -0,0 +1,5 @@
|
|||
<% @articles.each do |article| %>
|
||||
<div>
|
||||
<%= article.title %>: <%= article.body %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -5,5 +5,5 @@
|
|||
Body:
|
||||
<%= f.text_area :body %>
|
||||
|
||||
<%= f.submit %>
|
||||
<%= f.submit :Save %>
|
||||
<% end %>
|
||||
|
|
|
@ -5,6 +5,12 @@ end
|
|||
|
||||
class ArticlesController < ApplicationController
|
||||
|
||||
def index
|
||||
@articles = Article.all
|
||||
js_callback :params => {:article_count => @articles.size}
|
||||
end
|
||||
|
||||
|
||||
def show
|
||||
@article = Article.find params[:id]
|
||||
end
|
||||
|
@ -17,11 +23,30 @@ class ArticlesController < ApplicationController
|
|||
|
||||
def create
|
||||
@article = Article.new params[:article]
|
||||
|
||||
|
||||
if @article.save
|
||||
redirect_to @article
|
||||
else
|
||||
js_callback :new
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
@article = Article.find params[:id]
|
||||
render :new
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
@article = Article.find params[:id]
|
||||
|
||||
if @article.update_attributes params[:article]
|
||||
js_callback false
|
||||
redirect_to @article
|
||||
else
|
||||
js_callback :controller => :articles, :action => :edit
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
# ActiveRecord Configuration
|
||||
# We are not using :memory: database to handle javascript requests on controller
|
||||
require 'active_record/railtie'
|
||||
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
||||
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => 'paloma_test'}}
|
||||
ActiveRecord::Base.establish_connection('test')
|
||||
|
||||
|
||||
# Model
|
||||
class Article < ActiveRecord::Base
|
||||
attr_accessible :title, :body
|
||||
|
||||
validates_presence_of :title
|
||||
end
|
||||
|
||||
|
||||
# Migration
|
||||
class CreateArticles < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :articles do |t|
|
||||
create_table :articles, :force => true do |t|
|
||||
t.string :title
|
||||
t.string :body
|
||||
end
|
||||
|
|
BIN
spec/sample_app/paloma_test
Normal file
BIN
spec/sample_app/paloma_test
Normal file
Binary file not shown.
|
@ -8,3 +8,14 @@ require 'rspec/rails'
|
|||
|
||||
require 'capybara/rspec'
|
||||
require 'database_cleaner'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.before :each do
|
||||
DatabaseCleaner.strategy = :truncation
|
||||
DatabaseCleaner.start
|
||||
end
|
||||
|
||||
config.after do
|
||||
DatabaseCleaner.clean
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue