diff --git a/README.md b/README.md index 3c7f4ad..e1ef6d4 100644 --- a/README.md +++ b/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 - ->*Execute the command above to generate a folder, named as __\__ 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 / - -> *This command allows the user to create the file __\.js__ under the __\ 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 .//callbacks + **Generates:** + * /paloma + * /users + * new.js -###callbacks.js -Contains code for requiring all callbacks under the same folder - # app/assets/javascripts/callbacks//callbacks.js - - //= require_tree . - -###\.js -Actual code to be executed when callback is called - - # app/assets/javascripts/callbacks//.js - - Paloma.callbacks['/'] = 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. diff --git a/app/views/paloma/_callback_hook.html.erb b/app/views/paloma/_callback_hook.html.erb index 6d27c48..e5d30a2 100644 --- a/app/views/paloma/_callback_hook.html.erb +++ b/app/views/paloma/_callback_hook.html.erb @@ -2,19 +2,32 @@
diff --git a/lib/paloma/action_controller_filters.rb b/lib/paloma/action_controller_filters.rb index d38b2ed..6ba529a 100644 --- a/lib/paloma/action_controller_filters.rb +++ b/lib/paloma/action_controller_filters.rb @@ -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 diff --git a/spec/callback_spec.rb b/spec/callback_spec.rb index 914d980..598a029 100644 --- a/spec/callback_spec.rb +++ b/spec/callback_spec.rb @@ -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 diff --git a/spec/sample_app/app/assets/javascripts/application.js b/spec/sample_app/app/assets/javascripts/application.js index f376821..eca5e93 100644 --- a/spec/sample_app/app/assets/javascripts/application.js +++ b/spec/sample_app/app/assets/javascripts/application.js @@ -1,4 +1,4 @@ // //= require jquery.js //= require jquery_ujs.js -//= require_tree . +//= require paloma diff --git a/spec/sample_app/app/assets/javascripts/callbacks/articles/callbacks.js b/spec/sample_app/app/assets/javascripts/paloma/articles/callbacks.js similarity index 100% rename from spec/sample_app/app/assets/javascripts/callbacks/articles/callbacks.js rename to spec/sample_app/app/assets/javascripts/paloma/articles/callbacks.js diff --git a/spec/sample_app/app/assets/javascripts/paloma/articles/create.js b/spec/sample_app/app/assets/javascripts/paloma/articles/create.js new file mode 100644 index 0000000..209e53e --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/articles/create.js @@ -0,0 +1,3 @@ +Paloma.callbacks['articles/create'] = function(params){ + $('body').append($("
")); +}; diff --git a/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js b/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js new file mode 100644 index 0000000..a1cecf8 --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js @@ -0,0 +1,3 @@ +Paloma.callbacks['articles/edit'] = function(params){ + $('body').append($("
")); +}; diff --git a/spec/sample_app/app/assets/javascripts/paloma/articles/index.js b/spec/sample_app/app/assets/javascripts/paloma/articles/index.js new file mode 100644 index 0000000..4b541d6 --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/articles/index.js @@ -0,0 +1,3 @@ +Paloma.callbacks['articles/index'] = function(params){ + $('body').append($("
")); +}; diff --git a/spec/sample_app/app/assets/javascripts/callbacks/articles/new.js b/spec/sample_app/app/assets/javascripts/paloma/articles/new.js similarity index 100% rename from spec/sample_app/app/assets/javascripts/callbacks/articles/new.js rename to spec/sample_app/app/assets/javascripts/paloma/articles/new.js diff --git a/spec/sample_app/app/assets/javascripts/paloma/articles/show.js b/spec/sample_app/app/assets/javascripts/paloma/articles/show.js new file mode 100644 index 0000000..17ea301 --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/articles/show.js @@ -0,0 +1,3 @@ +Paloma.callbacks['articles/show'] = function(params){ + $('body').append($("
")); +}; diff --git a/spec/sample_app/app/assets/javascripts/paloma/articles/update.js b/spec/sample_app/app/assets/javascripts/paloma/articles/update.js new file mode 100644 index 0000000..fe61bf3 --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/articles/update.js @@ -0,0 +1,3 @@ +Paloma.callbacks['articles/update'] = function(params){ + $('body').append($("
")); +}; diff --git a/spec/sample_app/app/assets/javascripts/callbacks/index.js b/spec/sample_app/app/assets/javascripts/paloma/index.js similarity index 50% rename from spec/sample_app/app/assets/javascripts/callbacks/index.js rename to spec/sample_app/app/assets/javascripts/paloma/index.js index 3d68338..e8ec454 100644 --- a/spec/sample_app/app/assets/javascripts/callbacks/index.js +++ b/spec/sample_app/app/assets/javascripts/paloma/index.js @@ -1,3 +1,2 @@ -window.Paloma = {callbacks:{}}; - +//= require ./paloma //= require ./articles/callbacks diff --git a/spec/sample_app/app/assets/javascripts/paloma/paloma.js b/spec/sample_app/app/assets/javascripts/paloma/paloma.js new file mode 100644 index 0000000..5de4323 --- /dev/null +++ b/spec/sample_app/app/assets/javascripts/paloma/paloma.js @@ -0,0 +1 @@ +window.Paloma = {callbacks:{}}; diff --git a/spec/sample_app/app/views/articles/index.html.erb b/spec/sample_app/app/views/articles/index.html.erb new file mode 100644 index 0000000..381cdf9 --- /dev/null +++ b/spec/sample_app/app/views/articles/index.html.erb @@ -0,0 +1,5 @@ +<% @articles.each do |article| %> +
+ <%= article.title %>: <%= article.body %> +
+<% end %> diff --git a/spec/sample_app/app/views/articles/new.html.erb b/spec/sample_app/app/views/articles/new.html.erb index 1785591..fd57f42 100644 --- a/spec/sample_app/app/views/articles/new.html.erb +++ b/spec/sample_app/app/views/articles/new.html.erb @@ -5,5 +5,5 @@ Body: <%= f.text_area :body %> - <%= f.submit %> + <%= f.submit :Save %> <% end %> diff --git a/spec/sample_app/controllers.rb b/spec/sample_app/controllers.rb index e3aba80..34cca04 100644 --- a/spec/sample_app/controllers.rb +++ b/spec/sample_app/controllers.rb @@ -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 diff --git a/spec/sample_app/model.rb b/spec/sample_app/model.rb index ccc486a..909d6d6 100644 --- a/spec/sample_app/model.rb +++ b/spec/sample_app/model.rb @@ -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 diff --git a/spec/sample_app/paloma_test b/spec/sample_app/paloma_test new file mode 100644 index 0000000..c51a094 Binary files /dev/null and b/spec/sample_app/paloma_test differ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4c6403e..20899d9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -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