Skip to content

Instantly share code, notes, and snippets.

@nilbus
Forked from ledermann/ransack.rb
Created January 3, 2013 15:24
Show Gist options
  • Save nilbus/4444256 to your computer and use it in GitHub Desktop.
Save nilbus/4444256 to your computer and use it in GitHub Desktop.
# Patch for ransack (https://github.com/ernie/ransack) to use scopes
# Helps migrating from Searchlogic or MetaSearch
# Place this file into config/initializer/ransack.rb of your Rails 3.2 project
#
# Usage:
# class Debt < ActiveRecord::Base
# scope :overdue, lambda { where(["status = 'open' AND due_date < ?", Date.today]) }
# end
#
# Ransack out of the box ignores scopes. Example:
# Debt.search(:overdue => true, :amount_gteq => 10).result.to_sql
# => "SELECT `debts`.* FROM `debts` AND (`debts`.`amount` >= 10.0)"
#
# This is changed by the patch. Example:
# Debt.search(:overdue => true).result.to_sql
# => "SELECT `debts`.* FROM `debts` WHERE `debts`.`status` = 'open' AND (due_date < '2012-11-23') AND (`debts`.`amount` >= 10.0)"
#
# BEWARE: Every scope (and class method) of the model is available. This may be a security issue!
# Only scopes that return ActiveRecord::Relation are supported.
# Any other scope or method that is called via Ransack will throw an exception
# and cause a database transaction rollback.
#
module Ransack
module Adapters
module ActiveRecord
module Base
def search_with_scopes(params = {}, options = {})
ransack_scope = self
ransack_params = {}
# Extract params which refer to a scope
transaction do
(params||{}).each_pair do |k,v|
if ransack_scope.respond_to?(k)
if (v == true)
ransack_scope = ransack_scope.send(k)
else
ransack_scope = ransack_scope.send(k, v)
end
raise ArgumentError.new "#{k} is not a scope that returns an ActiveRecord::Relation" unless ransack_scope.is_a? ::ActiveRecord::Relation
else
ransack_params.merge!(k => v)
end
end
end
ransack_scope.search_without_scopes(ransack_params, options)
end
alias_method_chain :search, :scopes
end
end
end
end
@dexion
Copy link

dexion commented Apr 25, 2013

it doesn't work in this way:

Debt.search({'combinator' => 'or', 'groupings' => { '0' => {'overdue' => true}, '1' => {'amount_gteq' => 10}}}).result.to_sql

result is:

SELECT "debts".* FROM "debts"  WHERE "debts"."amount" >= 10

but should be:

SELECT "debts".* FROM "debts"  WHERE (`debts`.`status` = 'open' AND (due_date < '2012-11-23')) OR (`debts`.`amount` >= 10.0)

What are you think about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment