Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with a ransacker using Arel.sql and the present predicate #617

Closed
yan-hoose opened this issue Nov 15, 2015 · 2 comments

Comments

Projects
None yet
3 participants
@yan-hoose
Copy link

commented Nov 15, 2015

I ran into an issue with custom ransackers. Here is a test case to demonstrate the issue:

gem 'activerecord', '4.2.4'
gem 'ransack', '1.7.0'
gem 'sqlite3'
require 'active_record'
require 'ransack'
require 'minitest/autorun'
require 'logger'

# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :projects, force: true do |t|
    t.string :name
    t.string :number
  end
end

class Project < ActiveRecord::Base
  ransacker :name do
    Arel.sql('projects.name')
  end

  ransacker :number do |parent|
    parent.table[:number]
  end
end

class BugTest < Minitest::Test
  def test_ransackers
    sql = Project.ransack({number_present: 1}).result.to_sql
    assert_equal "SELECT \"projects\".* FROM \"projects\" WHERE (\"projects\".\"number\" IS NOT NULL AND \"projects\".\"number\" != '')", sql

    sql = Project.ransack({name_present: 1}).result.to_sql
    assert_equal "SELECT \"projects\".* FROM \"projects\" WHERE (projects.name IS NOT NULL AND projects.name != '')", sql
  end
end

As you can see I use two ransackers which are defined a bit differently. One uses Arel.sql and the other does not.

When using a present predicate on the ransacker called "number", the query is generated as expected (first assertion).

However, using a present predicate on the ransacker called "name" that uses Arel.sql, the query that is generated is not correct (second - failing - assertion). It creates a

WHERE (projects.name != NULL AND projects.name != '')

condition which does NOT return expected rows (at least in PostgreSQL 9.4). The query that will return expected rows should be:

WHERE (projects.name IS NOT NULL AND projects.name != '')

I'm using:

  • Rails 4.2.4
  • Ruby 2.2.3
  • Ransack 1.7.0
  • Using PostgreSQL 9.4 but the test fails also with SQLite
  • Ubuntu Linux 15.10
@jonatack

This comment has been minimized.

Copy link
Member

commented Nov 15, 2015

@yan-hoose Thanks for supplying your environment info and the test case 👍

I adapted your test case to the stand-alone script in this gist.

With Rails 5 master, Ransack master and Polyamorous master, your issue is fixed:

=============================================================================
Running test case with Ruby 2.2.3, Active Record 5.0.0, Arel 7.0.0 and SQLite
=============================================================================

SELECT "projects".* FROM "projects" WHERE ("projects"."number" IS NOT NULL AND "projects"."number" != '')
SELECT "projects".* FROM "projects" WHERE (projects.name IS NOT NULL AND projects.name != '')
.

1 runs, 2 assertions, 0 failures, 0 errors, 0 skips

With the last release of Rails 4.2, your issue is reproduced:

=============================================================================
Running test case with Ruby 2.2.3, Active Record 4.2.5, Arel 6.0.3 and SQLite
=============================================================================

  1) Failure:
--- expected
+++ actual
-"SELECT \"projects\".* FROM \"projects\" WHERE (projects.name IS NOT NULL AND projects.name != '')"
+"SELECT \"projects\".* FROM \"projects\" WHERE (projects.name != NULL AND projects.name != '')"

1 runs, 2 assertions, 1 failures, 0 errors, 0 skips

It looks like you have found a bug in Active Record 4.2 / Arel 6.0.

In constants.rb, Ransack's present predicate is invoking the not_eq_all and eq_any predicates in Arel. See arel/predications.rb for more info on Arel predicates.

Closing as this issue appears to be with Active Record or Arel. Upgrading to Rails 5 solves it (I've been using Rails 5 in production for several months on a large app, and so does Basecamp... give it a try 😃)

Thanks again 👍

@jonatack jonatack closed this Nov 15, 2015

@ajporterfield

This comment has been minimized.

Copy link
Contributor

commented May 13, 2016

As a temporary work around, you can try monkey patching Arel.

# in config/initializers/arel.rb
module Arel
  module Nodes
    class Quoted < Arel::Nodes::Unary # :nodoc:
      raise "This is no longer needed" if Arel::VERSION[0] == "7"
      def nil?
        value.nil?
      end
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.