ransackable_scope with boolean value is skipped

Created on 14 Sep 2017  路  4Comments  路  Source: activerecord-hackery/ransack

here's bug report that reproduce the bug

begin
  require 'bundler/inline'
  require 'bundler'
rescue LoadError => e
  STDERR.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
  raise e
end

gemfile(true, ui: ENV['SILENT'] ? Bundler::UI::Silent.new : Bundler::UI::Shell.new) do
  source 'https://rubygems.org'

  gem 'activerecord', require: false

  if ENV['RANSACK_PG']
    gem 'pg'
  else
    gem 'sqlite3', platform: :mri
    gem 'activerecord-jdbcsqlite3-adapter',
        git: 'https://github.com/jruby/activerecord-jdbc-adapter',
        branch: 'rails-5',
        platform: :jruby
  end

  if ENV['RANSACK_PATH']
    gem 'ransack', path: ENV['RANSACK_PATH'], require: false
  elsif ENV['RANSACK_VERSION']
    gem 'ransack', ENV['RANSACK_VERSION'], require: false
  elsif ENV['RANSACK_LATEST_GEM']
    gem 'ransack', require: false
  else
    gem 'ransack', git: 'https://github.com/activerecord-hackery/ransack', require: false
  end

end

# prepare active_record database
require 'active_record'
require 'ransack'

class NullLogger < Logger
  def initialize(*_args)
  end

  def add(*_args, &_block)
  end
end

if ENV['RANSACK_PG']
  db_name = ENV['RANSACK_PG']
  system("psql -c 'DROP DATABASE IF EXISTS #{db_name};'")
  system("psql -c 'CREATE DATABASE #{db_name};'")
  ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: db_name)
else
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
end

ActiveRecord::Base.logger = ENV['SILENT'] ? NullLogger.new : Logger.new(STDOUT)
ActiveRecord::Migration.verbose = !ENV['SILENT']

ActiveRecord::Schema.define do
  # Add your schema here
  create_table :reviews, force: true do |t|
    t.string :content
    t.integer :rank
    t.boolean :is_private, default: false, null: false
  end
end

# create models
class Review < ActiveRecord::Base
  scope :review_private_eq, ->(flag = true) do
    logger.debug { "review_private_eq called with #{flag.inspect}" }
    where(is_private: flag)
  end

  scope :review_private_true, ->(flag = true) do
    logger.debug { "review_private_true called with #{flag.inspect}" }
    where(is_private: flag)
  end

  def self.ransackable_scopes(_auth = nil)
    [:review_private_eq, :review_private_true]
  end
end

# prepare tests
require 'minitest/autorun'
require 'rack/test'

# Replace this with the code necessary to make your test fail.
class BugTest < Minitest::Test

  def test_ransackable_scope_eq_with_true
    received_sql = ransack_sql(Review, review_private_eq: true)
    expected_sql = model_sql(Review, is_private: true)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_eq_with_false
    received_sql = ransack_sql(Review, review_private_eq: false)
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_eq_with_false_string
    received_sql = ransack_sql(Review, review_private_eq: 'false')
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_eq_with_0_string
    received_sql = ransack_sql(Review, review_private_eq: '0')
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_true_with_true
    received_sql = ransack_sql(Review, review_private_true: true)
    expected_sql = model_sql(Review, is_private: true)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_true_with_false
    received_sql = ransack_sql(Review, review_private_true: false)
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_true_with_false_string
    received_sql = ransack_sql(Review, review_private_true: 'false')
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  def test_ransackable_scope_true_with_0_string
    received_sql = ransack_sql(Review, review_private_true: '0')
    expected_sql = model_sql(Review, is_private: false)
    assert_equal expected_sql, received_sql
  end

  private

  def model_sql(klass, params)
    klass.where(params).to_sql
  end

  def ransack_sql(klass, params)
    klass.ransack(params).result.to_sql
  end

end

Most helpful comment

@luhova I have same problem with ransack to convert string to boolean, but if I disable sanitize_custom_scope_booleans , some of my search cases will die .How can I disable convert string to boolean with some scopes. Please help me.

All 4 comments

Look at the README file:

In Rails 3 and 4, if the true value is being passed via url params or some other mechanism that will convert it to a string, the true value may not be passed to the ransackable scope unless you wrap it in an array (i.e. activated: ['true']). Ransack will take care of changing 'true' into a boolean. This is currently resolved in Rails 5 :smiley:
However, perhaps you have user_id: [1] and you do not want Ransack to convert 1 into a boolean. (Values sanitized to booleans can be found in the constants.rb). To turn this off, and handle type conversions yourself, set sanitize_custom_scope_booleans to false in an initializer file like config/initializers/ransack.rb:

Ransack.configure do |c|
  c.sanitize_custom_scope_booleans = false
end

@senid231 Awesome bug report! I wish all issues came with code to replicate the issue which could be added to the trunk as tests.

However, considering this is resolved in Rails 5, and there is a workaround otherwise, can we close this?

@seanfcarroll I think it can be closed now
Thanks for clarification

@luhova I have same problem with ransack to convert string to boolean, but if I disable sanitize_custom_scope_booleans , some of my search cases will die .How can I disable convert string to boolean with some scopes. Please help me.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

itsalongstory picture itsalongstory  路  3Comments

tagrudev picture tagrudev  路  3Comments

timoschilling picture timoschilling  路  5Comments

AnnaErshova picture AnnaErshova  路  3Comments

llopez picture llopez  路  4Comments