diff --git a/Gemfile b/Gemfile index 749623a..1074abd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,11 @@ -source "http://rubygems.org" +source "https://rubygems.org" gemspec gem 'rake' -rails = ENV['RAILS'] || '3-2-stable' +rails = ENV['RAILS'] || '4-0-stable' -gem 'arel', '3.0.2' +gem 'arel' case rails when /\// # A path diff --git a/lib/ransack/adapters/active_record.rb b/lib/ransack/adapters/active_record.rb index a4ffc39..ca7c94e 100644 --- a/lib/ransack/adapters/active_record.rb +++ b/lib/ransack/adapters/active_record.rb @@ -7,6 +7,8 @@ when /^3\.0\./ require 'ransack/adapters/active_record/3.0/context' when /^3\.1\./ require 'ransack/adapters/active_record/3.1/context' +when /^3\.2\./ + require 'ransack/adapters/active_record/3.2/context' else require 'ransack/adapters/active_record/context' end \ No newline at end of file diff --git a/lib/ransack/adapters/active_record/3.0/context.rb b/lib/ransack/adapters/active_record/3.0/context.rb index 7727cc2..5efb672 100644 --- a/lib/ransack/adapters/active_record/3.0/context.rb +++ b/lib/ransack/adapters/active_record/3.0/context.rb @@ -10,12 +10,18 @@ module Ransack # Because the AR::Associations namespace is insane JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency JoinBase = JoinDependency::JoinBase - + + # Redefine a few things for ActiveRecord 3.0. + def initialize(object, options = {}) super @arel_visitor = Arel::Visitors.visitor_for @engine end + def relation_for(object) + object.scoped + end + def evaluate(search, opts = {}) viz = Visitor.new relation = @object.where(viz.accept(search.base)) @@ -48,18 +54,6 @@ module Ransack parent.table end - def klassify(obj) - if Class === obj && ::ActiveRecord::Base > obj - obj - elsif obj.respond_to? :klass - obj.klass - elsif obj.respond_to? :active_record - obj.active_record - else - raise ArgumentError, "Don't know how to klassify #{obj}" - end - end - def type_for(attr) return nil unless attr && attr.valid? klassify(attr.parent).columns_hash[attr.arel_attribute.name.to_s].type diff --git a/lib/ransack/adapters/active_record/3.1/context.rb b/lib/ransack/adapters/active_record/3.1/context.rb index a4d04c6..c23295f 100644 --- a/lib/ransack/adapters/active_record/3.1/context.rb +++ b/lib/ransack/adapters/active_record/3.1/context.rb @@ -1,4 +1,5 @@ require 'ransack/context' +require 'ransack/adapters/active_record/compat' require 'polyamorous' module Ransack @@ -8,12 +9,18 @@ module Ransack # Because the AR::Associations namespace is insane JoinDependency = ::ActiveRecord::Associations::JoinDependency JoinPart = JoinDependency::JoinPart - + + # Redefine a few things for ActiveRecord 3.1. + def initialize(object, options = {}) super @arel_visitor = Arel::Visitors.visitor_for @engine end + def relation_for(object) + object.scoped + end + def evaluate(search, opts = {}) viz = Visitor.new relation = @object.where(viz.accept(search.base)) @@ -46,18 +53,6 @@ module Ransack parent.table end - def klassify(obj) - if Class === obj && ::ActiveRecord::Base > obj - obj - elsif obj.respond_to? :klass - obj.klass - elsif obj.respond_to? :active_record - obj.active_record - else - raise ArgumentError, "Don't know how to klassify #{obj}" - end - end - def type_for(attr) return nil unless attr && attr.valid? name = attr.arel_attribute.name.to_s diff --git a/lib/ransack/adapters/active_record/3.2/context.rb b/lib/ransack/adapters/active_record/3.2/context.rb new file mode 100644 index 0000000..a9810f3 --- /dev/null +++ b/lib/ransack/adapters/active_record/3.2/context.rb @@ -0,0 +1,44 @@ +require 'ransack/context' +require 'ransack/adapters/active_record/3.1/context' +require 'ransack/adapters/active_record/compat' +require 'polyamorous' + +module Ransack + module Adapters + module ActiveRecord + class Context < ::Ransack::Context + + # Redefine a few things for ActiveRecord 3.2. + + def initialize(object, options = {}) + super + @arel_visitor = @engine.connection.visitor + end + + def relation_for(object) + object.scoped + end + + def type_for(attr) + return nil unless attr && attr.valid? + name = attr.arel_attribute.name.to_s + table = attr.arel_attribute.relation.table_name + + schema_cache = @engine.connection.schema_cache + raise "No table named #{table} exists" unless schema_cache.table_exists?(table) + schema_cache.columns_hash[table][name].type + end + + def evaluate(search, opts = {}) + viz = Visitor.new + relation = @object.where(viz.accept(search.base)) + if search.sorts.any? + relation = relation.except(:order).reorder(viz.accept(search.sorts)) + end + opts[:distinct] ? relation.uniq : relation + end + + end + end + end +end \ No newline at end of file diff --git a/lib/ransack/adapters/active_record/context.rb b/lib/ransack/adapters/active_record/context.rb index 2b96ba2..188c032 100644 --- a/lib/ransack/adapters/active_record/context.rb +++ b/lib/ransack/adapters/active_record/context.rb @@ -1,5 +1,5 @@ require 'ransack/context' -require 'ransack/adapters/active_record/3.1/context' +require 'ransack/adapters/active_record/3.2/context' require 'ransack/adapters/active_record/compat' require 'polyamorous' @@ -8,21 +8,23 @@ module Ransack module ActiveRecord class Context < ::Ransack::Context - # Redefine a few things that have changed with 3.2. - def initialize(object, options = {}) super @arel_visitor = @engine.connection.visitor end + def relation_for(object) + object.all + end + def type_for(attr) return nil unless attr && attr.valid? name = attr.arel_attribute.name.to_s table = attr.arel_attribute.relation.table_name - schema_cache = @engine.connection.schema_cache - raise "No table named #{table} exists" unless schema_cache.table_exists?(table) - schema_cache.columns_hash[table][name].type + schema_cache = @engine.connection.schema_cache + raise "No table named #{table} exists" unless schema_cache.table_exists?(table) + schema_cache.columns_hash(table)[name].type end def evaluate(search, opts = {}) @@ -31,7 +33,7 @@ module Ransack if search.sorts.any? relation = relation.except(:order).reorder(viz.accept(search.sorts)) end - opts[:distinct] ? relation.uniq : relation + opts[:distinct] ? relation.distinct : relation end end diff --git a/lib/ransack/context.rb b/lib/ransack/context.rb index e0a1b60..f46d7b7 100644 --- a/lib/ransack/context.rb +++ b/lib/ransack/context.rb @@ -28,7 +28,7 @@ module Ransack end def initialize(object, options = {}) - @object = object.scoped + @object = relation_for(object) @klass = @object.klass @join_dependency = join_dependency(@object) @join_type = options[:join_type] || Arel::OuterJoin @@ -44,6 +44,20 @@ module Ransack end end + def klassify(obj) + if Class === obj && ::ActiveRecord::Base > obj + obj + elsif obj.respond_to? :klass + obj.klass + elsif obj.respond_to? :active_record # Rails 3 + obj.active_record + elsif obj.respond_to? :base_klass # Rails 4 + obj.base_klass + else + raise ArgumentError, "Don't know how to klassify #{obj}" + end + end + # Convert a string representing a chain of associations and an attribute # into the attribute itself def contextualize(str) diff --git a/lib/ransack/translate.rb b/lib/ransack/translate.rb index ee7c113..c2e0334 100644 --- a/lib/ransack/translate.rb +++ b/lib/ransack/translate.rb @@ -23,7 +23,7 @@ module Ransack attribute_names = attributes_str.split(/_and_|_or_/) combinator = attributes_str.match(/_and_/) ? :and : :or defaults = base_ancestors.map do |klass| - :"ransack.attributes.#{klass.model_name.underscore}.#{original_name}" + :"ransack.attributes.#{klass.model_name.singular}.#{original_name}" end translated_names = attribute_names.map do |attr| @@ -50,7 +50,7 @@ module Ransack raise ArgumentError, "A context is required to translate associations" end - defaults = key.blank? ? [:"#{context.klass.i18n_scope}.models.#{context.klass.model_name.underscore}"] : [:"ransack.associations.#{context.klass.model_name.underscore}.#{key}"] + defaults = key.blank? ? [:"#{context.klass.i18n_scope}.models.#{context.klass.model_name.singular}"] : [:"ransack.associations.#{context.klass.model_name.singular}.#{key}"] defaults << context.traverse(key).model_name.human options = {:count => 1, :default => defaults} I18n.translate(defaults.shift, options) @@ -65,20 +65,20 @@ module Ransack interpolations = {} interpolations[:attr_fallback_name] = I18n.translate( (associated_class ? - :"ransack.attributes.#{associated_class.model_name.underscore}.#{attr_name}" : - :"ransack.attributes.#{context.klass.model_name.underscore}.#{attr_name}" + :"ransack.attributes.#{associated_class.model_name.singular}.#{attr_name}" : + :"ransack.attributes.#{context.klass.model_name.singular}.#{attr_name}" ), :default => [ (associated_class ? - :"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.underscore}.#{attr_name}" : - :"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.underscore}.#{attr_name}" + :"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.singular}.#{attr_name}" : + :"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.singular}.#{attr_name}" ), :".attributes.#{attr_name}", attr_name.humanize ] ) defaults = [ - :"ransack.attributes.#{context.klass.model_name.underscore}.#{name}" + :"ransack.attributes.#{context.klass.model_name.singular}.#{name}" ] if include_associations && associated_class defaults << '%{association_name} %{attr_fallback_name}' diff --git a/ransack.gemspec b/ransack.gemspec index f8da91c..51b145b 100644 --- a/ransack.gemspec +++ b/ransack.gemspec @@ -14,8 +14,8 @@ Gem::Specification.new do |s| s.rubyforge_project = "ransack" - s.add_dependency 'activerecord', '~> 3.0' - s.add_dependency 'actionpack', '~> 3.0' + s.add_dependency 'activerecord', '>= 3.0' + s.add_dependency 'actionpack', '>= 3.0' s.add_dependency 'polyamorous', '~> 0.6.0' s.add_development_dependency 'rspec', '~> 2.8.0' s.add_development_dependency 'machinist', '~> 1.0.6' diff --git a/spec/ransack/adapters/active_record/context_spec.rb b/spec/ransack/adapters/active_record/context_spec.rb index a3440b6..b1e89fc 100644 --- a/spec/ransack/adapters/active_record/context_spec.rb +++ b/spec/ransack/adapters/active_record/context_spec.rb @@ -6,6 +6,12 @@ module Ransack describe Context do subject { Context.new(Person) } + describe '#relation_for' do + it 'returns relation for given object' do + subject.object.should be_an ::ActiveRecord::Relation + end + end + describe '#evaluate' do it 'evaluates search obects' do search = Search.new(Person, :name_eq => 'Joe Blow')