From 53ef01b9e69234e1f406030f0cfc9404957c9c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Sj=C3=B6berg?= Date: Wed, 6 Feb 2013 11:26:06 +0100 Subject: [PATCH 001/112] Fix issue #190 and #195 This resolves issues where an integer column would raise an exception when handled by Ransack::Constants.escape_wildcards. --- lib/ransack/constants.rb | 2 +- spec/ransack/predicate_spec.rb | 23 +++++++++++++++++++---- spec/spec_helper.rb | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index 5b5908e..01eb3b2 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -23,7 +23,7 @@ module Ransack module_function # replace % \ to \% \\ def escape_wildcards(unescaped) - unescaped.gsub(/([\\|\%|.])/, '\\\\\\1') + unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') end end end diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index 4d67917..aae41d7 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -7,6 +7,17 @@ module Ransack @s = Search.new(Person) end + shared_examples 'wildcard escaping' do |method, regexp| + it 'automatically converts integers to strings' do + subject.parent_id_cont = 1 + expect { subject.result }.to_not raise_error + end + it "escapes '%', '.' and '\\\\' in value" do + subject.public_send(:"#{method}=", '%._\\') + subject.result.to_sql.should match(regexp) + end + end + describe 'eq' do it 'generates an equality condition for boolean true' do @s.awesome_eq = true @@ -25,17 +36,21 @@ module Ransack end describe 'cont' do + it_has_behavior 'wildcard escaping', :name_cont, /"people"."name" LIKE '%\\%\\._\\\\%'/ do + subject { @s } + end + it 'generates a LIKE query with value surrounded by %' do @s.name_cont = 'ric' @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/ end - it 'escapes %, . and \\ in value' do - @s.name_cont = '%._\\' - @s.result.to_sql.should match /"people"."name" LIKE '%\\%\\._\\\\%'/ - end end describe 'not_cont' do + it_has_behavior 'wildcard escaping', :name_not_cont, /"people"."name" NOT LIKE '%\\%\\._\\\\%'/ do + subject { @s } + end + it 'generates a NOT LIKE query with value surrounded by %' do @s.name_not_cont = 'ric' @s.result.to_sql.should match /"people"."name" NOT LIKE '%ric%'/ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6cf14bd..52a97d1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,6 +20,8 @@ Sham.define do end RSpec.configure do |config| + config.alias_it_behaves_like_to :it_has_behavior, 'has behavior' + config.before(:suite) do puts '=' * 80 puts "Running specs against ActiveRecord #{ActiveRecord::VERSION::STRING} and ARel #{Arel::VERSION}..." From 8501b983d60e581043d50a4b33cdeb619eb88142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Sj=C3=B6berg?= Date: Wed, 6 Feb 2013 14:15:05 +0100 Subject: [PATCH 002/112] Change RSpec configuration alias In RSpec, v2.8, RSpec::Core::Configuration#alias_it_behaves_like_to does not exist. This method is introduced in later versions. Instead, use RSpec::Core::Configuration#alias_it_should_behave_like_to. --- spec/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 52a97d1..203a3ec 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,7 +20,7 @@ Sham.define do end RSpec.configure do |config| - config.alias_it_behaves_like_to :it_has_behavior, 'has behavior' + config.alias_it_should_behave_like_to :it_has_behavior, 'has behavior' config.before(:suite) do puts '=' * 80 From 39268579764f42c5548e7610fea6d0d33d1fda3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Sj=C3=B6berg?= Date: Wed, 6 Feb 2013 14:25:37 +0100 Subject: [PATCH 003/112] Use Object#send to comply with Ruby 1.8.7 --- spec/ransack/predicate_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index aae41d7..ff9a00a 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -13,7 +13,7 @@ module Ransack expect { subject.result }.to_not raise_error end it "escapes '%', '.' and '\\\\' in value" do - subject.public_send(:"#{method}=", '%._\\') + subject.send(:"#{method}=", '%._\\') subject.result.to_sql.should match(regexp) end end From 5cc0595244a669f5cd54833d22db31343deb7e0a Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 7 Feb 2013 10:04:06 +1100 Subject: [PATCH 004/112] Bump to 0.7.3 --- lib/ransack/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ransack/version.rb b/lib/ransack/version.rb index 813b99e..d2f0d8c 100644 --- a/lib/ransack/version.rb +++ b/lib/ransack/version.rb @@ -1,3 +1,3 @@ module Ransack - VERSION = "0.7.2" + VERSION = "0.7.3" end From c98135e6c2795af63a8d6774ddbfbae5e4499b67 Mon Sep 17 00:00:00 2001 From: Eduardo Lanchares Date: Thu, 7 Feb 2013 09:55:49 +0100 Subject: [PATCH 005/112] Fixed lteq spanish translation --- lib/ransack/locale/es.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ransack/locale/es.yml b/lib/ransack/locale/es.yml index 2a285fc..fa05bd0 100644 --- a/lib/ransack/locale/es.yml +++ b/lib/ransack/locale/es.yml @@ -29,7 +29,7 @@ es: lt: "menor que" lt_any: "menor que cualquier" lt_all: "menor o igual a" - lteq: "less than or equal to" + lteq: "menor que o igual a" lteq_any: "menor o igual a cualquier" lteq_all: "menor o igual a todos" gt: "mayor que" From 74fc9739927ffb138dae56281a2a3bbbfc9373f7 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Tue, 19 Feb 2013 22:45:02 -0500 Subject: [PATCH 006/112] Separated searchable attributes from sortable attributes so either can be overwritten in a model --- lib/ransack/adapters/active_record/base.rb | 5 ++ lib/ransack/context.rb | 4 ++ lib/ransack/helpers/form_builder.rb | 56 ++++++++++++++-------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/lib/ransack/adapters/active_record/base.rb b/lib/ransack/adapters/active_record/base.rb index 5998892..51d814b 100644 --- a/lib/ransack/adapters/active_record/base.rb +++ b/lib/ransack/adapters/active_record/base.rb @@ -23,6 +23,11 @@ module Ransack column_names + _ransackers.keys end + def ransortable_attributes(auth_object = nil) + # Here so users can overwrite the attributes that show up in the sort_select + ransackable_attributes(auth_object) + end + def ransackable_associations(auth_object = nil) reflect_on_all_associations.map {|a| a.name.to_s} end diff --git a/lib/ransack/context.rb b/lib/ransack/context.rb index e0a1b60..516c8f5 100644 --- a/lib/ransack/context.rb +++ b/lib/ransack/context.rb @@ -117,6 +117,10 @@ module Ransack traverse(str).ransackable_attributes(auth_object) end + def sortable_attributes(str = '') + traverse(str).ransortable_attributes(auth_object) + end + def searchable_associations(str = '') traverse(str).ransackable_associations(auth_object) end diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index e23462a..7a62501 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -23,16 +23,11 @@ module Ransack bases = [''] + association_array(options[:associations]) if bases.size > 1 @template.grouped_collection_select( - @object_name, :name, attribute_collection_for_bases(bases), :last, :first, :first, :last, + @object_name, :name, searchable_attribute_collection_for_bases(bases), :last, :first, :first, :last, objectify_options(options), @default_options.merge(html_options) ) else - collection = object.context.searchable_attributes(bases.first).map do |c| - [ - attr_from_base_and_column(bases.first, c), - Translate.attribute(attr_from_base_and_column(bases.first, c), :context => object.context) - ] - end + collection = searchable_attribute_collection_for_base(bases.first) @template.collection_select( @object_name, :name, collection, :first, :last, objectify_options(options), @default_options.merge(html_options) @@ -46,19 +41,14 @@ module Ransack bases = [''] + association_array(options[:associations]) if bases.size > 1 @template.grouped_collection_select( - @object_name, :name, attribute_collection_for_bases(bases), :last, :first, :first, :last, + @object_name, :name, sortable_attribute_collection_for_bases(bases), :last, :first, :first, :last, objectify_options(options), @default_options.merge(html_options) ) + @template.collection_select( @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, objectify_options(options), @default_options.merge(html_options) ) else - collection = object.context.searchable_attributes(bases.first).map do |c| - [ - attr_from_base_and_column(bases.first, c), - Translate.attribute(attr_from_base_and_column(bases.first, c), :context => object.context) - ] - end + collection = sortable_attribute_collection_for_base(bases.first) @template.collection_select( @object_name, :name, collection, :first, :last, objectify_options(options), @default_options.merge(html_options) @@ -170,17 +160,29 @@ module Ransack [base, column].reject {|v| v.blank?}.join('_') end - def attribute_collection_for_bases(bases) + def attribute_collection_for_base(attributes, base=nil) + attributes.map do |c| + [ + attr_from_base_and_column(base, c), + Translate.attribute(attr_from_base_and_column(base, c), :context => object.context) + ] + end + end + + def sortable_attribute_collection_for_base(base=nil) + attribute_collection_for_base(object.context.sortable_attributes(base), base) + end + + def searchable_attribute_collection_for_base(base=nil) + attribute_collection_for_base(object.context.searchable_attributes(base), base) + end + + def sortable_attribute_collection_for_bases(bases) bases.map do |base| begin [ Translate.association(base, :context => object.context), - object.context.searchable_attributes(base).map do |c| - [ - attr_from_base_and_column(base, c), - Translate.attribute(attr_from_base_and_column(base, c), :context => object.context) - ] - end + sortable_attribute_collection_for_base(base) ] rescue UntraversableAssociationError => e nil @@ -188,6 +190,18 @@ module Ransack end.compact end + def searchable_attribute_collection_for_bases(bases) + bases.map do |base| + begin + [ + Translate.association(base, :context => object.context), + searchable_attribute_collection_for_base(base) + ] + rescue UntraversableAssociationError => e + nil + end + end.compact + end end end end \ No newline at end of file From 2ee96508cc549f211c990e7a9212949f66e2b61d Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Tue, 19 Feb 2013 22:54:55 -0500 Subject: [PATCH 007/112] Added simple spec to test newly added ransortable attributes --- .rvmrc | 81 +++++++++++++++++++ .../adapters/active_record/base_spec.rb | 8 ++ 2 files changed, 89 insertions(+) create mode 100644 .rvmrc diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000..285d263 --- /dev/null +++ b/.rvmrc @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# This is an RVM Project .rvmrc file, used to automatically load the ruby +# development environment upon cd'ing into the directory + +# First we specify our desired [@], the @gemset name is optional. +environment_id="ruby-1.9.3-p362@ransack" + +# +# Uncomment the following lines if you want to verify rvm version per project +# +# rvmrc_rvm_version="1.10.2" # 1.10.1 seams as a safe start +# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || { +# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading." +# return 1 +# } +# + +# +# Uncomment following line if you want options to be set only for given project. +# +# PROJECT_JRUBY_OPTS=( --1.9 ) +# +# The variable PROJECT_JRUBY_OPTS requires the following to be run in shell: +# +# chmod +x ${rvm_path}/hooks/after_use_jruby_opts +# + +# +# First we attempt to load the desired environment directly from the environment +# file. This is very fast and efficient compared to running through the entire +# CLI and selector. If you want feedback on which environment was used then +# insert the word 'use' after --create as this triggers verbose mode. +# +if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ + && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] +then + \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" + + if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] + then + . "${rvm_path:-$HOME/.rvm}/hooks/after_use" + fi +else + # If the environment file has not yet been created, use the RVM CLI to select. + if ! rvm --create "$environment_id" + then + echo "Failed to create RVM environment '${environment_id}'." + return 1 + fi +fi + +# +# If you use an RVM gemset file to install a list of gems (*.gems), you can have +# it be automatically loaded. Uncomment the following and adjust the filename if +# necessary. +# +# filename=".gems" +# if [[ -s "$filename" ]] +# then +# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d' +# fi + +# If you use bundler, this might be useful to you: +# if [[ -s Gemfile ]] && ! command -v bundle >/dev/null +# then +# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n" +# gem install bundler +# fi +# if [[ -s Gemfile ]] && command -v bundle +# then +# bundle install +# fi + +if [[ $- == *i* ]] # check for interactive shells +then + echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green +else + echo "Using: $GEM_HOME" # don't use colors in interactive shells +fi + diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 88ddfd8..a827984 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -58,6 +58,14 @@ module Ransack it { should include 'doubled_name' } end + describe '#ransortable_attributes' do + subject { Person.ransortable_attributes } + + it { should include 'name' } + it { should include 'reversed_name' } + it { should include 'doubled_name' } + end + describe '#ransackable_associations' do subject { Person.ransackable_associations } From a7ee60dde713d0e1ceb427092fe6664ff43484ec Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Tue, 19 Feb 2013 23:00:15 -0500 Subject: [PATCH 008/112] Removing accidentally committed file --- .rvmrc | 81 ---------------------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 .rvmrc diff --git a/.rvmrc b/.rvmrc deleted file mode 100644 index 285d263..0000000 --- a/.rvmrc +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -# This is an RVM Project .rvmrc file, used to automatically load the ruby -# development environment upon cd'ing into the directory - -# First we specify our desired [@], the @gemset name is optional. -environment_id="ruby-1.9.3-p362@ransack" - -# -# Uncomment the following lines if you want to verify rvm version per project -# -# rvmrc_rvm_version="1.10.2" # 1.10.1 seams as a safe start -# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || { -# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading." -# return 1 -# } -# - -# -# Uncomment following line if you want options to be set only for given project. -# -# PROJECT_JRUBY_OPTS=( --1.9 ) -# -# The variable PROJECT_JRUBY_OPTS requires the following to be run in shell: -# -# chmod +x ${rvm_path}/hooks/after_use_jruby_opts -# - -# -# First we attempt to load the desired environment directly from the environment -# file. This is very fast and efficient compared to running through the entire -# CLI and selector. If you want feedback on which environment was used then -# insert the word 'use' after --create as this triggers verbose mode. -# -if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ - && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] -then - \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" - - if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] - then - . "${rvm_path:-$HOME/.rvm}/hooks/after_use" - fi -else - # If the environment file has not yet been created, use the RVM CLI to select. - if ! rvm --create "$environment_id" - then - echo "Failed to create RVM environment '${environment_id}'." - return 1 - fi -fi - -# -# If you use an RVM gemset file to install a list of gems (*.gems), you can have -# it be automatically loaded. Uncomment the following and adjust the filename if -# necessary. -# -# filename=".gems" -# if [[ -s "$filename" ]] -# then -# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d' -# fi - -# If you use bundler, this might be useful to you: -# if [[ -s Gemfile ]] && ! command -v bundle >/dev/null -# then -# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n" -# gem install bundler -# fi -# if [[ -s Gemfile ]] && command -v bundle -# then -# bundle install -# fi - -if [[ $- == *i* ]] # check for interactive shells -then - echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green -else - echo "Using: $GEM_HOME" # don't use colors in interactive shells -fi - From 1cfebb7158e30cefb0a4f779045dac7b2963701f Mon Sep 17 00:00:00 2001 From: Peter Fern Date: Thu, 28 Feb 2013 17:10:49 +1100 Subject: [PATCH 009/112] Reorder results to override orders applied up the chain (eg - scopes) --- lib/ransack/adapters/active_record/3.0/context.rb | 4 ++-- lib/ransack/adapters/active_record/3.1/context.rb | 2 +- lib/ransack/adapters/active_record/context.rb | 4 ++-- spec/ransack/search_spec.rb | 5 +++++ spec/support/schema.rb | 3 ++- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/ransack/adapters/active_record/3.0/context.rb b/lib/ransack/adapters/active_record/3.0/context.rb index d968553..7727cc2 100644 --- a/lib/ransack/adapters/active_record/3.0/context.rb +++ b/lib/ransack/adapters/active_record/3.0/context.rb @@ -20,7 +20,7 @@ module Ransack viz = Visitor.new relation = @object.where(viz.accept(search.base)) if search.sorts.any? - relation = relation.except(:order).order(viz.accept(search.sorts)) + relation = relation.except(:order).reorder(viz.accept(search.sorts)) end opts[:distinct] ? relation.select("DISTINCT #{@klass.quoted_table_name}.*") : relation end @@ -158,4 +158,4 @@ module Ransack end end end -end \ No newline at end of file +end diff --git a/lib/ransack/adapters/active_record/3.1/context.rb b/lib/ransack/adapters/active_record/3.1/context.rb index af60cfe..a4d04c6 100644 --- a/lib/ransack/adapters/active_record/3.1/context.rb +++ b/lib/ransack/adapters/active_record/3.1/context.rb @@ -18,7 +18,7 @@ module Ransack viz = Visitor.new relation = @object.where(viz.accept(search.base)) if search.sorts.any? - relation = relation.except(:order).order(viz.accept(search.sorts)) + relation = relation.except(:order).reorder(viz.accept(search.sorts)) end opts[:distinct] ? relation.select("DISTINCT #{@klass.quoted_table_name}.*") : relation end diff --git a/lib/ransack/adapters/active_record/context.rb b/lib/ransack/adapters/active_record/context.rb index 2249b2d..2b96ba2 100644 --- a/lib/ransack/adapters/active_record/context.rb +++ b/lib/ransack/adapters/active_record/context.rb @@ -29,7 +29,7 @@ module Ransack viz = Visitor.new relation = @object.where(viz.accept(search.base)) if search.sorts.any? - relation = relation.except(:order).order(viz.accept(search.sorts)) + relation = relation.except(:order).reorder(viz.accept(search.sorts)) end opts[:distinct] ? relation.uniq : relation end @@ -37,4 +37,4 @@ module Ransack end end end -end \ No newline at end of file +end diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 88e3e48..4627d62 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -217,6 +217,11 @@ module Ransack id_sort.dir.should eq 'desc' name_sort.dir.should eq 'asc' end + + it 'overrides existing sort' do + @s.sorts = 'id asc' + @s.result.first.id.should eq 1 + end end describe '#method_missing' do diff --git a/spec/support/schema.rb b/spec/support/schema.rb index cdf1355..119408c 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -6,6 +6,7 @@ ActiveRecord::Base.establish_connection( ) class Person < ActiveRecord::Base + default_scope order('id DESC') belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id has_many :children, :class_name => 'Person', :foreign_key => :parent_id has_many :articles @@ -108,4 +109,4 @@ module Schema Comment.make(:body => 'First post!', :article => Article.make(:title => 'Hello, world!')) end -end \ No newline at end of file +end From 08c375d4b0aa80a4fc2bc7312fce7e3f257490c7 Mon Sep 17 00:00:00 2001 From: Anatoliy Pronin Date: Sun, 17 Mar 2013 02:34:07 +0400 Subject: [PATCH 010/112] changed the translation of common attributes --- lib/ransack/translate.rb | 3 ++- spec/ransack/helpers/form_builder_spec.rb | 16 +++++++++++----- spec/support/en.yml | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/ransack/translate.rb b/lib/ransack/translate.rb index f52b254..ee7c113 100644 --- a/lib/ransack/translate.rb +++ b/lib/ransack/translate.rb @@ -73,6 +73,7 @@ module Ransack :"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.underscore}.#{attr_name}" : :"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.underscore}.#{attr_name}" ), + :".attributes.#{attr_name}", attr_name.humanize ] ) @@ -89,4 +90,4 @@ module Ransack I18n.translate(defaults.shift, options.merge(interpolations)) end end -end \ No newline at end of file +end diff --git a/spec/ransack/helpers/form_builder_spec.rb b/spec/ransack/helpers/form_builder_spec.rb index 09cc42a..f1c0834 100644 --- a/spec/ransack/helpers/form_builder_spec.rb +++ b/spec/ransack/helpers/form_builder_spec.rb @@ -48,11 +48,17 @@ module Ransack end describe '#sort_link' do - subject { @f.sort_link :name, :controller => 'people' } + it 'sort_link for ransack attribute' do + sort_link = @f.sort_link :name, :controller => 'people' + sort_link.should match /people\?q%5Bs%5D=name\+asc/ + sort_link.should match /sort_link/ + sort_link.should match /Full Name<\/a>/ + end - it { should match /people\?q%5Bs%5D=name\+asc/} - it { should match /sort_link/} - it { should match /Full Name<\/a>/} + it 'sort_link for common attribute' do + sort_link = @f.sort_link :id, :controller => 'people' + sort_link.should match /id<\/a>/ + end end describe '#submit' do @@ -124,4 +130,4 @@ module Ransack end end end -end \ No newline at end of file +end diff --git a/spec/support/en.yml b/spec/support/en.yml index 469593e..503d50c 100644 --- a/spec/support/en.yml +++ b/spec/support/en.yml @@ -1,5 +1,7 @@ en: + attributes: + id: 'id' ransack: attributes: person: - name: Full Name \ No newline at end of file + name: Full Name From a2ad5ee56151e224cc83cd8f5a1f4f4e350bda4a Mon Sep 17 00:00:00 2001 From: Shinichi Maeshima Date: Fri, 22 Mar 2013 17:01:57 +0900 Subject: [PATCH 011/112] Fixes squeel link is 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 54dea51..be430ec 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Ransack enables the creation of both simple and [advanced](http://ransack-demo.h search forms against your application's models. If you're looking for something that simplifies query generation at the model or controller layer, you're probably not looking for Ransack (or MetaSearch, for that matter). Try -[Squeel](http://metautonomo.us/projects/squeel) instead. +[Squeel](https://github.com/ernie/squeel) instead. ## Getting started From d0a9ed4e963f7a32bede386e4958e8318f97157c Mon Sep 17 00:00:00 2001 From: willnet Date: Fri, 22 Mar 2013 19:35:32 +0900 Subject: [PATCH 012/112] Fixes meta_search link is 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be430ec..d38f36c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/ernie/ransack.png?branch=master)](https://travis-ci.org/ernie/ransack) -Ransack is a rewrite of [MetaSearch](http://metautonomo.us/projects/metasearch). While it +Ransack is a rewrite of [MetaSearch](https://github.com/ernie/meta_search). While it supports many of the same features as MetaSearch, its underlying implementation differs greatly from MetaSearch, and _backwards compatibility is not a design goal._ From 88c1efbc92e27b6d1e95338fe1bfeb920c6f86e0 Mon Sep 17 00:00:00 2001 From: Louis Davin Date: Sat, 20 Apr 2013 14:09:03 -0400 Subject: [PATCH 013/112] Add French locale Translated the English locale to French (:fr) --- lib/ransack/locale/fr.yml | 70 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 lib/ransack/locale/fr.yml diff --git a/lib/ransack/locale/fr.yml b/lib/ransack/locale/fr.yml new file mode 100644 index 0000000..de928f4 --- /dev/null +++ b/lib/ransack/locale/fr.yml @@ -0,0 +1,70 @@ +fr: + ransack: + search: "recherche" + predicate: "prédicat" + and: "et" + or: "ou" + any: "au moins un" + all: "tous" + combinator: "combinateur" + attribute: "attribut" + value: "valeur" + condition: "condition" + sort: "tri" + asc: "ascendant" + desc: "descendant" + predicates: + eq: "égal à" + eq_any: "égal à au moins un" + eq_all: "égal à tous" + not_eq: "différent de" + not_eq_any: "différent d'au moins un" + not_eq_all: "différent de tous" + matches: "correspond à" + matches_any: "correspond à au moins un" + matches_all: "correspond à tous" + does_not_match: "ne correspond pas à" + does_not_match_any: "ne correspond pas à au moins un" + does_not_match_all: "ne correspond à aucun" + lt: "inférieur à" + lt_any: "inférieur à au moins un" + lt_all: "inférieur à tous" + lteq: "inférieur ou égal à" + lteq_any: "inférieur ou égal à au moins un" + lteq_all: "inférieur ou égal à tous" + gt: "supérieur à" + gt_any: "supérieur à au moins un" + gt_all: "supérieur à tous" + gteq: "supérieur ou égal à" + gteq_any: "supérieur ou égal à au moins un" + gteq_all: "supérieur ou égal à tous" + in: "inclus dans" + in_any: "inclus dans au moins un" + in_all: "inclus dans tous" + not_in: "non inclus dans" + not_in_any: "non inclus dans au moins un" + not_in_all: "non inclus dans tous" + cont: "contient" + cont_any: "contient au moins un" + cont_all: "contient tous" + not_cont: "ne contient pas" + not_cont_any: "ne contient pas au moins un" + not_cont_all: "ne contient pas tous" + start: "commence par" + start_any: "commence par au moins un" + start_all: "commence par tous" + not_start: "ne commence pas par" + not_start_any: "ne commence pas par au moins un" + not_start_all: "ne commence pas par tous" + end: "finit par" + end_any: "finit par au moins un" + end_all: "finit par tous" + not_end: "ne finit pas par" + not_end_any: "ne finit pas par au moins un" + not_end_all: "ne finit pas par tous" + 'true': "est vrai" + 'false': "est faux" + present: "est présent" + blank: "est blanc" + 'null': "est null" + not_null: "n'est pas null" From edffdadc75faec250363e9d5d3db336ee2f9dcd7 Mon Sep 17 00:00:00 2001 From: sanemat Date: Sat, 27 Apr 2013 20:55:23 -0700 Subject: [PATCH 014/112] Test with 1.9.3 and 2.0.0 in travis-ci --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 33d70a1..67018b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ rvm: - 1.8.7 - 1.9.2 + - 1.9.3 + - 2.0.0 - ree - rbx-18mode - ruby-head From cfe6e0f146cdd8a4421d9fa644cc7fd01eba9367 Mon Sep 17 00:00:00 2001 From: Alif Rachmawadi Date: Sat, 4 May 2013 12:13:46 +0700 Subject: [PATCH 015/112] enable syntax highlighting on README --- README.md | 125 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index d38f36c..ba9ca24 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,15 @@ for Ransack (or MetaSearch, for that matter). Try In your Gemfile: - gem "ransack" # Last officially released gem +```ruby +gem "ransack" # Last officially released gem +``` Or if you want to use the bleeding edge: - gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo - +```ruby +gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo +``` ## Usage @@ -55,20 +58,24 @@ If you're coming from MetaSearch, things to note: In your controller: - def index - @q = Person.search(params[:q]) - @people = @q.result(:distinct => true) - end +```ruby +def index + @q = Person.search(params[:q]) + @people = @q.result(:distinct => true) +end +``` In your view: - <%= search_form_for @q do |f| %> - <%= f.label :name_cont %> - <%= f.text_field :name_cont %> - <%= f.label :articles_title_start %> - <%= f.text_field :articles_title_start %> - <%= f.submit %> - <% end %> +```erb +<%= search_form_for @q do |f| %> + <%= f.label :name_cont %> + <%= f.text_field :name_cont %> + <%= f.label :articles_title_start %> + <%= f.text_field :articles_title_start %> + <%= f.submit %> +<% end %> +``` `cont` (contains) and `start` (starts with) are just two of the available search predicates. See [Constants](https://github.com/ernie/ransack/blob/master/lib/ransack/constants.rb) for a full list and the [wiki](https://github.com/ernie/ransack/wiki/Basic-Searching) for more description. @@ -83,23 +90,29 @@ parameter string will typically force you to use the HTTP POST method instead of This means you'll need to tweak your routes... - resources :people do - collection do - match 'search' => 'people#search', :via => [:get, :post], :as => :search - end - end +```ruby +resources :people do + collection do + match 'search' => 'people#search', :via => [:get, :post], :as => :search + end +end +``` ... and add another controller action ... - def search - index - render :index - end +```ruby +def search + index + render :index +end +``` ... and update your `search_form_for` line in the view ... - <%= search_form_for @q, :url => search_people_path, - :html => {:method => :post} do |f| %> +```erb +<%= search_form_for @q, :url => search_people_path, + :html => {:method => :post} do |f| %> +``` Once you've done so, you can make use of the helpers in Ransack::Helpers::FormBuilder to construct much more complex search forms, such as the one on the @@ -111,48 +124,54 @@ You can easily use Ransack to search in associated objects. Given you have these associations ... - class Employee < ActiveRecord::Base - belongs_to :supervisor +```ruby +class Employee < ActiveRecord::Base + belongs_to :supervisor - # has attribute last_name:string - end + # has attribute last_name:string +end - class Department < ActiveRecord::Base - has_many :supervisors +class Department < ActiveRecord::Base + has_many :supervisors - # has attribute title:string - end + # has attribute title:string +end - class Supervisor < ActiveRecord::Base - belongs_to :department - has_many :employees +class Supervisor < ActiveRecord::Base + belongs_to :department + has_many :employees - # has attribute last_name:string - end + # has attribute last_name:string +end +``` ... and a controller ... - class SupervisorsController < ApplicationController - def index - @search = Supervisor.search(params[:q]) - @supervisors = @search.result(:distinct => true) - end - end +```ruby +class SupervisorsController < ApplicationController + def index + @search = Supervisor.search(params[:q]) + @supervisors = @search.result(:distinct => true) + end +end +``` ... you might set up your form like this ... - <%= search_form_for @search do |f| %> - <%= f.label :last_name_cont %> - <%= f.text_field :last_name_cont %> +```erb +<%= search_form_for @search do |f| %> + <%= f.label :last_name_cont %> + <%= f.text_field :last_name_cont %> - <%= f.label :department_title_cont %> - <%= f.text_field :department_title_cont %> + <%= f.label :department_title_cont %> + <%= f.text_field :department_title_cont %> - <%= f.label :employees_last_name_cont %> - <%= f.text_field :employees_last_name_cont %> + <%= f.label :employees_last_name_cont %> + <%= f.text_field :employees_last_name_cont %> - <%= f.submit "search" %> - <% end %> + <%= f.submit "search" %> +<% end %> +``` ## Contributions From cad65ca0259c99eda552129a9d3922b8f0373a94 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 21 May 2013 14:28:24 +0800 Subject: [PATCH 016/112] Resolve versions conflict between Squeel and Ransack --- ransack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ransack.gemspec b/ransack.gemspec index c558132..f8da91c 100644 --- a/ransack.gemspec +++ b/ransack.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.add_dependency 'activerecord', '~> 3.0' s.add_dependency 'actionpack', '~> 3.0' - s.add_dependency 'polyamorous', '~> 0.5.0' + s.add_dependency 'polyamorous', '~> 0.6.0' s.add_development_dependency 'rspec', '~> 2.8.0' s.add_development_dependency 'machinist', '~> 1.0.6' s.add_development_dependency 'faker', '~> 0.9.5' From 5aefc4643c0229c44449c951c22bad6042cf6225 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 2 Jul 2013 11:27:14 +0200 Subject: [PATCH 017/112] Update README Add Gemfile instructions for using the 'rails-4' branch. --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba9ca24..00b2fbb 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,21 @@ for Ransack (or MetaSearch, for that matter). Try In your Gemfile: ```ruby -gem "ransack" # Last officially released gem +gem "ransack" # Last officially released gem (Rails 3) ``` -Or if you want to use the bleeding edge: +Or if you want to use the bleeding edge (Rails 3): ```ruby gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo ``` +For Rails 4, specify the 'rails-4' branch: + +```ruby +gem 'ransack', :github => 'ernie/ransack', :branch => 'rails-4' +``` + ## Usage Ransack can be used in one of two modes, simple or advanced. From f60123591e59af6b69f3e17927cdca62177f2306 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 2 Jul 2013 12:31:40 +0200 Subject: [PATCH 018/112] Travis-ci: Temporarily comment-out "ruby-head" test Travis currently unable to load from rubygems.org. Tested with ruby 2.0.0-head as well today; same issue. --- .travis.yml | 2 +- README.md | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67018b0..4542256 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ rvm: - 2.0.0 - ree - rbx-18mode - - ruby-head +# - ruby-head env: - RAILS=3-2-stable diff --git a/README.md b/README.md index 00b2fbb..c881f03 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ for Ransack (or MetaSearch, for that matter). Try In your Gemfile: +For Rails 3: + ```ruby gem "ransack" # Last officially released gem (Rails 3) ``` @@ -23,13 +25,13 @@ gem "ransack" # Last officially released gem (Rails 3) Or if you want to use the bleeding edge (Rails 3): ```ruby -gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo +gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo (Rails 3) ``` -For Rails 4, specify the 'rails-4' branch: +For Rails 4, specify the "rails-4" branch: ```ruby -gem 'ransack', :github => 'ernie/ransack', :branch => 'rails-4' +gem "ransack", github: "ernie/ransack", branch: "rails-4" # Use rails 4 branch ``` ## Usage From c795a856a2cfe569ebea2e81b4c0ab2f5632755c Mon Sep 17 00:00:00 2001 From: Andrew Premdas Date: Mon, 22 Jul 2013 14:23:39 +0100 Subject: [PATCH 019/112] #sort_link no longer removes params --- lib/ransack/helpers/form_helper.rb | 5 +++-- spec/ransack/helpers/form_helper_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/ransack/helpers/form_helper.rb b/lib/ransack/helpers/form_helper.rb index 99c7564..17aa142 100644 --- a/lib/ransack/helpers/form_helper.rb +++ b/lib/ransack/helpers/form_helper.rb @@ -59,11 +59,12 @@ module Ransack query_hash = {} query_hash[search.context.search_key] = search_params.merge(:s => "#{attr_name} #{new_dir}") options.merge!(query_hash) + options_for_url = params.merge options url = if routing_proxy && respond_to?(routing_proxy) - send(routing_proxy).url_for(options) + send(routing_proxy).url_for(options_for_url) else - url_for(options) + url_for(options_for_url) end link_to [ERB::Util.h(name), order_indicator_for(current_dir)].compact.join(' ').html_safe, diff --git a/spec/ransack/helpers/form_helper_spec.rb b/spec/ransack/helpers/form_helper_spec.rb index 54d504a..320f3d4 100644 --- a/spec/ransack/helpers/form_helper_spec.rb +++ b/spec/ransack/helpers/form_helper_spec.rb @@ -45,6 +45,28 @@ module Ransack it { should match /people\?people_search%5Bs%5D=name\+asc/ } end + + + context 'view has existing parameters' do + before do + @controller.view_context.params.merge!({exist: 'existing'}) + end + describe '#sort_link should not remove existing params' do + subject { + @controller.view_context.sort_link( + Person.search( + {:sorts => ['name desc']}, + :search_key => 'people_search' + ), + :name, + :controller => 'people' + ) + } + it { + should match /exist\=existing/ + } + end + end end end end From 936a37df20a058c3e4bef7c07a2bf4769d34504f Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 25 Jul 2013 11:29:31 +1000 Subject: [PATCH 020/112] No more support for Ruby 1.8 --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4542256..a0e1f61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,7 @@ rvm: - - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 - - ree - - rbx-18mode -# - ruby-head env: - RAILS=3-2-stable From 94faa32c46e051315a85ff409821983390ce918d Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 25 Jul 2013 11:30:01 +1000 Subject: [PATCH 021/112] Remove test_app line from Contrib guide. Fixes #257 --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 963dd56..406058c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,8 +24,7 @@ Here's a quick guide: to know that you have a clean slate: $ bundle install - $ bundle exec rake test_app - $ bundle exec rake + $ bundle exec rake spec 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need From 4855f81d511a080d982555ee84aec37273f872b8 Mon Sep 17 00:00:00 2001 From: jonatack Date: Sun, 4 Aug 2013 15:34:55 +0200 Subject: [PATCH 022/112] flatten.map => flat_map --- lib/ransack/helpers/form_builder.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index e23462a..557808a 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -163,7 +163,8 @@ module Ransack end else [obj] - end).compact.flatten.map {|v| [prefix, v].compact.join('_')} + end). + compact.flat_map { |v| [prefix, v].compact.join('_') } end def attr_from_base_and_column(base, column) From 87ad87abdab1046911fb661df2c48f14886f5fcb Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 00:01:52 +0200 Subject: [PATCH 023/112] Prepare for Rails 4 compatibility with active_record versioning --- lib/ransack/constants.rb | 7 ++- spec/ransack/predicate_spec.rb | 24 ++++++++-- spec/ransack/search_spec.rb | 14 ++++-- spec/support/schema.rb | 80 +++++++++++++++++----------------- 4 files changed, 79 insertions(+), 46 deletions(-) diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index 01eb3b2..fd79075 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -23,7 +23,12 @@ module Ransack module_function # replace % \ to \% \\ def escape_wildcards(unescaped) - unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') + if ActiveRecord::VERSION::STRING =~ /^3/ + unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') + else + unescaped.to_s.gsub(/\\/){ "\\\\" }.gsub(/%/, "\\%") + end end + end end diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index ff9a00a..e92e8be 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -12,7 +12,14 @@ module Ransack subject.parent_id_cont = 1 expect { subject.result }.to_not raise_error end - it "escapes '%', '.' and '\\\\' in value" do + + it ( + if ActiveRecord::VERSION::STRING =~ /^3/ + "escapes '%', '.' and '\\\\' in value" + else + "escapes % and \\ in value" + end + ) do subject.send(:"#{method}=", '%._\\') subject.result.to_sql.should match(regexp) end @@ -36,7 +43,13 @@ module Ransack end describe 'cont' do - it_has_behavior 'wildcard escaping', :name_cont, /"people"."name" LIKE '%\\%\\._\\\\%'/ do + + it_has_behavior 'wildcard escaping', :name_cont, ( + if ActiveRecord::VERSION::STRING =~ /^3/ + /"people"."name" LIKE '%\\%\\._\\\\%'/ + else + /"people"."name" LIKE '%\\%._\\\\%'/ + end) do subject { @s } end @@ -47,7 +60,12 @@ module Ransack end describe 'not_cont' do - it_has_behavior 'wildcard escaping', :name_not_cont, /"people"."name" NOT LIKE '%\\%\\._\\\\%'/ do + it_has_behavior 'wildcard escaping', :name_not_cont, ( + if ActiveRecord::VERSION::STRING =~ /^3/ + /"people"."name" NOT LIKE '%\\%\\._\\\\%'/ + else + /"people"."name" NOT LIKE '%\\%._\\\\%'/ + end) do subject { @s } end diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 4627d62..7aad44f 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -167,9 +167,17 @@ module Ransack it 'returns distinct records when passed :distinct => true' do search = Search.new(Person, :g => [{:m => 'or', :comments_body_cont => 'e', :articles_comments_body_cont => 'e'}]) - search.result.all.should have(920).items - search.result(:distinct => true).should have(330).items - search.result.all.uniq.should eq search.result(:distinct => true).all + if ActiveRecord::VERSION::STRING =~ /^3/ + all_or_load, uniq_or_distinct = :all, :uniq + else + all_or_load, uniq_or_distinct = :load, :distinct + end + search.result.send(all_or_load). + should have(920).items + search.result(:distinct => true). + should have(330).items + search.result.send(all_or_load).send(uniq_or_distinct). + should eq search.result(distinct: true).send(all_or_load) end end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 119408c..c026dbd 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -6,7 +6,11 @@ ActiveRecord::Base.establish_connection( ) class Person < ActiveRecord::Base - default_scope order('id DESC') + if ActiveRecord::VERSION::STRING =~ /^3/ + default_scope order('id DESC') + else + default_scope { order(id: :desc) } + end belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id has_many :children, :class_name => 'Person', :foreign_key => :parent_id has_many :articles @@ -46,46 +50,44 @@ end module Schema def self.create - ActiveRecord::Base.silence do - ActiveRecord::Migration.verbose = false - - ActiveRecord::Schema.define do - create_table :people, :force => true do |t| - t.integer :parent_id - t.string :name - t.integer :salary - t.boolean :awesome, :default => false - t.timestamps - end - - create_table :articles, :force => true do |t| - t.integer :person_id - t.string :title - t.text :body - end - - create_table :comments, :force => true do |t| - t.integer :article_id - t.integer :person_id - t.text :body - end - - create_table :tags, :force => true do |t| - t.string :name - end - - create_table :articles_tags, :force => true, :id => false do |t| - t.integer :article_id - t.integer :tag_id - end - - create_table :notes, :force => true do |t| - t.integer :notable_id - t.string :notable_type - t.string :note - end + ActiveRecord::Migration.verbose = false + ActiveRecord::Schema.define do + create_table :people, :force => true do |t| + t.integer :parent_id + t.string :name + t.integer :salary + t.boolean :awesome, :default => false + t.timestamps end + + create_table :articles, :force => true do |t| + t.integer :person_id + t.string :title + t.text :body + end + + create_table :comments, :force => true do |t| + t.integer :article_id + t.integer :person_id + t.text :body + end + + create_table :tags, :force => true do |t| + t.string :name + end + + create_table :articles_tags, :force => true, :id => false do |t| + t.integer :article_id + t.integer :tag_id + end + + create_table :notes, :force => true do |t| + t.integer :notable_id + t.string :notable_type + t.string :note + end + end 10.times do From cb2ff12e344723ad20eb1905d129d0c774cf7413 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 00:17:24 +0200 Subject: [PATCH 024/112] Use more explicit ActiveRecord::VERSION::MAJOR --- lib/ransack/constants.rb | 2 +- spec/ransack/predicate_spec.rb | 6 +++--- spec/ransack/search_spec.rb | 2 +- spec/support/schema.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index fd79075..44cdd3d 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -23,7 +23,7 @@ module Ransack module_function # replace % \ to \% \\ def escape_wildcards(unescaped) - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') else unescaped.to_s.gsub(/\\/){ "\\\\" }.gsub(/%/, "\\%") diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index e92e8be..36f9e6e 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -14,7 +14,7 @@ module Ransack end it ( - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 "escapes '%', '.' and '\\\\' in value" else "escapes % and \\ in value" @@ -45,7 +45,7 @@ module Ransack describe 'cont' do it_has_behavior 'wildcard escaping', :name_cont, ( - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 /"people"."name" LIKE '%\\%\\._\\\\%'/ else /"people"."name" LIKE '%\\%._\\\\%'/ @@ -61,7 +61,7 @@ module Ransack describe 'not_cont' do it_has_behavior 'wildcard escaping', :name_not_cont, ( - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 /"people"."name" NOT LIKE '%\\%\\._\\\\%'/ else /"people"."name" NOT LIKE '%\\%._\\\\%'/ diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 7aad44f..4f99836 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -167,7 +167,7 @@ module Ransack it 'returns distinct records when passed :distinct => true' do search = Search.new(Person, :g => [{:m => 'or', :comments_body_cont => 'e', :articles_comments_body_cont => 'e'}]) - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 all_or_load, uniq_or_distinct = :all, :uniq else all_or_load, uniq_or_distinct = :load, :distinct diff --git a/spec/support/schema.rb b/spec/support/schema.rb index c026dbd..e1c4540 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -6,7 +6,7 @@ ActiveRecord::Base.establish_connection( ) class Person < ActiveRecord::Base - if ActiveRecord::VERSION::STRING =~ /^3/ + if ActiveRecord::VERSION::MAJOR == 3 default_scope order('id DESC') else default_scope { order(id: :desc) } From fc5fbcf8b4d60131d8358458e657126a77ee9575 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 18:56:16 +0200 Subject: [PATCH 025/112] Tests: more AR versioning and update routes for Rails 3 + 4 --- spec/ransack/helpers/form_builder_spec.rb | 8 +++- spec/ransack/helpers/form_helper_spec.rb | 51 ++++++++++++++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/spec/ransack/helpers/form_builder_spec.rb b/spec/ransack/helpers/form_builder_spec.rb index f1c0834..b00cd8e 100644 --- a/spec/ransack/helpers/form_builder_spec.rb +++ b/spec/ransack/helpers/form_builder_spec.rb @@ -7,7 +7,7 @@ module Ransack router = ActionDispatch::Routing::RouteSet.new router.draw do resources :people - match ':controller(/:action(/:id(.:format)))' + get ':controller(/:action(/:id(.:format)))' end include router.url_helpers @@ -50,7 +50,11 @@ module Ransack describe '#sort_link' do it 'sort_link for ransack attribute' do sort_link = @f.sort_link :name, :controller => 'people' - sort_link.should match /people\?q%5Bs%5D=name\+asc/ + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + sort_link.should match /people\?q%5Bs%5D=name\+asc/ + else + sort_link.should match /people\?q(%5B|\[)s(%5D|\])=name\+asc/ + end sort_link.should match /sort_link/ sort_link.should match /Full Name<\/a>/ end diff --git a/spec/ransack/helpers/form_helper_spec.rb b/spec/ransack/helpers/form_helper_spec.rb index 320f3d4..292ab8c 100644 --- a/spec/ransack/helpers/form_helper_spec.rb +++ b/spec/ransack/helpers/form_helper_spec.rb @@ -7,7 +7,7 @@ module Ransack router = ActionDispatch::Routing::RouteSet.new router.draw do resources :people - match ':controller(/:action(/:id(.:format)))' + get ':controller(/:action(/:id(.:format)))' end include router.url_helpers @@ -26,24 +26,53 @@ module Ransack end describe '#sort_link with default search_key' do - subject { @controller.view_context.sort_link([:main_app, Person.search(:sorts => ['name desc'])], :name, :controller => 'people') } - it { should match /people\?q%5Bs%5D=name\+asc/ } + subject { + @controller.view_context.sort_link( + [:main_app, Person.search(sorts: ['name desc'])], + :name, controller: 'people' + ) + } + it { should match ( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?q%5Bs%5D=name\+asc/ + else + /people\?q(%5B|\[)s(%5D|\])=name\+asc/ + end) + } it { should match /sort_link desc/ } it { should match /Full Name ▼/ } end describe '#sort_link with default search_key defined as symbol' do - subject { @controller.view_context.sort_link(Person.search({:sorts => ['name desc']}, :search_key => :people_search), - :name, :controller => 'people') } - - it { should match /people\?people_search%5Bs%5D=name\+asc/ } + subject { @controller. + view_context.sort_link( + Person.search({ sorts: ['name desc'] }, search_key: :people_search), + :name, controller: 'people' + ) + } + it { should match ( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?people_search%5Bs%5D=name\+asc/ + else + /people\?people_search(%5B|\[)s(%5D|\])=name\+asc/ + end) + } end describe '#sort_link with default search_key defined as string' do - subject { @controller.view_context.sort_link(Person.search({:sorts => ['name desc']}, :search_key => 'people_search'), - :name, :controller => 'people') } - - it { should match /people\?people_search%5Bs%5D=name\+asc/ } + subject { + @controller.view_context.sort_link( + Person.search({ sorts: ['name desc'] }, search_key: 'people_search'), + :name, controller: 'people' + ) + } + it { should match ( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?people_search%5Bs%5D=name\+asc/ + else + /people\?people_search(%5B|\[)s(%5D|\])=name\+asc/ + end) + } end From 5a522b4f4a38662f4cef764ff8d602a054ec2247 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 19:00:52 +0200 Subject: [PATCH 026/112] Add Rails 4 compatibility to master --- Gemfile | 6 +-- lib/ransack/adapters/active_record.rb | 2 + .../adapters/active_record/3.0/context.rb | 20 +++------ .../adapters/active_record/3.1/context.rb | 21 ++++----- .../adapters/active_record/3.2/context.rb | 44 +++++++++++++++++++ lib/ransack/adapters/active_record/context.rb | 16 ++++--- lib/ransack/context.rb | 16 ++++++- lib/ransack/translate.rb | 14 +++--- ransack.gemspec | 4 +- .../adapters/active_record/context_spec.rb | 6 +++ 10 files changed, 103 insertions(+), 46 deletions(-) create mode 100644 lib/ransack/adapters/active_record/3.2/context.rb 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') From 77cefa62121592814194ce4080e01ae945ed68b7 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 19:07:35 +0200 Subject: [PATCH 027/112] Add Rails 4-0-stable, 3-1-stable, 3-0-stable to travis-ci --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index a0e1f61..460c10d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,7 @@ rvm: - 2.0.0 env: + - RAILS=4-0-stable - RAILS=3-2-stable + - RAILS=3-1-stable + - RAILS=3-0-stable From 39324dfd5ee584c07da7956e945c51e09f117d83 Mon Sep 17 00:00:00 2001 From: jonatack Date: Tue, 6 Aug 2013 19:47:59 +0200 Subject: [PATCH 028/112] Update README --- README.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c881f03..377a7ac 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,13 @@ In your Gemfile: For Rails 3: ```ruby -gem "ransack" # Last officially released gem (Rails 3) +gem "ransack" ``` -Or if you want to use the bleeding edge (Rails 3): +Or if you want to use the bleeding edge (Rails 3 and 4): ```ruby -gem "ransack", :git => "git://github.com/ernie/ransack.git" # Track git repo (Rails 3) -``` - -For Rails 4, specify the "rails-4" branch: - -```ruby -gem "ransack", github: "ernie/ransack", branch: "rails-4" # Use rails 4 branch +gem "ransack", github: "ernie/ransack" # Track git repo ``` ## Usage @@ -54,12 +48,12 @@ If you're coming from MetaSearch, things to note: is passed to it. 3. Common ActiveRecord::Relation methods are no longer delegated by the search object. Instead, you will get your search results (an ActiveRecord::Relation in the case of - the ActiveRecord adapter) via a call to `Search#result`. If passed `:distinct => true`, + the ActiveRecord adapter) via a call to `Search#result`. If passed `distinct: true`, `result` will generate a `SELECT DISTINCT` to avoid returning duplicate rows, even if conditions on a join would otherwise result in some. Please note that for many databases, a sort on an associated table's columns will - result in invalid SQL with `:distinct => true` -- in those cases, you're on your own, + result in invalid SQL with `distinct: true` -- in those cases, you're on your own, and will need to modify the result as needed to allow these queries to work. Thankfully, 9 times out of 10, sort against the search's base is sufficient, though, as that's generally what's being displayed on your results page. @@ -69,7 +63,7 @@ In your controller: ```ruby def index @q = Person.search(params[:q]) - @people = @q.result(:distinct => true) + @people = @q.result(distinct: true) end ``` @@ -101,7 +95,7 @@ This means you'll need to tweak your routes... ```ruby resources :people do collection do - match 'search' => 'people#search', :via => [:get, :post], :as => :search + match 'search' => 'people#search', via: [:get, :post], as: :search end end ``` @@ -118,8 +112,8 @@ end ... and update your `search_form_for` line in the view ... ```erb -<%= search_form_for @q, :url => search_people_path, - :html => {:method => :post} do |f| %> +<%= search_form_for @q, url: search_people_path, + html: { method: :post } do |f| %> ``` Once you've done so, you can make use of the helpers in Ransack::Helpers::FormBuilder to @@ -159,7 +153,7 @@ end class SupervisorsController < ApplicationController def index @search = Supervisor.search(params[:q]) - @supervisors = @search.result(:distinct => true) + @supervisors = @search.result(distinct: true) end end ``` From e70d120a128fb25c759990de2e205577261eed4a Mon Sep 17 00:00:00 2001 From: jonatack Date: Wed, 7 Aug 2013 20:10:38 +0200 Subject: [PATCH 029/112] Maintain Ruby 1.8 compatibility as long as it's supported. --- spec/ransack/helpers/form_helper_spec.rb | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/spec/ransack/helpers/form_helper_spec.rb b/spec/ransack/helpers/form_helper_spec.rb index 292ab8c..5ac18c7 100644 --- a/spec/ransack/helpers/form_helper_spec.rb +++ b/spec/ransack/helpers/form_helper_spec.rb @@ -28,8 +28,8 @@ module Ransack describe '#sort_link with default search_key' do subject { @controller.view_context.sort_link( - [:main_app, Person.search(sorts: ['name desc'])], - :name, controller: 'people' + [:main_app, Person.search(:sorts => ['name desc'])], + :name, :controller => 'people' ) } it { should match ( @@ -46,8 +46,8 @@ module Ransack describe '#sort_link with default search_key defined as symbol' do subject { @controller. view_context.sort_link( - Person.search({ sorts: ['name desc'] }, search_key: :people_search), - :name, controller: 'people' + Person.search({ :sorts => ['name desc'] }, :search_key => :people_search), + :name, :controller => 'people' ) } it { should match ( @@ -62,8 +62,8 @@ module Ransack describe '#sort_link with default search_key defined as string' do subject { @controller.view_context.sort_link( - Person.search({ sorts: ['name desc'] }, search_key: 'people_search'), - :name, controller: 'people' + Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'), + :name, :controller => 'people' ) } it { should match ( @@ -83,12 +83,8 @@ module Ransack describe '#sort_link should not remove existing params' do subject { @controller.view_context.sort_link( - Person.search( - {:sorts => ['name desc']}, - :search_key => 'people_search' - ), - :name, - :controller => 'people' + Person.search({ :sorts => ['name desc'] }, :search_key => 'people_search'), + :name, :controller => 'people' ) } it { From 40b239416cff26605b5f3fe4baa8fe27e642ee7c Mon Sep 17 00:00:00 2001 From: jonatack Date: Thu, 8 Aug 2013 12:50:21 +0200 Subject: [PATCH 030/112] Backwards compatibility fixes for Ruby 1.8.7 --- lib/ransack/helpers/form_builder.rb | 2 +- spec/ransack/helpers/form_helper_spec.rb | 8 +-- spec/ransack/search_spec.rb | 68 ++++++++++++------------ spec/support/schema.rb | 4 +- 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index 557808a..f91dc8b 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -164,7 +164,7 @@ module Ransack else [obj] end). - compact.flat_map { |v| [prefix, v].compact.join('_') } + compact.flatten.map { |v| [prefix, v].compact.join('_') } end def attr_from_base_and_column(base, column) diff --git a/spec/ransack/helpers/form_helper_spec.rb b/spec/ransack/helpers/form_helper_spec.rb index 5ac18c7..1ddfccd 100644 --- a/spec/ransack/helpers/form_helper_spec.rb +++ b/spec/ransack/helpers/form_helper_spec.rb @@ -32,7 +32,7 @@ module Ransack :name, :controller => 'people' ) } - it { should match ( + it { should match( if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ /people\?q%5Bs%5D=name\+asc/ else @@ -50,7 +50,7 @@ module Ransack :name, :controller => 'people' ) } - it { should match ( + it { should match( if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ /people\?people_search%5Bs%5D=name\+asc/ else @@ -66,7 +66,7 @@ module Ransack :name, :controller => 'people' ) } - it { should match ( + it { should match( if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ /people\?people_search%5Bs%5D=name\+asc/ else @@ -78,7 +78,7 @@ module Ransack context 'view has existing parameters' do before do - @controller.view_context.params.merge!({exist: 'existing'}) + @controller.view_context.params.merge!({ :exist => 'existing' }) end describe '#sort_link should not remove existing params' do subject { diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 4f99836..8be0b20 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -32,8 +32,10 @@ module Ransack end it 'creates Conditions for multiple polymorphic belongs_to association attributes' do - search = Search.new(Note, :notable_of_Person_type_name_or_notable_of_Article_type_title_eq => 'Ernie') - condition = search.base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq] + search = Search.new(Note, + :notable_of_Person_type_name_or_notable_of_Article_type_title_eq => 'Ernie') + condition = search. + base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq] condition.should be_a Nodes::Condition condition.predicate.name.should eq 'eq' condition.attributes.first.name.should eq 'notable_of_Person_type_name' @@ -50,8 +52,8 @@ module Ransack it 'accepts arrays of groupings' do search = Search.new(Person, :g => [ - {:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}, - {:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'}, + { :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }, + { :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' }, ] ) ors = search.groupings @@ -66,8 +68,8 @@ module Ransack it 'accepts "attributes" hashes for groupings' do search = Search.new(Person, :g => { - '0' => {:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}, - '1' => {:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'}, + '0' => { :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }, + '1' => { :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' }, } ) ors = search.groupings @@ -82,8 +84,8 @@ module Ransack it 'accepts "attributes" hashes for conditions' do search = Search.new(Person, :c => { - '0' => {:a => ['name'], :p => 'eq', :v => ['Ernie']}, - '1' => {:a => ['children_name', 'parent_name'], :p => 'eq', :v => ['Ernie'], :m => 'or'} + '0' => { :a => ['name'], :p => 'eq', :v => ['Ernie'] }, + '1' => { :a => ['children_name', 'parent_name'], :p => 'eq', :v => ['Ernie'], :m => 'or' } } ) conditions = search.base.conditions @@ -93,8 +95,7 @@ module Ransack it 'creates Conditions for custom predicates that take arrays' do Ransack.configure do |config| - config.add_predicate 'ary_pred', - :wants_array => true + config.add_predicate 'ary_pred', :wants_array => true end search = Search.new(Person, :name_ary_pred => ['Ernie', 'Bert']) @@ -135,11 +136,12 @@ module Ransack it 'evaluates nested conditions' do search = Search.new(Person, :children_name_eq => 'Ernie', - :g => [{ - :m => 'or', - :name_eq => 'Ernie', - :children_children_name_eq => 'Ernie' - }] + :g => [ + { :m => 'or', + :name_eq => 'Ernie', + :children_children_name_eq => 'Ernie' + } + ] ) search.result.should be_an ActiveRecord::Relation where = search.result.where_values.first @@ -151,8 +153,8 @@ module Ransack it 'evaluates arrays of groupings' do search = Search.new(Person, :g => [ - {:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}, - {:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'}, + { :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }, + { :m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert' }, ] ) search.result.should be_an ActiveRecord::Relation @@ -166,7 +168,14 @@ module Ransack end it 'returns distinct records when passed :distinct => true' do - search = Search.new(Person, :g => [{:m => 'or', :comments_body_cont => 'e', :articles_comments_body_cont => 'e'}]) + search = Search.new( + Person, :g => [ + { :m => 'or', + :comments_body_cont => 'e', + :articles_comments_body_cont => 'e' + } + ] + ) if ActiveRecord::VERSION::MAJOR == 3 all_or_load, uniq_or_distinct = :all, :uniq else @@ -177,7 +186,7 @@ module Ransack search.result(:distinct => true). should have(330).items search.result.send(all_or_load).send(uniq_or_distinct). - should eq search.result(distinct: true).send(all_or_load) + should eq search.result(:distinct => true).send(all_or_load) end end @@ -209,19 +218,13 @@ module Ransack it 'creates sorts based on multiple attributes/directions in hash format' do @s.sorts = { - '0' => { - :name => 'id', - :dir => 'desc' - }, - '1' => { - :name => 'name', - :dir => 'asc' - } + '0' => { :name => 'id', :dir => 'desc' }, + '1' => { :name => 'name', :dir => 'asc' } } @s.sorts.should have(2).items - @s.sorts.should be_all {|s| Nodes::Sort === s} - id_sort = @s.sorts.detect {|s| s.name == 'id'} - name_sort = @s.sorts.detect {|s| s.name == 'name'} + @s.sorts.should be_all { |s| Nodes::Sort === s } + id_sort = @s.sorts.detect { |s| s.name == 'id' } + name_sort = @s.sorts.detect { |s| s.name == 'name' } id_sort.dir.should eq 'desc' name_sort.dir.should eq 'asc' end @@ -238,7 +241,7 @@ module Ransack end it 'raises NoMethodError when sent an invalid attribute' do - expect {@s.blah}.to raise_error NoMethodError + expect { @s.blah }.to raise_error NoMethodError end it 'sets condition attributes when sent valid attributes' do @@ -247,8 +250,7 @@ module Ransack end it 'allows chaining to access nested conditions' do - @s.groupings = [{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}] - @s.groupings.first.name_eq.should eq 'Ernie' + @s.groupings = [{ :m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie' }] @s.groupings.first.children_name_eq.should eq 'Ernie' end end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index e1c4540..dbc6f31 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -9,7 +9,9 @@ class Person < ActiveRecord::Base if ActiveRecord::VERSION::MAJOR == 3 default_scope order('id DESC') else - default_scope { order(id: :desc) } + default_scope { order('id DESC') } + # The new activerecord syntax "{ order(id: :desc) }" does not work + # with Ruby 1.8.7 which we still need to support for Rails 3 end belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id has_many :children, :class_name => 'Person', :foreign_key => :parent_id From ed5fc717e0de09dfae48be521637ad4a1e437e38 Mon Sep 17 00:00:00 2001 From: jonatack Date: Thu, 8 Aug 2013 12:53:23 +0200 Subject: [PATCH 031/112] Travis-ci: Add tests for Ruby 1.8.7 with Rails 3 --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 460c10d..a4968b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ rvm: + - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 @@ -8,3 +9,8 @@ env: - RAILS=3-2-stable - RAILS=3-1-stable - RAILS=3-0-stable + +matrix: + exclude: + - rvm: 1.8.7 + env: RAILS=4-0-stable From abbdc5f2ef4935a9ed4430723fe80265179dcbf4 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Thu, 8 Aug 2013 13:34:25 +0200 Subject: [PATCH 032/112] Update README for release --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 377a7ac..b45893c 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,11 @@ for Ransack (or MetaSearch, for that matter). Try In your Gemfile: -For Rails 3: - ```ruby -gem "ransack" +gem "ransack" # Last officially released gem (Rails 3 and 4) ``` -Or if you want to use the bleeding edge (Rails 3 and 4): +Or if you want to use the bleeding edge: ```ruby gem "ransack", github: "ernie/ransack" # Track git repo From 7df31415e7253871e1e979b93f1e18b5bc4db502 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Fri, 9 Aug 2013 20:05:24 +0200 Subject: [PATCH 033/112] Release 1.0.0 (Rails 3 and 4 compatible) --- lib/ransack/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ransack/version.rb b/lib/ransack/version.rb index d2f0d8c..c472356 100644 --- a/lib/ransack/version.rb +++ b/lib/ransack/version.rb @@ -1,3 +1,3 @@ module Ransack - VERSION = "0.7.3" + VERSION = "1.0.0" end From be7c227a9547a359691258b0b10fb1842ae8de41 Mon Sep 17 00:00:00 2001 From: jonatack Date: Mon, 12 Aug 2013 19:59:19 +0200 Subject: [PATCH 034/112] Fix typo --- spec/ransack/adapters/active_record/context_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ransack/adapters/active_record/context_spec.rb b/spec/ransack/adapters/active_record/context_spec.rb index b1e89fc..fb171bd 100644 --- a/spec/ransack/adapters/active_record/context_spec.rb +++ b/spec/ransack/adapters/active_record/context_spec.rb @@ -13,7 +13,7 @@ module Ransack end describe '#evaluate' do - it 'evaluates search obects' do + it 'evaluates search objects' do search = Search.new(Person, :name_eq => 'Joe Blow') result = subject.evaluate(search) From b1644d4d2450558ba84fb9fdc9161869efe95ec4 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Mon, 12 Aug 2013 23:06:46 +0200 Subject: [PATCH 035/112] Fix #158 feature request (remove empty search params from sort_link params hash and URL) Builds on the discussion in PR #207. Submitted as a pull request to see if there is interest in having a shorter sort_link URL. If yes, will need some test coverage. --- lib/ransack/search.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ransack/search.rb b/lib/ransack/search.rb index ddd732a..4d4df9d 100644 --- a/lib/ransack/search.rb +++ b/lib/ransack/search.rb @@ -18,6 +18,8 @@ module Ransack @context = Context.for(object, options) @context.auth_object = options[:auth_object] @base = Nodes::Grouping.new(@context, 'and') + params = (params.delete_if { |k, v| v.blank? && v != false } + ) if params.present? build(params.with_indifferent_access) end From 642a5fc09c471838d8de00b108bb6a2d36ad3c21 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Fri, 16 Aug 2013 21:11:14 +0200 Subject: [PATCH 036/112] No need for nil or presence checking --- lib/ransack/search.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ransack/search.rb b/lib/ransack/search.rb index 4d4df9d..05c3413 100644 --- a/lib/ransack/search.rb +++ b/lib/ransack/search.rb @@ -14,12 +14,10 @@ module Ransack :translate, :to => :base def initialize(object, params = {}, options = {}) - params ||= {} + (params ||= {}).delete_if { |k, v| v.blank? && v != false } @context = Context.for(object, options) @context.auth_object = options[:auth_object] @base = Nodes::Grouping.new(@context, 'and') - params = (params.delete_if { |k, v| v.blank? && v != false } - ) if params.present? build(params.with_indifferent_access) end From ba6a8fcb185daaf58b96018e639bb7389deea089 Mon Sep 17 00:00:00 2001 From: Bonias Date: Thu, 5 Sep 2013 11:13:03 +0200 Subject: [PATCH 037/112] Fixes issue #273 - translations for namespaced models. ActiveRecord uses i18n_key methods which return "namespace/model_name"("namespace.model_name" in rails 3.0.x) for Namespace::ModelName. Ransack should used the same pattern. --- lib/ransack/translate.rb | 22 +++++++++++++++------- spec/ransack/translate_spec.rb | 14 ++++++++++++++ spec/support/en.yml | 6 ++++++ spec/support/schema.rb | 6 ++++++ 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 spec/ransack/translate_spec.rb diff --git a/lib/ransack/translate.rb b/lib/ransack/translate.rb index c2e0334..ec77c19 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.singular}.#{original_name}" + :"ransack.attributes.#{i18n_key(klass)}.#{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.singular}"] : [:"ransack.associations.#{context.klass.model_name.singular}.#{key}"] + defaults = key.blank? ? [:"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}"] : [:"ransack.associations.#{i18n_key(context.klass)}.#{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.singular}.#{attr_name}" : - :"ransack.attributes.#{context.klass.model_name.singular}.#{attr_name}" + :"ransack.attributes.#{i18n_key(associated_class)}.#{attr_name}" : + :"ransack.attributes.#{i18n_key(context.klass)}.#{attr_name}" ), :default => [ (associated_class ? - :"#{associated_class.i18n_scope}.attributes.#{associated_class.model_name.singular}.#{attr_name}" : - :"#{context.klass.i18n_scope}.attributes.#{context.klass.model_name.singular}.#{attr_name}" + :"#{associated_class.i18n_scope}.attributes.#{i18n_key(associated_class)}.#{attr_name}" : + :"#{context.klass.i18n_scope}.attributes.#{i18n_key(context.klass)}.#{attr_name}" ), :".attributes.#{attr_name}", attr_name.humanize ] ) defaults = [ - :"ransack.attributes.#{context.klass.model_name.singular}.#{name}" + :"ransack.attributes.#{i18n_key(context.klass)}.#{name}" ] if include_associations && associated_class defaults << '%{association_name} %{attr_fallback_name}' @@ -89,5 +89,13 @@ module Ransack options = {:count => 1, :default => defaults} I18n.translate(defaults.shift, options.merge(interpolations)) end + + def self.i18n_key(klass) + if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 + klass.model_name.i18n_key.to_s.tr('.', '/') + else + klass.model_name.i18n_key.to_s + end + end end end diff --git a/spec/ransack/translate_spec.rb b/spec/ransack/translate_spec.rb new file mode 100644 index 0000000..4ce2a21 --- /dev/null +++ b/spec/ransack/translate_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +module Ransack + describe Translate do + + describe '.attribute' do + it 'translate namespaced attribute like AR does' do + ar_translation = ::Namespace::Article.human_attribute_name(:title) + ransack_translation = Ransack::Translate.attribute(:title, :context => ::Namespace::Article.search.context) + ransack_translation.should eq ar_translation + end + end + end +end diff --git a/spec/support/en.yml b/spec/support/en.yml index 503d50c..57de6af 100644 --- a/spec/support/en.yml +++ b/spec/support/en.yml @@ -5,3 +5,9 @@ en: attributes: person: name: Full Name + activerecord: + attributes: + namespace/article: + title: AR Namespaced Title + namespace_article: + title: Old Ransack Namespaced Title diff --git a/spec/support/schema.rb b/spec/support/schema.rb index dbc6f31..22ae79a 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -37,6 +37,12 @@ class Article < ActiveRecord::Base has_many :notes, :as => :notable end +module Namespace + class Article < ::Article + + end +end + class Comment < ActiveRecord::Base belongs_to :article belongs_to :person From d66e7c7513285b1f20a5050227447a55fbe36f62 Mon Sep 17 00:00:00 2001 From: Niels Kristian Date: Mon, 7 Oct 2013 13:47:52 +0200 Subject: [PATCH 038/112] Fixed merge conflicts --- README.md | 5 +++ lib/ransack/locale/cs.yml | 70 ---------------------------------- lib/ransack/locale/es.yml | 70 ---------------------------------- spec/ransack/predicate_spec.rb | 4 ++ 4 files changed, 9 insertions(+), 140 deletions(-) delete mode 100644 lib/ransack/locale/cs.yml delete mode 100644 lib/ransack/locale/es.yml diff --git a/README.md b/README.md index b45893c..31ed939 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,11 @@ end <% end %> ``` +## I18n + +Take a look at our locale file on ``lib/ransack/locale/en.yml`` to check all available messages. You may also be interested in one of the many translations that are available on: + +http://www.localeapp.com/projects/2999 ## Contributions diff --git a/lib/ransack/locale/cs.yml b/lib/ransack/locale/cs.yml deleted file mode 100644 index cfd61b6..0000000 --- a/lib/ransack/locale/cs.yml +++ /dev/null @@ -1,70 +0,0 @@ -cs: - ransack: - search: "vyhledávání" - predicate: "predikát" - and: "a" - or: "nebo" - any: "kteroukoliv" - all: "každou" - combinator: "kombinátor" - attribute: "atribut" - value: "hodnota" - condition: "podmínka" - sort: "řazení" - asc: "vzestupné" - desc: "sestupné" - predicates: - eq: "rovno" - eq_any: "rovno kterékoliv" - eq_all: "rovno všem" - not_eq: "nerovno" - not_eq_any: "nerovno kterékoliv" - not_eq_all: "nerovno všem" - matches: "odpovídá" - matches_any: "odpovídá kterékoliv" - matches_all: "odpovídá všem" - does_not_match: "neodpovídá" - does_not_match_any: "neodpovídá kterékoliv" - does_not_match_all: "neodpovídá všem" - lt: "menší než" - lt_any: "menší než kterákoliv" - lt_all: "menší než všechny" - lteq: "menší nebo rovno než" - lteq_any: "menší nebo rovno než kterákoliv" - lteq_all: "menší nebo rovno než všechny" - gt: "větší než" - gt_any: "větší než kterákoliv" - gt_all: "větší než všechny" - gteq: "větší nebo rovno než" - gteq_any: "větší nebo rovno než kterákoliv" - gteq_all: "větší nebo rovno než všechny" - in: "v" - in_any: "v kterékoliv" - in_all: "ve všech" - not_in: "není v" - not_in_any: "není v kterékoliv" - not_in_all: "není ve všech" - cont: "obsahuje" - cont_any: "obsahuje kterékoliv" - cont_all: "obsahuje všechny" - not_cont: "neobsahuje" - not_cont_any: "neobsahuje kteroukoliv" - not_cont_all: "neobsahuje všechny" - start: "začíná s" - start_any: "začíná s kteroukoliv" - start_all: "začíná se všemi" - not_start: "nezačíná s" - not_start_any: "nezačíná s kteroukoliv" - not_start_all: "nezačíná se všemi" - end: "končí s" - end_any: "končí s kteroukoliv" - end_all: "končí se všemi" - not_end: "nekončí s" - not_end_any: "nekončí s kteroukoliv" - not_end_all: "nekončí se všemi" - 'true': "je pravdivé" - 'false': "není pravdivé" - present: "je vyplněné" - blank: "je prázdné" - 'null': "je null" - not_null: "není null" diff --git a/lib/ransack/locale/es.yml b/lib/ransack/locale/es.yml deleted file mode 100644 index fa05bd0..0000000 --- a/lib/ransack/locale/es.yml +++ /dev/null @@ -1,70 +0,0 @@ -es: - ransack: - search: "buscar" - predicate: "predicado" - and: "y" - or: "o" - any: "cualquier" - all: "todos" - combinator: "combinado" - attribute: "atributo" - value: "valor" - condition: "condición" - sort: "ordernar" - asc: "ascendente" - desc: "descendente" - predicates: - eq: "es igual a" - eq_any: "es igual a cualquier" - eq_all: "es igual a todos" - not_eq: "no es igual a" - not_eq_any: "no es igual a cualquier" - not_eq_all: "no es iguala todos" - matches: "coincidir" - matches_any: "coincidir a cualquier" - matches_all: "coincidir a todos" - does_not_match: "no coincide" - does_not_match_any: "no coincide con ninguna" - does_not_match_all: "no coincide con todos" - lt: "menor que" - lt_any: "menor que cualquier" - lt_all: "menor o igual a" - lteq: "menor que o igual a" - lteq_any: "menor o igual a cualquier" - lteq_all: "menor o igual a todos" - gt: "mayor que" - gt_any: "mayor que cualquier" - gt_all: "mayor que todos" - gteq: "mayor que o igual a" - gteq_any: "mayor que o igual a cualquier" - gteq_all: "mayor que o igual a todos" - in: "en" - in_any: "en cualquier" - in_all: "en todos" - not_in: "no en" - not_in_any: "no en cualquier" - not_in_all: "no en todos" - cont: "contiene" - cont_any: "contiene cualquier" - cont_all: "contiene todos" - not_cont: "no contiene" - not_cont_any: "no contiene ninguna" - not_cont_all: "no contiene toda" - start: "comienza con" - start_any: "comienza con cualquier" - start_all: "comienza con toda" - not_start: "no inicia con" - not_start_any: "no comienza con cualquier" - not_start_all: "no inicia con toda" - end: "termina con" - end_any: "termina con cualquier" - end_all: "termina con todo" - not_end: "no termina con" - not_end_any: "no termina con cualquier" - not_end_all: "no termina con todo" - 'true': "es verdadero" - 'false': "es falso" - present: "es presente" - blank: "está en blanco" - 'null': "es nula" - not_null: "no es nula" diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index 36f9e6e..08135c7 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -57,6 +57,10 @@ module Ransack @s.name_cont = 'ric' @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/ end + it 'escapes % and \\ in value' do + @s.name_cont = '%\\' + @s.result.to_sql.should match /"people"."name" LIKE '%\\%\\\\%'/ + end end describe 'not_cont' do From 8d2d14bb2a111e22db6b3d061a81be29433dbf3b Mon Sep 17 00:00:00 2001 From: Niels Kristian Date: Mon, 7 Oct 2013 13:56:24 +0200 Subject: [PATCH 039/112] Removed fr.yml locale --- lib/ransack/locale/fr.yml | 70 --------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 lib/ransack/locale/fr.yml diff --git a/lib/ransack/locale/fr.yml b/lib/ransack/locale/fr.yml deleted file mode 100644 index de928f4..0000000 --- a/lib/ransack/locale/fr.yml +++ /dev/null @@ -1,70 +0,0 @@ -fr: - ransack: - search: "recherche" - predicate: "prédicat" - and: "et" - or: "ou" - any: "au moins un" - all: "tous" - combinator: "combinateur" - attribute: "attribut" - value: "valeur" - condition: "condition" - sort: "tri" - asc: "ascendant" - desc: "descendant" - predicates: - eq: "égal à" - eq_any: "égal à au moins un" - eq_all: "égal à tous" - not_eq: "différent de" - not_eq_any: "différent d'au moins un" - not_eq_all: "différent de tous" - matches: "correspond à" - matches_any: "correspond à au moins un" - matches_all: "correspond à tous" - does_not_match: "ne correspond pas à" - does_not_match_any: "ne correspond pas à au moins un" - does_not_match_all: "ne correspond à aucun" - lt: "inférieur à" - lt_any: "inférieur à au moins un" - lt_all: "inférieur à tous" - lteq: "inférieur ou égal à" - lteq_any: "inférieur ou égal à au moins un" - lteq_all: "inférieur ou égal à tous" - gt: "supérieur à" - gt_any: "supérieur à au moins un" - gt_all: "supérieur à tous" - gteq: "supérieur ou égal à" - gteq_any: "supérieur ou égal à au moins un" - gteq_all: "supérieur ou égal à tous" - in: "inclus dans" - in_any: "inclus dans au moins un" - in_all: "inclus dans tous" - not_in: "non inclus dans" - not_in_any: "non inclus dans au moins un" - not_in_all: "non inclus dans tous" - cont: "contient" - cont_any: "contient au moins un" - cont_all: "contient tous" - not_cont: "ne contient pas" - not_cont_any: "ne contient pas au moins un" - not_cont_all: "ne contient pas tous" - start: "commence par" - start_any: "commence par au moins un" - start_all: "commence par tous" - not_start: "ne commence pas par" - not_start_any: "ne commence pas par au moins un" - not_start_all: "ne commence pas par tous" - end: "finit par" - end_any: "finit par au moins un" - end_all: "finit par tous" - not_end: "ne finit pas par" - not_end_any: "ne finit pas par au moins un" - not_end_all: "ne finit pas par tous" - 'true': "est vrai" - 'false': "est faux" - present: "est présent" - blank: "est blanc" - 'null': "est null" - not_null: "n'est pas null" From adb18c975a0af7097b1820fd0cdf3c53eb793df5 Mon Sep 17 00:00:00 2001 From: Niels Kristian Date: Tue, 8 Oct 2013 14:51:56 +0200 Subject: [PATCH 040/112] Removed unwanted spec --- spec/ransack/predicate_spec.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index 08135c7..36f9e6e 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -57,10 +57,6 @@ module Ransack @s.name_cont = 'ric' @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/ end - it 'escapes % and \\ in value' do - @s.name_cont = '%\\' - @s.result.to_sql.should match /"people"."name" LIKE '%\\%\\\\%'/ - end end describe 'not_cont' do From 63b52638867923cee89c91a92770131608116906 Mon Sep 17 00:00:00 2001 From: kia84 Date: Tue, 15 Oct 2013 12:38:54 +0400 Subject: [PATCH 041/112] fixed 'DESC' and 'desc' problem Fixes #287 --- lib/ransack/nodes/sort.rb | 1 + spec/ransack/search_spec.rb | 68 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/lib/ransack/nodes/sort.rb b/lib/ransack/nodes/sort.rb index 75cde2b..d61de31 100644 --- a/lib/ransack/nodes/sort.rb +++ b/lib/ransack/nodes/sort.rb @@ -33,6 +33,7 @@ module Ransack end def dir=(dir) + dir = dir.try(:downcase) @dir = %w(asc desc).include?(dir) ? dir : 'asc' end diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 8be0b20..4894515 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -204,6 +204,24 @@ module Ransack sort.dir.should eq 'desc' end + it 'creates sorts based on a single attribute and uppercase direction' do + @s.sorts = 'id DESC' + @s.sorts.should have(1).item + sort = @s.sorts.first + sort.should be_a Nodes::Sort + sort.name.should eq 'id' + sort.dir.should eq 'desc' + end + + it 'creates sorts based on a single attribute and without direction' do + @s.sorts = 'id' + @s.sorts.should have(1).item + sort = @s.sorts.first + sort.should be_a Nodes::Sort + sort.name.should eq 'id' + sort.dir.should eq 'asc' + end + it 'creates sorts based on multiple attributes/directions in array format' do @s.sorts = ['id desc', 'name asc'] @s.sorts.should have(2).items @@ -216,6 +234,30 @@ module Ransack sort2.dir.should eq 'asc' end + it 'creates sorts based on multiple attributes and uppercase directions in array format' do + @s.sorts = ['id DESC', 'name ASC'] + @s.sorts.should have(2).items + sort1, sort2 = @s.sorts + sort1.should be_a Nodes::Sort + sort1.name.should eq 'id' + sort1.dir.should eq 'desc' + sort2.should be_a Nodes::Sort + sort2.name.should eq 'name' + sort2.dir.should eq 'asc' + end + + it 'creates sorts based on multiple attributes and different directions in array format' do + @s.sorts = ['id DESC', 'name'] + @s.sorts.should have(2).items + sort1, sort2 = @s.sorts + sort1.should be_a Nodes::Sort + sort1.name.should eq 'id' + sort1.dir.should eq 'desc' + sort2.should be_a Nodes::Sort + sort2.name.should eq 'name' + sort2.dir.should eq 'asc' + end + it 'creates sorts based on multiple attributes/directions in hash format' do @s.sorts = { '0' => { :name => 'id', :dir => 'desc' }, @@ -229,6 +271,32 @@ module Ransack name_sort.dir.should eq 'asc' end + it 'creates sorts based on multiple attributes and uppercase directions in hash format' do + @s.sorts = { + '0' => { :name => 'id', :dir => 'DESC' }, + '1' => { :name => 'name', :dir => 'ASC' } + } + @s.sorts.should have(2).items + @s.sorts.should be_all { |s| Nodes::Sort === s } + id_sort = @s.sorts.detect { |s| s.name == 'id' } + name_sort = @s.sorts.detect { |s| s.name == 'name' } + id_sort.dir.should eq 'desc' + name_sort.dir.should eq 'asc' + end + + it 'creates sorts based on multiple attributes and different directions in hash format' do + @s.sorts = { + '0' => { :name => 'id', :dir => 'DESC' }, + '1' => { :name => 'name', :dir => nil } + } + @s.sorts.should have(2).items + @s.sorts.should be_all { |s| Nodes::Sort === s } + id_sort = @s.sorts.detect { |s| s.name == 'id' } + name_sort = @s.sorts.detect { |s| s.name == 'name' } + id_sort.dir.should eq 'desc' + name_sort.dir.should eq 'asc' + end + it 'overrides existing sort' do @s.sorts = 'id asc' @s.result.first.id.should eq 1 From 47d7a95eacd082b36df85e79ac2e470b94b60065 Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Thu, 24 Oct 2013 12:56:45 -0300 Subject: [PATCH 042/112] Allow sort by a field, and not use in search. Accepts sort column only if it's a ransortable_attribute. accepts sort column only if it's a ransortable_attribute. --- lib/ransack/context.rb | 5 +++-- lib/ransack/nodes/sort.rb | 5 +++-- .../adapters/active_record/base_spec.rb | 21 ++++++++++++++++++- spec/support/schema.rb | 16 ++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/ransack/context.rb b/lib/ransack/context.rb index 5ec1ef6..3a3fbb3 100644 --- a/lib/ransack/context.rb +++ b/lib/ransack/context.rb @@ -120,7 +120,8 @@ module Ransack end def ransackable_attribute?(str, klass) - klass.ransackable_attributes(auth_object).include? str + klass.ransackable_attributes(auth_object).include?(str) || + klass.ransortable_attributes(auth_object).include?(str) end def ransackable_association?(str, klass) @@ -140,4 +141,4 @@ module Ransack end end -end \ No newline at end of file +end diff --git a/lib/ransack/nodes/sort.rb b/lib/ransack/nodes/sort.rb index d61de31..1e55432 100644 --- a/lib/ransack/nodes/sort.rb +++ b/lib/ransack/nodes/sort.rb @@ -24,7 +24,8 @@ module Ransack end def valid? - bound? && attr + bound? && attr && + context.klassify(parent).ransortable_attributes.include?(attr_name) end def name=(name) @@ -39,4 +40,4 @@ module Ransack end end -end \ No newline at end of file +end diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index a827984..302da17 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -48,6 +48,21 @@ module Ransack s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith') s.result.count.should eq 1 end if defined?(Arel::Nodes::InfixOperation) + + it 'allows sort by "only_sort" field' do + s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_sort"}}) + s.result.to_sql.should match /ORDER BY "people"."name" \|\| "only_sort" \|\| "people"."name" ASC/ + end + + it "doesn't sort by 'only_search' field" do + s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_search"}}) + s.result.to_sql.should_not match /ORDER BY "people"."name" \|\| "only_search" \|\| "people"."name" ASC/ + end + + it "can't be searched by 'only_sort'" do + s = Person.search(:only_sort_eq => 'htimS cirA') + s.result.to_sql.should_not match /'htimS cirA'/ + end end describe '#ransackable_attributes' do @@ -56,6 +71,8 @@ module Ransack it { should include 'name' } it { should include 'reversed_name' } it { should include 'doubled_name' } + it { should include 'only_search' } + it { should_not include 'only_sort' } end describe '#ransortable_attributes' do @@ -64,6 +81,8 @@ module Ransack it { should include 'name' } it { should include 'reversed_name' } it { should include 'doubled_name' } + it { should include 'only_sort' } + it { should_not include 'only_search' } end describe '#ransackable_associations' do @@ -77,4 +96,4 @@ module Ransack end end end -end \ No newline at end of file +end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index dbc6f31..601d054 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -28,6 +28,22 @@ class Person < ActiveRecord::Base ransacker :doubled_name do |parent| Arel::Nodes::InfixOperation.new('||', parent.table[:name], parent.table[:name]) end + + ransacker :only_search, :formatter => proc {|v| "only_search#{v}"} do |parent| + Arel::Nodes::InfixOperation.new('|| "only_search" ||', parent.table[:name], parent.table[:name]) + end + + ransacker :only_sort, :formatter => proc {|v| "only_sort#{v}"} do |parent| + Arel::Nodes::InfixOperation.new('|| "only_sort" ||', parent.table[:name], parent.table[:name]) + end + + def self.ransackable_attributes(auth_object = nil) + column_names + _ransackers.keys - ['only_sort'] + end + + def self.ransortable_attributes(auth_object = nil) + column_names + _ransackers.keys - ['only_search'] + end end class Article < ActiveRecord::Base From ff617be5730663174a1ebf5f9bb6a225e7306ece Mon Sep 17 00:00:00 2001 From: Johnny Shields Date: Wed, 30 Oct 2013 06:46:43 +0900 Subject: [PATCH 043/112] ORM agnosticism: do not `require activerecord`, and instead only load the ransack AR adapters if AR has already been defined --- lib/ransack.rb | 2 +- lib/ransack/adapters/active_record.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/ransack.rb b/lib/ransack.rb index e418739..2ceeebf 100644 --- a/lib/ransack.rb +++ b/lib/ransack.rb @@ -19,7 +19,7 @@ end require 'ransack/translate' require 'ransack/search' require 'ransack/ransacker' -require 'ransack/adapters/active_record' +require 'ransack/adapters/active_record' if defined?(::ActiveRecord::Base) require 'ransack/helpers' require 'action_controller' diff --git a/lib/ransack/adapters/active_record.rb b/lib/ransack/adapters/active_record.rb index ca7c94e..5108a94 100644 --- a/lib/ransack/adapters/active_record.rb +++ b/lib/ransack/adapters/active_record.rb @@ -1,4 +1,3 @@ -require 'active_record' require 'ransack/adapters/active_record/base' ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base From 852c3db6c54cd4a7202617b5fda7e8e124f7fd03 Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Tue, 29 Oct 2013 20:16:49 -0300 Subject: [PATCH 044/112] Only ransackable_attributes are valid for search. Fix spec and add one to test search valid attributes. Remove unused formatter from schema.rb. --- lib/ransack/nodes/attribute.rb | 5 +++-- spec/ransack/adapters/active_record/base_spec.rb | 7 ++++++- spec/support/schema.rb | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/ransack/nodes/attribute.rb b/lib/ransack/nodes/attribute.rb index 3e6792e..20d9ca6 100644 --- a/lib/ransack/nodes/attribute.rb +++ b/lib/ransack/nodes/attribute.rb @@ -19,7 +19,8 @@ module Ransack end def valid? - bound? && attr + bound? && attr && + context.klassify(parent).ransackable_attributes.include?(attr_name) end def type @@ -50,4 +51,4 @@ module Ransack end end -end \ No newline at end of file +end diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 302da17..90c65f5 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -59,9 +59,14 @@ module Ransack s.result.to_sql.should_not match /ORDER BY "people"."name" \|\| "only_search" \|\| "people"."name" ASC/ end + it 'allows search by "only_search" field' do + s = Person.search(:only_search_eq => 'htimS cirA') + s.result.to_sql.should match /WHERE "people"."name" \|\| "only_search" \|\| "people"."name" = 'htimS cirA'/ + end + it "can't be searched by 'only_sort'" do s = Person.search(:only_sort_eq => 'htimS cirA') - s.result.to_sql.should_not match /'htimS cirA'/ + s.result.to_sql.should_not match /WHERE "people"."name" \|\| "only_sort" \|\| "people"."name" = 'htimS cirA'/ end end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 601d054..e406392 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -29,11 +29,11 @@ class Person < ActiveRecord::Base Arel::Nodes::InfixOperation.new('||', parent.table[:name], parent.table[:name]) end - ransacker :only_search, :formatter => proc {|v| "only_search#{v}"} do |parent| + ransacker :only_search do |parent| Arel::Nodes::InfixOperation.new('|| "only_search" ||', parent.table[:name], parent.table[:name]) end - ransacker :only_sort, :formatter => proc {|v| "only_sort#{v}"} do |parent| + ransacker :only_sort do |parent| Arel::Nodes::InfixOperation.new('|| "only_sort" ||', parent.table[:name], parent.table[:name]) end From bf2fb8828454cd553552c04cb94cf4141845e240 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 15:58:30 +1100 Subject: [PATCH 045/112] Add testing support for MySQL and PostgreSQL databases Conflicts: spec/support/schema.rb --- ransack.gemspec | 2 ++ spec/spec_helper.rb | 3 ++- spec/support/schema.rb | 25 +++++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/ransack.gemspec b/ransack.gemspec index 51b145b..05fc028 100644 --- a/ransack.gemspec +++ b/ransack.gemspec @@ -21,6 +21,8 @@ Gem::Specification.new do |s| s.add_development_dependency 'machinist', '~> 1.0.6' s.add_development_dependency 'faker', '~> 0.9.5' s.add_development_dependency 'sqlite3', '~> 1.3.3' + s.add_development_dependency 'pg', '0.17.0' + s.add_development_dependency 'mysql2', '0.3.13' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 203a3ec..a25d698 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,7 +24,8 @@ RSpec.configure do |config| config.before(:suite) do puts '=' * 80 - puts "Running specs against ActiveRecord #{ActiveRecord::VERSION::STRING} and ARel #{Arel::VERSION}..." + connection_name = ActiveRecord::Base.connection.adapter_name + puts "Running specs against #{connection_name}, ActiveRecord #{ActiveRecord::VERSION::STRING} and ARel #{Arel::VERSION}..." puts '=' * 80 Schema.create end diff --git a/spec/support/schema.rb b/spec/support/schema.rb index dbc6f31..1cb719b 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -1,9 +1,26 @@ require 'active_record' -ActiveRecord::Base.establish_connection( - :adapter => 'sqlite3', - :database => ':memory:' -) +case ENV['DB'] +when "mysql" + ActiveRecord::Base.establish_connection( + adapter: 'mysql2', + database: 'ransack', + encoding: 'utf8' + ) +when "postgres" + ActiveRecord::Base.establish_connection( + adapter: 'postgresql', + database: 'ransack', + username: 'postgres', + min_messages: 'warning' + ) +else + # Assume SQLite3 + ActiveRecord::Base.establish_connection( + adapter: 'sqlite3', + database: ':memory:' + ) +end class Person < ActiveRecord::Base if ActiveRecord::VERSION::MAJOR == 3 From 1279aee8901d9a65269a8b76937a05c5272e6841 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 16:19:48 +1100 Subject: [PATCH 046/112] Add pry for great debugging --- ransack.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ransack.gemspec b/ransack.gemspec index 05fc028..fcfd9fe 100644 --- a/ransack.gemspec +++ b/ransack.gemspec @@ -23,6 +23,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'sqlite3', '~> 1.3.3' s.add_development_dependency 'pg', '0.17.0' s.add_development_dependency 'mysql2', '0.3.13' + s.add_development_dependency 'pry', '0.9.12.2' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") From 810a954477367e88b89b73d3828bf7816d5f3325 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 16:37:00 +1100 Subject: [PATCH 047/112] Add email field to Person model (for wildcard testing, coming soon) --- spec/blueprints/people.rb | 1 + spec/support/schema.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/blueprints/people.rb b/spec/blueprints/people.rb index b7ba882..42b0292 100644 --- a/spec/blueprints/people.rb +++ b/spec/blueprints/people.rb @@ -1,4 +1,5 @@ Person.blueprint do name + email { "test@example.com" } salary end \ No newline at end of file diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 1cb719b..5d1056b 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -75,6 +75,7 @@ module Schema create_table :people, :force => true do |t| t.integer :parent_id t.string :name + t.string :email t.integer :salary t.boolean :awesome, :default => false t.timestamps From 6060acf870c614c8e6465a22d9040f561c3dbb15 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:20:51 +1100 Subject: [PATCH 048/112] Fix overly aggressive escaping on databases that are not PostgreSQL I am unsure if this is necessary for any other databases. Relevant to #171 Fixes #176 Fixes spree/spree#3936 --- lib/ransack/constants.rb | 10 +++--- spec/helpers/ransack_helper.rb | 7 ++++ .../adapters/active_record/base_spec.rb | 33 +++++++++++++++++-- spec/ransack/predicate_spec.rb | 28 +++++++--------- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index 44cdd3d..47d67c2 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -23,10 +23,12 @@ module Ransack module_function # replace % \ to \% \\ def escape_wildcards(unescaped) - if ActiveRecord::VERSION::MAJOR == 3 - unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') - else - unescaped.to_s.gsub(/\\/){ "\\\\" }.gsub(/%/, "\\%") + case ActiveRecord::Base.connection.adapter_name + when "SQLite" + unescaped + else + # Necessary for PostgreSQL + unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') end end diff --git a/spec/helpers/ransack_helper.rb b/spec/helpers/ransack_helper.rb index b7374aa..dfdaceb 100644 --- a/spec/helpers/ransack_helper.rb +++ b/spec/helpers/ransack_helper.rb @@ -1,2 +1,9 @@ module RansackHelper + def quote_table_name(table) + ActiveRecord::Base.connection.quote_table_name(table) + end + + def quote_column_name(column) + ActiveRecord::Base.connection.quote_column_name(column) + end end \ No newline at end of file diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index a827984..62c013f 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -20,6 +20,15 @@ module Ransack end describe '#ransacker' do + # For infix tests + def self.sane_adapter? + case ::ActiveRecord::Base.connection.adapter_name + when "SQLite3" || "PostgreSQL" + true + else + false + end + end # in schema.rb, class Person: # ransacker :reversed_name, :formatter => proc {|v| v.reverse} do |parent| # parent.table[:name] @@ -36,18 +45,36 @@ module Ransack it 'can be accessed through associations' do s = Person.search(:children_reversed_name_eq => 'htimS cirA') - s.result.to_sql.should match /"children_people"."name" = 'Aric Smith'/ + + s.result.to_sql.should match /#{quote_table_name("children_people")}.#{quote_column_name("name")} = 'Aric Smith'/ end it 'allows an "attribute" to be an InfixOperation' do s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith') s.result.first.should eq Person.find_by_name('Aric Smith') - end if defined?(Arel::Nodes::InfixOperation) + end if defined?(Arel::Nodes::InfixOperation) && sane_adapter? it "doesn't break #count if using InfixOperations" do s = Person.search(:doubled_name_eq => 'Aric SmithAric Smith') s.result.count.should eq 1 - end if defined?(Arel::Nodes::InfixOperation) + end if defined?(Arel::Nodes::InfixOperation) && sane_adapter? + + it "should function correctly when using fields with dots in them" do + s = Person.search(email_cont: "example.com") + s.result.exists?.should be_true + end + + it "should function correctly when using fields with % in them" do + Person.create!(name: "110%-er") + s = Person.search(name_cont: "10%") + s.result.exists?.should be_true + end + + it "should function correctly when using fields with backslashes in them" do + Person.create!(name: "\\WINNER\\") + s = Person.search(name_cont: "\\WINNER\\") + s.result.exists?.should be_true + end end describe '#ransackable_attributes' do diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index 36f9e6e..5ec4ce4 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -13,13 +13,7 @@ module Ransack expect { subject.result }.to_not raise_error end - it ( - if ActiveRecord::VERSION::MAJOR == 3 - "escapes '%', '.' and '\\\\' in value" - else - "escapes % and \\ in value" - end - ) do + it "escapes '%', '.' and '\\\\' in value" do subject.send(:"#{method}=", '%._\\') subject.result.to_sql.should match(regexp) end @@ -44,34 +38,34 @@ module Ransack describe 'cont' do - it_has_behavior 'wildcard escaping', :name_cont, ( - if ActiveRecord::VERSION::MAJOR == 3 - /"people"."name" LIKE '%\\%\\._\\\\%'/ + it_has_behavior 'wildcard escaping', :name_cont, + (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + /"people"."name" ILIKE '%\\%\\._\\\\%'/ else - /"people"."name" LIKE '%\\%._\\\\%'/ + /"people"."name" LIKE '%%._\\%'/ end) do subject { @s } end it 'generates a LIKE query with value surrounded by %' do @s.name_cont = 'ric' - @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/ + @s.result.to_sql.should match /"people"."name" I?LIKE '%ric%'/ end end describe 'not_cont' do - it_has_behavior 'wildcard escaping', :name_not_cont, ( - if ActiveRecord::VERSION::MAJOR == 3 - /"people"."name" NOT LIKE '%\\%\\._\\\\%'/ + it_has_behavior 'wildcard escaping', :name_not_cont, + (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + /"people"."name" NOT ILIKE '%\\%\\._\\\\%'/ else - /"people"."name" NOT LIKE '%\\%._\\\\%'/ + /"people"."name" NOT LIKE '%%._\\%'/ end) do subject { @s } end it 'generates a NOT LIKE query with value surrounded by %' do @s.name_not_cont = 'ric' - @s.result.to_sql.should match /"people"."name" NOT LIKE '%ric%'/ + @s.result.to_sql.should match /"people"."name" NOT I?LIKE '%ric%'/ end end From 236046c3336d76b981e31f20eb50f14b8f9d8b04 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:21:53 +1100 Subject: [PATCH 049/112] Remove 1.8.7 + Rails 4 support from this branch Ruby 1.8.7 is no longer supported, so stop using it. (Please) Rails 4 support is over in the rails-4 branch. All Rails 4 specific code belongs there. --- .travis.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4968b2..7da17b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,8 @@ rvm: - - 1.8.7 - - 1.9.2 - 1.9.3 - 2.0.0 env: - - RAILS=4-0-stable - RAILS=3-2-stable - RAILS=3-1-stable - RAILS=3-0-stable - -matrix: - exclude: - - rvm: 1.8.7 - env: RAILS=4-0-stable From 5429a1420ae2eeed4371ee2c4bd2740448403b68 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:23:35 +1100 Subject: [PATCH 050/112] Run tests on sqlite, mysql and postgresql --- .travis.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7da17b9..e990562 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,12 @@ rvm: - 2.0.0 env: - - RAILS=3-2-stable - - RAILS=3-1-stable - - RAILS=3-0-stable + - RAILS=3-2-stable DB=sqlite + - RAILS=3-2-stable DB=mysql + - RAILS=3-2-stable DB=postgres + - RAILS=3-1-stable DB=sqlite + - RAILS=3-1-stable DB=mysql + - RAILS=3-1-stable DB=postgres + - RAILS=3-0-stable DB=sqlite + - RAILS=3-0-stable DB=mysql + - RAILS=3-0-stable DB=postgres From b2149a1e131688a02c21384452d4690ad071b186 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:43:23 +1100 Subject: [PATCH 051/112] Fix tests for MySQL --- lib/ransack/constants.rb | 2 +- .../adapters/active_record/context_spec.rb | 2 +- spec/ransack/predicate_spec.rb | 22 ++++++++++++++----- spec/ransack/search_spec.rb | 22 ++++++++++--------- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/ransack/constants.rb b/lib/ransack/constants.rb index 47d67c2..1991ea3 100644 --- a/lib/ransack/constants.rb +++ b/lib/ransack/constants.rb @@ -27,7 +27,7 @@ module Ransack when "SQLite" unescaped else - # Necessary for PostgreSQL + # Necessary for PostgreSQL and MySQL unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1') end end diff --git a/spec/ransack/adapters/active_record/context_spec.rb b/spec/ransack/adapters/active_record/context_spec.rb index fb171bd..fac20d8 100644 --- a/spec/ransack/adapters/active_record/context_spec.rb +++ b/spec/ransack/adapters/active_record/context_spec.rb @@ -18,7 +18,7 @@ module Ransack result = subject.evaluate(search) result.should be_an ::ActiveRecord::Relation - result.to_sql.should match /"name" = 'Joe Blow'/ + result.to_sql.should match /#{quote_column_name("name")} = 'Joe Blow'/ end it 'SELECTs DISTINCT when :distinct => true' do diff --git a/spec/ransack/predicate_spec.rb b/spec/ransack/predicate_spec.rb index 5ec4ce4..0e9ec6e 100644 --- a/spec/ransack/predicate_spec.rb +++ b/spec/ransack/predicate_spec.rb @@ -22,12 +22,14 @@ module Ransack describe 'eq' do it 'generates an equality condition for boolean true' do @s.awesome_eq = true - @s.result.to_sql.should match /"people"."awesome" = 't'/ + field = "#{quote_table_name("people")}.#{quote_column_name("awesome")}" + @s.result.to_sql.should match /#{field} = #{ActiveRecord::Base.connection.quoted_true}/ end it 'generates an equality condition for boolean false' do @s.awesome_eq = false - @s.result.to_sql.should match /"people"."awesome" = 'f'/ + field = "#{quote_table_name("people")}.#{quote_column_name("awesome")}" + @s.result.to_sql.should match /#{field} = #{ActiveRecord::Base.connection.quoted_false}/ end it 'does not generate a condition for nil' do @@ -41,6 +43,8 @@ module Ransack it_has_behavior 'wildcard escaping', :name_cont, (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" /"people"."name" ILIKE '%\\%\\._\\\\%'/ + elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + /`people`.`name` LIKE '%\\\\%\\\\._\\\\\\\\%'/ else /"people"."name" LIKE '%%._\\%'/ end) do @@ -49,7 +53,8 @@ module Ransack it 'generates a LIKE query with value surrounded by %' do @s.name_cont = 'ric' - @s.result.to_sql.should match /"people"."name" I?LIKE '%ric%'/ + field = "#{quote_table_name("people")}.#{quote_column_name("name")}" + @s.result.to_sql.should match /#{field} I?LIKE '%ric%'/ end end @@ -57,6 +62,8 @@ module Ransack it_has_behavior 'wildcard escaping', :name_not_cont, (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" /"people"."name" NOT ILIKE '%\\%\\._\\\\%'/ + elsif ActiveRecord::Base.connection.adapter_name == "Mysql2" + /`people`.`name` NOT LIKE '%\\\\%\\\\._\\\\\\\\%'/ else /"people"."name" NOT LIKE '%%._\\%'/ end) do @@ -65,21 +72,24 @@ module Ransack it 'generates a NOT LIKE query with value surrounded by %' do @s.name_not_cont = 'ric' - @s.result.to_sql.should match /"people"."name" NOT I?LIKE '%ric%'/ + field = "#{quote_table_name("people")}.#{quote_column_name("name")}" + @s.result.to_sql.should match /#{field} NOT I?LIKE '%ric%'/ end end describe 'null' do it 'generates a value IS NULL query' do @s.name_null = true - @s.result.to_sql.should match /"people"."name" IS NULL/ + field = "#{quote_table_name("people")}.#{quote_column_name("name")}" + @s.result.to_sql.should match /#{field} IS NULL/ end end describe 'not_null' do it 'generates a value IS NOT NULL query' do @s.name_not_null = true - @s.result.to_sql.should match /"people"."name" IS NOT NULL/ + field = "#{quote_table_name("people")}.#{quote_column_name("name")}" + @s.result.to_sql.should match /#{field} IS NOT NULL/ end end end diff --git a/spec/ransack/search_spec.rb b/spec/ransack/search_spec.rb index 4894515..7dacdf9 100644 --- a/spec/ransack/search_spec.rb +++ b/spec/ransack/search_spec.rb @@ -113,25 +113,27 @@ module Ransack end describe '#result' do + let(:people_name_field) { "#{quote_table_name("people")}.#{quote_column_name("name")}" } + let(:children_people_name_field) { "#{quote_table_name("children_people")}.#{quote_column_name("name")}" } it 'evaluates conditions contextually' do search = Search.new(Person, :children_name_eq => 'Ernie') search.result.should be_an ActiveRecord::Relation where = search.result.where_values.first - where.to_sql.should match /"children_people"\."name" = 'Ernie'/ + where.to_sql.should match /#{children_people_name_field} = 'Ernie'/ end it 'evaluates compound conditions contextually' do search = Search.new(Person, :children_name_or_name_eq => 'Ernie') search.result.should be_an ActiveRecord::Relation where = search.result.where_values.first - where.to_sql.should match /"children_people"\."name" = 'Ernie' OR "people"\."name" = 'Ernie'/ + where.to_sql.should match /#{children_people_name_field} = 'Ernie' OR #{people_name_field} = 'Ernie'/ end it 'evaluates polymorphic belongs_to association conditions contextually' do search = Search.new(Note, :notable_of_Person_type_name_eq => 'Ernie') search.result.should be_an ActiveRecord::Relation where = search.result.where_values.first - where.to_sql.should match /"people"."name" = 'Ernie'/ + where.to_sql.should match /#{people_name_field} = 'Ernie'/ end it 'evaluates nested conditions' do @@ -145,9 +147,9 @@ module Ransack ) search.result.should be_an ActiveRecord::Relation where = search.result.where_values.first - where.to_sql.should match /"children_people"."name" = 'Ernie'/ - where.to_sql.should match /"people"."name" = 'Ernie'/ - where.to_sql.should match /"children_people_2"."name" = 'Ernie'/ + where.to_sql.should match /#{children_people_name_field} = 'Ernie'/ + where.to_sql.should match /#{people_name_field} = 'Ernie'/ + where.to_sql.should match /#{quote_table_name("children_people_2")}.#{quote_column_name("name")} = 'Ernie'/ end it 'evaluates arrays of groupings' do @@ -161,10 +163,10 @@ module Ransack where = search.result.where_values.first sql = where.to_sql first, second = sql.split(/ AND /) - first.should match /"people"."name" = 'Ernie'/ - first.should match /"children_people"."name" = 'Ernie'/ - second.should match /"people"."name" = 'Bert'/ - second.should match /"children_people"."name" = 'Bert'/ + first.should match /#{people_name_field} = 'Ernie'/ + first.should match /#{children_people_name_field} = 'Ernie'/ + second.should match /#{people_name_field} = 'Bert'/ + second.should match /#{children_people_name_field} = 'Bert'/ end it 'returns distinct records when passed :distinct => true' do From 8f5ab85af2c49fb277d0c6d0cc62023868059e4b Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:48:23 +1100 Subject: [PATCH 052/112] It helps to create the databases before running the tests on travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index e990562..884c642 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,3 +12,7 @@ env: - RAILS=3-0-stable DB=sqlite - RAILS=3-0-stable DB=mysql - RAILS=3-0-stable DB=postgres + +before_script: + - mysql -e 'create database ransack;' + - psql -c 'create database ransack;' -U postgres \ No newline at end of file From 2106d04804ab59ee4888efac086a2009ba54c68c Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:57:35 +1100 Subject: [PATCH 053/112] Support Rails 4 on the master branch Given that's where we do gem releases from anyway So... what's the purpose of the Rails 4 branch? --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 884c642..0e1bc2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ rvm: - 2.0.0 env: +- RAILS=4-0-stable DB=sqlite + - RAILS=4-0-stable DB=mysql + - RAILS=4-0-stable DB=postgres - RAILS=3-2-stable DB=sqlite - RAILS=3-2-stable DB=mysql - RAILS=3-2-stable DB=postgres From bb07c66e1eb5a6994172fb019a95a31add209cba Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 17:59:02 +1100 Subject: [PATCH 054/112] Bump to 1.1.0 --- lib/ransack/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ransack/version.rb b/lib/ransack/version.rb index c472356..8e0f1a8 100644 --- a/lib/ransack/version.rb +++ b/lib/ransack/version.rb @@ -1,3 +1,3 @@ module Ransack - VERSION = "1.0.0" + VERSION = "1.1.0" end From 53fd7c68e5b3cd64b9a0f71f91b1d047fc5295de Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 6 Nov 2013 18:04:31 +1100 Subject: [PATCH 055/112] Fix indentation in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0e1bc2d..e529bfe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ rvm: - 2.0.0 env: -- RAILS=4-0-stable DB=sqlite + - RAILS=4-0-stable DB=sqlite - RAILS=4-0-stable DB=mysql - RAILS=4-0-stable DB=postgres - RAILS=3-2-stable DB=sqlite From c51a7cdda5920e136b48e184450e549634dda607 Mon Sep 17 00:00:00 2001 From: Sean Linsley Date: Tue, 12 Nov 2013 18:51:12 -0600 Subject: [PATCH 056/112] fix typo in base_spec Fixes #301 --- spec/ransack/adapters/active_record/base_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 62c013f..8c5c2b0 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -23,7 +23,7 @@ module Ransack # For infix tests def self.sane_adapter? case ::ActiveRecord::Base.connection.adapter_name - when "SQLite3" || "PostgreSQL" + when "SQLite3", "PostgreSQL" true else false @@ -104,4 +104,4 @@ module Ransack end end end -end \ No newline at end of file +end From 9e87676d9f7682b9db44ce3710284452e64e113c Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Thu, 14 Nov 2013 17:10:24 -0600 Subject: [PATCH 057/112] Add license to gemspec, is MIT Fixes #303 Fixes #304 --- ransack.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/ransack.gemspec b/ransack.gemspec index fcfd9fe..1c1cc67 100644 --- a/ransack.gemspec +++ b/ransack.gemspec @@ -11,6 +11,7 @@ Gem::Specification.new do |s| s.homepage = "https://github.com/ernie/ransack" s.summary = %q{Object-based searching for ActiveRecord (currently).} s.description = %q{Ransack is the successor to the MetaSearch gem. It improves and expands upon MetaSearch's functionality, but does not have a 100%-compatible API.} + s.license = 'MIT' s.rubyforge_project = "ransack" From 76f909a2ad77874b8e795b9fc562b49d92c90fe9 Mon Sep 17 00:00:00 2001 From: Jerod Santo Date: Fri, 15 Nov 2013 14:54:48 -0600 Subject: [PATCH 058/112] use `respond_to?` instead of `method_defined?` when aliasing `search` Fixes #305 --- lib/ransack/adapters/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ransack/adapters/active_record/base.rb b/lib/ransack/adapters/active_record/base.rb index 51d814b..a42d911 100644 --- a/lib/ransack/adapters/active_record/base.rb +++ b/lib/ransack/adapters/active_record/base.rb @@ -4,7 +4,7 @@ module Ransack module Base def self.extended(base) - alias :search :ransack unless base.method_defined? :search + alias :search :ransack unless base.respond_to? :search base.class_eval do class_attribute :_ransackers self._ransackers ||= {} From a769aaedd5658e9bc1a4c543e954408efd03e978 Mon Sep 17 00:00:00 2001 From: Jeff Barriault Date: Thu, 21 Nov 2013 13:32:03 -0600 Subject: [PATCH 059/112] Remove direction select from sort_select form builder and put it into its own sort_direction helper method. --- lib/ransack/helpers/form_builder.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index 5b7b3eb..db86381 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -43,16 +43,27 @@ module Ransack @template.grouped_collection_select( @object_name, :name, sortable_attribute_collection_for_bases(bases), :last, :first, :first, :last, objectify_options(options), @default_options.merge(html_options) - ) + @template.collection_select( - @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, - objectify_options(options), @default_options.merge(html_options) ) else collection = sortable_attribute_collection_for_base(bases.first) @template.collection_select( @object_name, :name, collection, :first, :last, objectify_options(options), @default_options.merge(html_options) - ) + @template.collection_select( + ) + end + end + + def sort_direction(options = {}, html_options = {}) + raise ArgumentError, "sort_direction must be called inside a search FormBuilder!" unless object.respond_to?(:context) + bases = [''] + association_array(options[:associations]) + if bases.size > 1 + @template.collection_select( + @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, + objectify_options(options), @default_options.merge(html_options) + ) + else + collection = sortable_attribute_collection_for_base(bases.first) + @template.collection_select( @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, objectify_options(options), @default_options.merge(html_options) ) From 465d38b12bc1c232b90fcee1f85f661b14706a40 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 22 Nov 2013 16:29:39 +1100 Subject: [PATCH 060/112] Update Travis icon to use activerecord-hackery account --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31ed939..3ee9e33 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ransack -[![Build Status](https://travis-ci.org/ernie/ransack.png?branch=master)](https://travis-ci.org/ernie/ransack) +[![Build Status](https://travis-ci.org/activerecord-hackery/ransack)](https://travis-ci.org/ernie/ransack) Ransack is a rewrite of [MetaSearch](https://github.com/ernie/meta_search). While it supports many of the same features as MetaSearch, its underlying implementation differs From 3da2427e37d38384e6dd0f2d5939d43a5fda88b9 Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Fri, 22 Nov 2013 09:44:27 -0300 Subject: [PATCH 061/112] Add auth_object support to attribute & sort nodes when call ransackable_attributes or ransortable_attributes. --- lib/ransack/nodes/attribute.rb | 2 +- lib/ransack/nodes/sort.rb | 2 +- .../adapters/active_record/base_spec.rb | 72 +++++++++++++++---- spec/support/schema.rb | 16 ++++- 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/lib/ransack/nodes/attribute.rb b/lib/ransack/nodes/attribute.rb index 20d9ca6..7b48a92 100644 --- a/lib/ransack/nodes/attribute.rb +++ b/lib/ransack/nodes/attribute.rb @@ -20,7 +20,7 @@ module Ransack def valid? bound? && attr && - context.klassify(parent).ransackable_attributes.include?(attr_name) + context.klassify(parent).ransackable_attributes(context.auth_object).include?(attr_name) end def type diff --git a/lib/ransack/nodes/sort.rb b/lib/ransack/nodes/sort.rb index 1e55432..d9c4e64 100644 --- a/lib/ransack/nodes/sort.rb +++ b/lib/ransack/nodes/sort.rb @@ -25,7 +25,7 @@ module Ransack def valid? bound? && attr && - context.klassify(parent).ransortable_attributes.include?(attr_name) + context.klassify(parent).ransortable_attributes(context.auth_object).include?(attr_name) end def name=(name) diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 90c65f5..012f0ff 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -68,26 +68,74 @@ module Ransack s = Person.search(:only_sort_eq => 'htimS cirA') s.result.to_sql.should_not match /WHERE "people"."name" \|\| "only_sort" \|\| "people"."name" = 'htimS cirA'/ end + + it 'allows sort by "only_admin" field, if auth_object: :admin' do + s = Person.search({"s"=>{"0"=>{"dir"=>"asc", "name"=>"only_admin"}}}, {auth_object: :admin}) + s.result.to_sql.should match /ORDER BY "people"."name" \|\| "only_admin" \|\| "people"."name" ASC/ + end + + it "doesn't sort by 'only_admin' field, if auth_object: nil" do + s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_admin"}}) + s.result.to_sql.should_not match /ORDER BY "people"."name" \|\| "only_admin" \|\| "people"."name" ASC/ + end + + it 'allows search by "only_admin" field, if auth_object: :admin' do + s = Person.search({:only_admin_eq => 'htimS cirA'}, {auth_object: :admin}) + s.result.to_sql.should match /WHERE "people"."name" \|\| "only_admin" \|\| "people"."name" = 'htimS cirA'/ + end + + it "can't be searched by 'only_admin'" do + s = Person.search(:only_admin_eq => 'htimS cirA') + s.result.to_sql.should_not match /WHERE "people"."name" \|\| "only_admin" \|\| "people"."name" = 'htimS cirA'/ + end end describe '#ransackable_attributes' do - subject { Person.ransackable_attributes } + context 'when auth_object is nil' do + subject { Person.ransackable_attributes } - it { should include 'name' } - it { should include 'reversed_name' } - it { should include 'doubled_name' } - it { should include 'only_search' } - it { should_not include 'only_sort' } + it { should include 'name' } + it { should include 'reversed_name' } + it { should include 'doubled_name' } + it { should include 'only_search' } + it { should_not include 'only_sort' } + it { should_not include 'only_admin' } + end + + context 'with auth_object :admin' do + subject { Person.ransackable_attributes(:admin) } + + it { should include 'name' } + it { should include 'reversed_name' } + it { should include 'doubled_name' } + it { should include 'only_search' } + it { should_not include 'only_sort' } + it { should include 'only_admin' } + end end describe '#ransortable_attributes' do - subject { Person.ransortable_attributes } + context 'when auth_object is nil' do + subject { Person.ransortable_attributes } - it { should include 'name' } - it { should include 'reversed_name' } - it { should include 'doubled_name' } - it { should include 'only_sort' } - it { should_not include 'only_search' } + it { should include 'name' } + it { should include 'reversed_name' } + it { should include 'doubled_name' } + it { should include 'only_sort' } + it { should_not include 'only_search' } + it { should_not include 'only_admin' } + end + + context 'with auth_object :admin' do + subject { Person.ransortable_attributes(:admin) } + + it { should include 'name' } + it { should include 'reversed_name' } + it { should include 'doubled_name' } + it { should include 'only_sort' } + it { should_not include 'only_search' } + it { should include 'only_admin' } + end end describe '#ransackable_associations' do diff --git a/spec/support/schema.rb b/spec/support/schema.rb index e406392..3782c09 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -37,12 +37,24 @@ class Person < ActiveRecord::Base Arel::Nodes::InfixOperation.new('|| "only_sort" ||', parent.table[:name], parent.table[:name]) end + ransacker :only_admin do |parent| + Arel::Nodes::InfixOperation.new('|| "only_admin" ||', parent.table[:name], parent.table[:name]) + end + def self.ransackable_attributes(auth_object = nil) - column_names + _ransackers.keys - ['only_sort'] + if auth_object == :admin + column_names + _ransackers.keys - ['only_sort'] + else + column_names + _ransackers.keys - ['only_sort', 'only_admin'] + end end def self.ransortable_attributes(auth_object = nil) - column_names + _ransackers.keys - ['only_search'] + if auth_object == :admin + column_names + _ransackers.keys - ['only_search'] + else + column_names + _ransackers.keys - ['only_search', 'only_admin'] + end end end From 5c990b9d188d7886c13da17c8050db162754e0ba Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Tue, 26 Nov 2013 10:15:18 -0300 Subject: [PATCH 062/112] Fix mysql tests. Move sort, search & admin fields from ransacker to DB. --- spec/blueprints/people.rb | 5 ++++- .../adapters/active_record/base_spec.rb | 18 +++++++++--------- spec/spec_helper.rb | 15 +++++++++------ spec/support/schema.rb | 15 +++------------ 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/spec/blueprints/people.rb b/spec/blueprints/people.rb index 42b0292..5fc983a 100644 --- a/spec/blueprints/people.rb +++ b/spec/blueprints/people.rb @@ -2,4 +2,7 @@ Person.blueprint do name email { "test@example.com" } salary -end \ No newline at end of file + only_sort + only_search + only_admin +end diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 53bb710..8675f26 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -78,42 +78,42 @@ module Ransack it 'allows sort by "only_sort" field' do s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_sort"}}) - s.result.to_sql.should match /ORDER BY "people"."name" \|\| "only_sort" \|\| "people"."name" ASC/ + s.result.to_sql.should match /ORDER BY #{quote_table_name("people")}.#{quote_column_name("only_sort")} ASC/ end it "doesn't sort by 'only_search' field" do s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_search"}}) - s.result.to_sql.should_not match /ORDER BY "people"."name" \|\| "only_search" \|\| "people"."name" ASC/ + s.result.to_sql.should_not match /ORDER BY #{quote_table_name("people")}.#{quote_column_name("only_search")} ASC/ end it 'allows search by "only_search" field' do s = Person.search(:only_search_eq => 'htimS cirA') - s.result.to_sql.should match /WHERE "people"."name" \|\| "only_search" \|\| "people"."name" = 'htimS cirA'/ + s.result.to_sql.should match /WHERE #{quote_table_name("people")}.#{quote_column_name("only_search")} = 'htimS cirA'/ end it "can't be searched by 'only_sort'" do s = Person.search(:only_sort_eq => 'htimS cirA') - s.result.to_sql.should_not match /WHERE "people"."name" \|\| "only_sort" \|\| "people"."name" = 'htimS cirA'/ + s.result.to_sql.should_not match /WHERE #{quote_table_name("people")}.#{quote_column_name("only_sort")} = 'htimS cirA'/ end it 'allows sort by "only_admin" field, if auth_object: :admin' do s = Person.search({"s"=>{"0"=>{"dir"=>"asc", "name"=>"only_admin"}}}, {auth_object: :admin}) - s.result.to_sql.should match /ORDER BY "people"."name" \|\| "only_admin" \|\| "people"."name" ASC/ + s.result.to_sql.should match /ORDER BY #{quote_table_name("people")}.#{quote_column_name("only_admin")} ASC/ end it "doesn't sort by 'only_admin' field, if auth_object: nil" do s = Person.search("s"=>{"0"=>{"dir"=>"asc", "name"=>"only_admin"}}) - s.result.to_sql.should_not match /ORDER BY "people"."name" \|\| "only_admin" \|\| "people"."name" ASC/ + s.result.to_sql.should_not match /ORDER BY #{quote_table_name("people")}.#{quote_column_name("only_admin")} ASC/ end it 'allows search by "only_admin" field, if auth_object: :admin' do s = Person.search({:only_admin_eq => 'htimS cirA'}, {auth_object: :admin}) - s.result.to_sql.should match /WHERE "people"."name" \|\| "only_admin" \|\| "people"."name" = 'htimS cirA'/ + s.result.to_sql.should match /WHERE #{quote_table_name("people")}.#{quote_column_name("only_admin")} = 'htimS cirA'/ end - it "can't be searched by 'only_admin'" do + it "can't be searched by 'only_admin', if auth_object: nil" do s = Person.search(:only_admin_eq => 'htimS cirA') - s.result.to_sql.should_not match /WHERE "people"."name" \|\| "only_admin" \|\| "people"."name" = 'htimS cirA'/ + s.result.to_sql.should_not match /WHERE #{quote_table_name("people")}.#{quote_column_name("only_admin")} = 'htimS cirA'/ end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a25d698..77d9173 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,12 +11,15 @@ Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)].each do end Sham.define do - name { Faker::Name.name } - title { Faker::Lorem.sentence } - body { Faker::Lorem.paragraph } - salary {|index| 30000 + (index * 1000)} - tag_name { Faker::Lorem.words(3).join(' ') } - note { Faker::Lorem.words(7).join(' ') } + name { Faker::Name.name } + title { Faker::Lorem.sentence } + body { Faker::Lorem.paragraph } + salary {|index| 30000 + (index * 1000)} + tag_name { Faker::Lorem.words(3).join(' ') } + note { Faker::Lorem.words(7).join(' ') } + only_admin { Faker::Lorem.words(3).join(' ') } + only_search { Faker::Lorem.words(3).join(' ') } + only_sort { Faker::Lorem.words(3).join(' ') } end RSpec.configure do |config| diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 5ecc8a5..844cb50 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -46,18 +46,6 @@ class Person < ActiveRecord::Base Arel::Nodes::InfixOperation.new('||', parent.table[:name], parent.table[:name]) end - ransacker :only_search do |parent| - Arel::Nodes::InfixOperation.new('|| "only_search" ||', parent.table[:name], parent.table[:name]) - end - - ransacker :only_sort do |parent| - Arel::Nodes::InfixOperation.new('|| "only_sort" ||', parent.table[:name], parent.table[:name]) - end - - ransacker :only_admin do |parent| - Arel::Nodes::InfixOperation.new('|| "only_admin" ||', parent.table[:name], parent.table[:name]) - end - def self.ransackable_attributes(auth_object = nil) if auth_object == :admin column_names + _ransackers.keys - ['only_sort'] @@ -104,6 +92,9 @@ module Schema t.integer :parent_id t.string :name t.string :email + t.string :only_search + t.string :only_sort + t.string :only_admin t.integer :salary t.boolean :awesome, :default => false t.timestamps From f0ab5db5121e5b63e59d3bb939705ecb86f5b336 Mon Sep 17 00:00:00 2001 From: Jeff Barriault Date: Tue, 26 Nov 2013 08:34:06 -0600 Subject: [PATCH 063/112] refactor so we don't create a breaking change --- lib/ransack/helpers/form_builder.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index db86381..702b8ea 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -34,8 +34,13 @@ module Ransack ) end end - + def sort_select(options = {}, html_options = {}) + sort_attribute_select(options, html_options) + + sort_direction_select(options, html_options) + end + + def sort_attribute_select(options = {}, html_options = {}) raise ArgumentError, "sort_select must be called inside a search FormBuilder!" unless object.respond_to?(:context) options[:include_blank] = true unless options.has_key?(:include_blank) bases = [''] + association_array(options[:associations]) @@ -53,7 +58,7 @@ module Ransack end end - def sort_direction(options = {}, html_options = {}) + def sort_direction_select(options = {}, html_options = {}) raise ArgumentError, "sort_direction must be called inside a search FormBuilder!" unless object.respond_to?(:context) bases = [''] + association_array(options[:associations]) if bases.size > 1 From 98948773e48c7f33fc17aa22ce161ee88fdebf36 Mon Sep 17 00:00:00 2001 From: Sean Linsley Date: Tue, 26 Nov 2013 23:51:20 -0600 Subject: [PATCH 064/112] improve predicate lookup performance from .7 ms to .1 ms Fixes #309 --- lib/ransack/predicate.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/ransack/predicate.rb b/lib/ransack/predicate.rb index a54e59b..23405fe 100644 --- a/lib/ransack/predicate.rb +++ b/lib/ransack/predicate.rb @@ -17,11 +17,14 @@ module Ransack end def detect_and_strip_from_string!(str) - names_by_decreasing_length.detect {|p| str.sub!(/_#{p}$/, '')} + if p = detect_from_string(str) + str.sub! /_#{p}$/, '' + p + end end def detect_from_string(str) - names_by_decreasing_length.detect {|p| str.match(/_#{p}$/)} + names_by_decreasing_length.detect {|p| str.end_with?("_#{p}")} end def name_from_attribute_name(attribute_name) From bc58fbef249d29ad88ac6c3fee44111dd9e0c610 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Mon, 2 Dec 2013 12:14:04 +1100 Subject: [PATCH 065/112] Penderize annoying mysql-only failing test --- spec/ransack/adapters/active_record/base_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 8c5c2b0..74e23c5 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -70,7 +70,9 @@ module Ransack s.result.exists?.should be_true end - it "should function correctly when using fields with backslashes in them" do + # Pending due to it failing on Travis, but not on my local machine + # Doesn't seem to be all that important anyway. + pending "should function correctly when using fields with backslashes in them" do Person.create!(name: "\\WINNER\\") s = Person.search(name_cont: "\\WINNER\\") s.result.exists?.should be_true From 7869d937a4ce09341b449bd297b394dab7ec810b Mon Sep 17 00:00:00 2001 From: Andrew Hooker Date: Sun, 1 Dec 2013 22:01:10 -0600 Subject: [PATCH 066/112] Fixing TravisCI link properly --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ee9e33..3a08ecb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ransack -[![Build Status](https://travis-ci.org/activerecord-hackery/ransack)](https://travis-ci.org/ernie/ransack) +[![Build Status](https://travis-ci.org/activerecord-hackery/ransack.png)](https://travis-ci.org/activerecord-hackery/ransack) Ransack is a rewrite of [MetaSearch](https://github.com/ernie/meta_search). While it supports many of the same features as MetaSearch, its underlying implementation differs From 2ac274588976c571da9551b6cb7134a8014a6e14 Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Tue, 3 Dec 2013 10:16:41 -0300 Subject: [PATCH 067/112] change collating sequence to fix mysql search issue. --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e529bfe..1dde36f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,5 +17,6 @@ env: - RAILS=3-0-stable DB=postgres before_script: - - mysql -e 'create database ransack;' - - psql -c 'create database ransack;' -U postgres \ No newline at end of file + - mysql -e 'create database ransack collate utf8_general_ci;' + - mysql -e 'use ransack;show variables like "%character%";show variables like "%collation%";' + - psql -c 'create database ransack;' -U postgres From ec3e9521654b9f697a5ab0a5a90d06b428c64fdb Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Tue, 3 Dec 2013 10:28:58 -0300 Subject: [PATCH 068/112] run backslash test --- spec/ransack/adapters/active_record/base_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/ransack/adapters/active_record/base_spec.rb b/spec/ransack/adapters/active_record/base_spec.rb index 7e9bbfc..8675f26 100644 --- a/spec/ransack/adapters/active_record/base_spec.rb +++ b/spec/ransack/adapters/active_record/base_spec.rb @@ -70,9 +70,7 @@ module Ransack s.result.exists?.should be_true end - # Pending due to it failing on Travis, but not on my local machine - # Doesn't seem to be all that important anyway. - pending "should function correctly when using fields with backslashes in them" do + it "should function correctly when using fields with backslashes in them" do Person.create!(name: "\\WINNER\\") s = Person.search(name_cont: "\\WINNER\\") s.result.exists?.should be_true From 86edf0b068078c44c3e4c797ba74ec124e7667ad Mon Sep 17 00:00:00 2001 From: Alejandro Babio Date: Wed, 4 Dec 2013 12:09:33 -0300 Subject: [PATCH 069/112] Fix mysql issue on Rails 3.0 --- Gemfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index 1074abd..12ea702 100644 --- a/Gemfile +++ b/Gemfile @@ -27,4 +27,7 @@ else gem 'activerecord' gem 'actionpack' end + if rails == '3-0-stable' + gem 'mysql2', '< 0.3' + end end From f491cb2ad07fbbf89ac4175785b7a7bfe5c46665 Mon Sep 17 00:00:00 2001 From: Denis Tataurov Date: Fri, 29 Nov 2013 18:44:51 +0400 Subject: [PATCH 070/112] Fix issue where trying to add a polymorphic field in search form resulted in NameError Fixes #159 Fixes #313 --- lib/ransack/nodes/grouping.rb | 5 +++++ spec/blueprints/notes.rb | 2 ++ spec/ransack/helpers/form_builder_spec.rb | 17 +++++++++++++++++ spec/spec_helper.rb | 13 +++++++------ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/ransack/nodes/grouping.rb b/lib/ransack/nodes/grouping.rb index 3e38a8c..6835618 100644 --- a/lib/ransack/nodes/grouping.rb +++ b/lib/ransack/nodes/grouping.rb @@ -180,10 +180,15 @@ module Ransack def strip_predicate_and_index(str) string = str.split(/\(/).first + string = strip_before_type_cast(string) Predicate.detect_and_strip_from_string!(string) string end + def strip_before_type_cast(str) + str.split("_before_type_cast").first + end + end end end \ No newline at end of file diff --git a/spec/blueprints/notes.rb b/spec/blueprints/notes.rb index f143114..f6702ca 100644 --- a/spec/blueprints/notes.rb +++ b/spec/blueprints/notes.rb @@ -1,3 +1,5 @@ Note.blueprint do note + notable_type { "Article" } + notable_id end \ No newline at end of file diff --git a/spec/ransack/helpers/form_builder_spec.rb b/spec/ransack/helpers/form_builder_spec.rb index b00cd8e..7b8fc41 100644 --- a/spec/ransack/helpers/form_builder_spec.rb +++ b/spec/ransack/helpers/form_builder_spec.rb @@ -7,6 +7,7 @@ module Ransack router = ActionDispatch::Routing::RouteSet.new router.draw do resources :people + resources :notes get ':controller(/:action(/:id(.:format)))' end @@ -132,6 +133,22 @@ module Ransack end end end + + context 'fields used in polymorphic relations as search attributes in form' do + before do + @controller.view_context.search_form_for Note.search do |f| + @f = f + end + end + it 'accepts poly_id field' do + html = @f.text_field(:notable_id_eq) + html.should match /id=\"q_notable_id_eq\"/ + end + it 'accepts poly_type field' do + html = @f.text_field(:notable_type_eq) + html.should match /id=\"q_notable_type_eq\"/ + end + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a25d698..1e8e378 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,12 +11,13 @@ Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)].each do end Sham.define do - name { Faker::Name.name } - title { Faker::Lorem.sentence } - body { Faker::Lorem.paragraph } - salary {|index| 30000 + (index * 1000)} - tag_name { Faker::Lorem.words(3).join(' ') } - note { Faker::Lorem.words(7).join(' ') } + name { Faker::Name.name } + title { Faker::Lorem.sentence } + body { Faker::Lorem.paragraph } + salary {|index| 30000 + (index * 1000)} + tag_name { Faker::Lorem.words(3).join(' ') } + note { Faker::Lorem.words(7).join(' ') } + notable_id { |id| id } end RSpec.configure do |config| From 7582f12c029cf5e427cd4ec324acc6a8f4a0fcf4 Mon Sep 17 00:00:00 2001 From: jonatack Date: Sat, 7 Dec 2013 00:02:40 +0100 Subject: [PATCH 071/112] Update README to reference "activerecord-hackery" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and describe the “rails-4” branch. --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a08ecb..240c735 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,16 @@ In your Gemfile: gem "ransack" # Last officially released gem (Rails 3 and 4) ``` -Or if you want to use the bleeding edge: +Or if you want to use the bleeding edge (Rails 3 and 4): ```ruby -gem "ransack", github: "ernie/ransack" # Track git repo +gem "ransack", github: "activerecord-hackery/ransack" # Track git repo +``` + +A lighter, faster, latest-commits version of Ransack dedicated to Rails 4 is available on the "rails-4" branch: + +```ruby +gem "ransack", github: "activerecord-hackery/ransack", branch: "rails-4" ``` ## Usage From 914a0d7a1357d1893cedf5ad4a3dbbf36ed2fadb Mon Sep 17 00:00:00 2001 From: jonatack Date: Sat, 7 Dec 2013 23:17:17 +0100 Subject: [PATCH 072/112] Refactor form_builder --- lib/ransack/helpers/form_builder.rb | 156 +++++++++++----------- spec/ransack/helpers/form_builder_spec.rb | 22 +-- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index 702b8ea..cab55ba 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -3,76 +3,64 @@ require 'action_view' module Ransack module Helpers class FormBuilder < ::ActionView::Helpers::FormBuilder + def label(method, *args, &block) options = args.extract_options! text = args.first i18n = options[:i18n] || {} - text ||= object.translate(method, i18n.reverse_merge(:include_associations => true)) if object.respond_to? :translate + text ||= object.translate( + method, i18n.reverse_merge(:include_associations => true) + ) if object.respond_to? :translate super(method, text, options, &block) end - def submit(value=nil, options={}) + def submit(value = nil, options = {}) value, options = nil, value if value.is_a?(Hash) value ||= Translate.word(:search).titleize super(value, options) end - def attribute_select(options = {}, html_options = {}) - raise ArgumentError, "attribute_select must be called inside a search FormBuilder!" unless object.respond_to?(:context) + def attribute_select(action = 'search', options = {}, html_options = {}) + raise ArgumentError, formbuilder_error_message(action) unless + object.respond_to?(:context) options[:include_blank] = true unless options.has_key?(:include_blank) bases = [''] + association_array(options[:associations]) if bases.size > 1 @template.grouped_collection_select( - @object_name, :name, searchable_attribute_collection_for_bases(bases), :last, :first, :first, :last, + @object_name, :name, + attribute_collection_for_bases(bases, action), + :last, :first, :first, :last, objectify_options(options), @default_options.merge(html_options) ) else - collection = searchable_attribute_collection_for_base(bases.first) + collection = collection_for_base(action, bases.first) @template.collection_select( - @object_name, :name, collection, :first, :last, + @object_name, :name, + collection, + :first, :last, objectify_options(options), @default_options.merge(html_options) ) end end - + def sort_select(options = {}, html_options = {}) - sort_attribute_select(options, html_options) + + attribute_select('sort', options, html_options) + sort_direction_select(options, html_options) end - def sort_attribute_select(options = {}, html_options = {}) - raise ArgumentError, "sort_select must be called inside a search FormBuilder!" unless object.respond_to?(:context) - options[:include_blank] = true unless options.has_key?(:include_blank) - bases = [''] + association_array(options[:associations]) - if bases.size > 1 - @template.grouped_collection_select( - @object_name, :name, sortable_attribute_collection_for_bases(bases), :last, :first, :first, :last, - objectify_options(options), @default_options.merge(html_options) - ) - else - collection = sortable_attribute_collection_for_base(bases.first) - @template.collection_select( - @object_name, :name, collection, :first, :last, - objectify_options(options), @default_options.merge(html_options) - ) - end - end - def sort_direction_select(options = {}, html_options = {}) - raise ArgumentError, "sort_direction must be called inside a search FormBuilder!" unless object.respond_to?(:context) - bases = [''] + association_array(options[:associations]) - if bases.size > 1 - @template.collection_select( - @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, - objectify_options(options), @default_options.merge(html_options) + raise ArgumentError, + "sort_direction must be called inside a search FormBuilder!" unless + object.respond_to?(:context) + @template.collection_select( + @object_name, :dir, + [ + ['asc', object.translate('asc')], + ['desc', object.translate('desc')] + ], + :first, :last, + objectify_options(options), @default_options.merge(html_options) ) - else - collection = sortable_attribute_collection_for_base(bases.first) - @template.collection_select( - @object_name, :dir, [['asc', object.translate('asc')], ['desc', object.translate('desc')]], :first, :last, - objectify_options(options), @default_options.merge(html_options) - ) - end end def sort_fields(*args, &block) @@ -114,32 +102,38 @@ module Ransack name = "#{options[:object_name] || object_name}[#{name}]" output = ActiveSupport::SafeBuffer.new objects.each do |child| - output << @template.fields_for("#{name}[#{options[:child_index] || nested_child_index(name)}]", child, options, &block) + output << @template.fields_for("#{name}[#{ + options[:child_index] || nested_child_index(name) + }]", child, options, &block) end output end def predicate_select(options = {}, html_options = {}) options[:compounds] = true if options[:compounds].nil? - keys = options[:compounds] ? Predicate.names : Predicate.names.reject {|k| k.match(/_(any|all)$/)} + keys = options[:compounds] ? Predicate.names : + Predicate.names.reject { |k| k.match(/_(any|all)$/) } if only = options[:only] if only.respond_to? :call - keys = keys.select {|k| only.call(k)} + keys = keys.select { |k| only.call(k) } else only = Array.wrap(only).map(&:to_s) - keys = keys.select {|k| only.include? k.sub(/_(any|all)$/, '')} + keys = keys.select { |k| only.include? k.sub(/_(any|all)$/, '') } end end - @template.collection_select( - @object_name, :p, keys.map {|k| [k, Translate.predicate(k)]}, :first, :last, + @object_name, :p, + keys.map { |k| [k, Translate.predicate(k)] }, + :first, :last, objectify_options(options), @default_options.merge(html_options) ) end def combinator_select(options = {}, html_options = {}) @template.collection_select( - @object_name, :m, combinator_choices, :first, :last, + @object_name, :m, + combinator_choices, + :first, :last, objectify_options(options), @default_options.merge(html_options) ) end @@ -169,56 +163,56 @@ module Ransack end else [obj] - end). - compact.flatten.map { |v| [prefix, v].compact.join('_') } + end) + .compact + .flatten + .map { |v| [prefix, v].compact.join('_') } end def attr_from_base_and_column(base, column) - [base, column].reject {|v| v.blank?}.join('_') + [base, column] + .reject { |v| v.blank? } + .join('_') end - def attribute_collection_for_base(attributes, base=nil) + def collection_for_base(action, base) + attribute_collection_for_base( + object.context.send("#{action}able_attributes", base), base + ) + end + + def attribute_collection_for_base(attributes, base = nil) attributes.map do |c| [ attr_from_base_and_column(base, c), - Translate.attribute(attr_from_base_and_column(base, c), :context => object.context) + Translate.attribute( + attr_from_base_and_column(base, c), :context => object.context + ) ] end end - def sortable_attribute_collection_for_base(base=nil) - attribute_collection_for_base(object.context.sortable_attributes(base), base) - end - - def searchable_attribute_collection_for_base(base=nil) - attribute_collection_for_base(object.context.searchable_attributes(base), base) - end - - def sortable_attribute_collection_for_bases(bases) - bases.map do |base| - begin - [ - Translate.association(base, :context => object.context), - sortable_attribute_collection_for_base(base) - ] - rescue UntraversableAssociationError => e - nil + def attribute_collection_for_bases(bases, action) + ( + bases.map do |base| + begin + [ + Translate.association(base, :context => object.context), + collection_for_base(action, base) + ] + rescue UntraversableAssociationError => e + nil + end end - end.compact + ) + .compact end - def searchable_attribute_collection_for_bases(bases) - bases.map do |base| - begin - [ - Translate.association(base, :context => object.context), - searchable_attribute_collection_for_base(base) - ] - rescue UntraversableAssociationError => e - nil - end - end.compact + def formbuilder_error_message(action) + "#{action == 'search' ? 'attribute' : action + }_select must be called inside a search FormBuilder!" end + end end end \ No newline at end of file diff --git a/spec/ransack/helpers/form_builder_spec.rb b/spec/ransack/helpers/form_builder_spec.rb index 7b8fc41..c198a24 100644 --- a/spec/ransack/helpers/form_builder_spec.rb +++ b/spec/ransack/helpers/form_builder_spec.rb @@ -33,7 +33,11 @@ module Ransack it 'selects previously-entered time values with datetime_select' do @s.created_at_eq = [2011, 1, 2, 3, 4, 5] - html = @f.datetime_select :created_at_eq, :use_month_numbers => true, :include_seconds => true + html = @f.datetime_select( + :created_at_eq, + :use_month_numbers => true, + :include_seconds => true + ) %w(2011 1 2 03 04 05).each do |val| html.should match // end @@ -114,21 +120,21 @@ module Ransack it 'filters predicates with single-value :only' do html = @f.predicate_select :only => 'eq' - Predicate.names.reject {|k| k =~ /^eq/}.each do |key| + Predicate.names.reject { |k| k =~ /^eq/ }.each do |key| html.should_not match /