Skip to content

Instantly share code, notes, and snippets.

@tomraulet
Created January 22, 2018 15:17
Show Gist options
  • Save tomraulet/7e84f7a43d1677af5652bd037aa4b2fd to your computer and use it in GitHub Desktop.
Save tomraulet/7e84f7a43d1677af5652bd037aa4b2fd to your computer and use it in GitHub Desktop.
Ransack : join a table twice
# ransack_join_table_twice_issue
# Fork from : github.com/jonatack/test-ransacker-arel-present-predicate.rb
# Run it in your console with: `ruby ransack_joins_table_twice_issue.rb`
# If you change the gem dependencies, run it with:
# `rm gemfile* && ruby ransack_join_table_twice_issue.rb`
unless File.exist?('Gemfile')
File.write('Gemfile', <<-GEMFILE)
source 'https://rubygems.org'
gem 'rails', '5.1.4'
# gem 'pg', '0.20'
gem 'sqlite3'
gem 'ransack', github: 'activerecord-hackery/ransack'
gem 'polyamorous', github: 'activerecord-hackery/polyamorous'
GEMFILE
system 'bundle install'
end
require 'bundler'
Bundler.setup(:default)
require 'active_record'
require 'minitest/autorun'
require 'logger'
require 'ransack'
# This connection will do for database-independent bug reports.
# ActiveRecord::Base.establish_connection({"adapter"=>"postgresql", "encoding"=>"UTF8", "host"=>"localhost", "database"=>"test-database", "username"=>"######", "password"=>"######"})
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)
# Display versions.
message = "Running test case with Ruby #{RUBY_VERSION}, Active Record #{
::ActiveRecord::VERSION::STRING}, Arel #{Arel::VERSION} and #{
::ActiveRecord::Base.connection.adapter_name}"
line = '=' * message.length
puts line, message, line
# Define DB structure
ActiveRecord::Schema.define do
create_table :molecules, force: true do |t|
t.string :name
end
create_table :parameters, force: true do |t|
t.string :name
t.string :value
t.integer :parameterable_id
t.string :parameterable_type
t.integer :parameters_group_id
t.integer :parameter_definition_id
end
create_table :parameters_groups, force: true do |t|
t.string :name
end
create_table :parameter_definitions, force: true do |t|
t.string :name
end
end
# Define classes
class Molecule < ActiveRecord::Base
has_many :identifier_parameters, as: :parameterable, :class_name => "Parameter"
end
class Parameter < ActiveRecord::Base
belongs_to :parameters_group
belongs_to :parameterable, polymorphic: :true
belongs_to :parameter_definition
def self.ransackable_attributes(auth_object = nil)
%w(name value) + _ransackers.keys
end
ransacker :value_to_f do
Arel.sql("CAST(parameters_parameters_groups.value as float)")
end
ransacker :pg_value_to_f do
Arel.sql("CAST(parameters.value as float)")
end
end
class ParametersGroup < ActiveRecord::Base
has_many :parameters, dependent: :destroy
end
class ParameterDefinition < ActiveRecord::Base
has_many :parameters
def self.ransackable_attributes(auth_object = nil)
%w(name id) + _ransackers.keys
end
end
# Run test
## Joins do not behave as intented
class BugTest < Minitest::Test
def test_ransack_joins
sql = Molecule.ransack(
{
identifier_parameters_parameters_group_parameters_parameter_definition_id_eq: 1,
identifier_parameters_parameters_group_parameters_value_to_f_lt: 5
}
).result.to_sql
puts sql
assert_equal('SELECT "molecules".* FROM "molecules" LEFT OUTER JOIN "parameters" ON "parameters"."parameterable_id" = "molecules"."id" AND "parameters"."parameterable_type" = \'Molecule\' LEFT OUTER JOIN "parameters_groups" ON "parameters_groups"."id" = "parameters"."parameters_group_id" LEFT OUTER JOIN "parameters" "parameters_parameters_groups" ON "parameters_parameters_groups"."parameters_group_id" = "parameters_groups"."id" LEFT OUTER JOIN "parameter_definitions" ON "parameter_definitions"."id" = "parameters_parameters_groups"."parameter_definition_id" WHERE ("parameter_definitions"."id" = 1 AND CAST(parameters_parameters_groups.value as float) < \'5\')', sql)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment