Skip to content

Instantly share code, notes, and snippets.

@simaob
Created November 6, 2011 19:40
Show Gist options
  • Save simaob/1343364 to your computer and use it in GitHub Desktop.
Save simaob/1343364 to your computer and use it in GitHub Desktop.
Ordering records through index page record with AJAX (powered by jQuery) in a Ruby on Rails 3.1 App
<%#PATH: app/views/products/ %>
<% if !product.first? %>
<%= link_to image_tag("ordering_icons/up.gif", :alt => "up", :title => "Move up"), move_up_product_path(product), :method => :put, :remote => true %>
<% end %>
<% if !product.last? %>
<%= link_to image_tag("ordering_icons/down.gif", :alt => "down", :title => "Move down"), move_down_product_path(product), :method => :put, :remote => true %>
<% end %>
#PATH: db/migrate/
class AddSortIndexToProducts < ActiveRecord::Migration
def self.up
add_column :products, :sort_index, :integer
end
def self.down
remove_column :products, :sort_index
end
end
<%#PATH: app/views/products/ %>
<h1>Products</h1>
<p><%= link_to "New Product", new_product_path %></p>
<table>
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<% @products.each do |product| %>
<tr id="product_#{product.id}">
<td id="product_#{product.id}_sort">
<%= render :partial => "ordering", :locals => {:product => product} %>
</td>
<td><%= product.name %></td>
<td><%= product.price %></td>
</tr>
<% end %>
</tbody>
</thead>
<%#PATH: app/views/products/ %>
$(function(){
<% if @success %>
$("#product_<%[email protected]%>").next().after($("#product_<%[email protected]%>"));
$("#product_<%[email protected]%>_sort").html("<%= escape_javascript(render :partial => "ordering", :locals => {:product => @product} ) %>");
$("#product_<%[email protected]%>_sort").html("<%= escape_javascript(render :partial => "ordering", :locals => {:product => @product.previous} ) %>");
<% else %>
alert("It wasn't possible to move the product. The last product can't be moved further down...")
<% end %>
});
<%#PATH: app/views/products/ %>
$(function(){
<% if @success %>
$("#product_<%[email protected]%>").prev().before($("#product_<%[email protected]%>"));
$("#product_<%[email protected]%>_sort").html("<%= escape_javascript(render :partial => "ordering", :locals => {:product => @product} ) %>");
$("#product_<%[email protected]%>_sort").html("<%= escape_javascript(render :partial => "ordering", :locals => {:product => @product.next} ) %>");
<% else %>
alert("It wasn't possible to move the product. The first product can't be moved further up...")
<% end %>
});
#PATH: app/models/
class Product < ActiveRecord::Base
attr_accessible :sort_index, :name, :price
before_create :set_sort_index
def last?
self.sort_index == Product.maximum('sort_index')
end
def first?
self.sort_index == 0
end
def next
Product.where(:sort_index => (self.sort_index+1)).first
end
def previous
Product.where(:sort_index => (self.sort_index-1)).first
end
def move_up
switched = Product.where(:sort_index => (self.sort_index - 1)).first
return false if !switched
switched.sort_index = self.sort_index
self.sort_index -= 1
switched.save
self.save
end
def move_down
switched = Product.where(:sort_index => (self.sort_index + 1)).first
return false if !switched
switched.sort_index = self.sort_index
self.sort_index += 1
switched.save
self.save
end
private
def set_sort_index
current_max_index = Product.maximum('sort_index') || -1
self.sort_index = current_max_index+1
end
end
#PATH: spec/models/
require 'spec_helper'
describe 'setting and updating product sort_index value' do
it "should set the sort_index value to zero for the first product, and then increment the sort_index value for the following records" do
#no products
Product.all.count.should == 0
#create a product
product = Product.create
Product.all.count.should == 1
product.sort_index.should == 0
#create another product
product1 = Product.create
Product.all.count.should == 2
product1.sort_index.should == 1
#create another product
product2 = Product.create
Product.all.count.should == 3
product2.sort_index.should == 2
end
it "should respond true to first? and last? if there's only a product and it has sort_index value of 0" do
product = Product.create
product.first?.should == true
product.last?.should == true
product.sort_index.should == 0
end
it "responds true to the method first? and false to the method last? when called on a product with sort_index 0, and when there is a second product with sort_index value 1" do
product = Product.create
product1 = Product.create
product.first?.should == true
product.last?.should == false
product.sort_index.should == 0
product1.first?.should == false
product1.last?.should == true
product1.sort_index.should == 1
end
it "responds false to both first? and last? when called on a product with sort_index 1, and there are other designations of the same level with sort_index 0 and 2" do
product = Product.create
product1 = Product.create
product2 = Product.create
product.first?.should == true
product.last?.should == false
product.sort_index.should == 0
product1.first?.should == false
product1.last?.should == false
product1.sort_index.should == 1
product2.first?.should == false
product2.last?.should == true
product2.sort_index.should == 2
end
it "should return the product with sort_index+1 when calling next on a product. it should return nil if there isn't another product" do
product = Product.create
product.next.should == nil
product.previous.should == nil
product1 = Product.create
product.next.should == product1
product1.sort_index.should == product.sort_index+1
product1.previous.should == product
end
#Order hierarchy: 0, 1, 2, ...
it "should increase the sort_index of a product when moving it down, and increase it when moving up, updating the other products accordingly" do
product = Product.create
product1 = Product.create
product2 = Product.create
product.sort_index.should == 0
product1.sort_index.should == 1
product2.sort_index.should == 2
product.move_down
product.reload
product1.reload
product2.reload
product.sort_index.should == 1
product1.sort_index.should == 0
product2.sort_index.should == 2
product.move_down
product.reload
product1.reload
product2.reload
product.sort_index.should == 2
product1.sort_index.should == 0
product2.sort_index.should == 1
product.move_down
product.reload
product1.reload
product2.reload
product.sort_index.should == 2
product1.sort_index.should == 0
product2.sort_index.should == 1
product.move_up
product.reload
product1.reload
product2.reload
product.sort_index.should == 1
product1.sort_index.should == 0
product2.sort_index.should == 2
product.move_up
product.reload
product1.reload
product2.reload
product.sort_index.should == 0
product1.sort_index.should == 1
product2.sort_index.should == 2
product.move_up
product.reload
product1.reload
product2.reload
product.sort_index.should == 0
product1.sort_index.should == 1
product2.sort_index.should == 2
end
end
#PATH: app/controllers/
class ProductsController < ApplicationController
respond_to :html, :js
def index
@products = Product.order("sort_index ASC")
end
def move_up
@product = Product.find(params[:id])
@success = [email protected]? && @product.move_up
end
def move_down
@product = Product.find(params[:id])
@success = [email protected]? && @product.move_down
end
end
#PATH: config/
YourApplication::Application.routes.draw do
resources :products do
member do
put :move_up
put :move_down
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment