Open tayagi-aim opened 3 years ago
What's the full error trace? Only showing the top line of the error with no context makes this difficult to understand.
@tom-lord
Hi, Thanks for reply.
I did attach full trace log for rails.
@tom-lord
Hi. I had reading source code for ransack.
Therefore, I did notice that "1" character did convert from "1" to "true" for sanitize scope method.
def add_scope(key, args)
sanitized_args = if Ransack.options[:sanitize_scope_args] && !@context.ransackable_scope_skip_sanitize_args?(key, @context.object)
sanitized_scope_args(args)
else
args
end
if @context.scope_arity(key) == 1
@scope_args[key] = args.is_a?(Array) ? args[0] : args
else
@scope_args[key] = args.is_a?(Array) ? sanitized_args : args
end
@context.chain_scope(key, sanitized_args)
end
def sanitized_scope_args(args)
if args.is_a?(Array)
args = args.map(&method(:sanitized_scope_args))
end
if Constants::TRUE_VALUES.include? args
true
elsif Constants::FALSE_VALUES.include? args
false
else
args
end
end
def chain_scope(scope, args)
return unless @klass.method(scope) && args != false
@object = if scope_arity(scope) < 1 && args == true
@object.public_send(scope)
else
@object.public_send(scope, *args)
end
end
130: def add_scope(key, args)
131: binding.pry
=> 132: sanitized_args = if Ransack.options[:sanitize_scope_args] && !@context.ransackable_scope_skip_sanitize_args?(key, @context.object)
133: sanitized_scope_args(args)
134: else
135: args
136: end
137:
138: if @context.scope_arity(key) == 1
139: @scope_args[key] = args.is_a?(Array) ? args[0] : args
140: else
141: @scope_args[key] = args.is_a?(Array) ? sanitized_args : args
142: end
143: @context.chain_scope(key, sanitized_args)
144: end
[1] pry(#<Ransack::Search>)> args
=> "1"
47: def chain_scope(scope, args)
48: binding.pry
=> 49: return unless @klass.method(scope) && args != false
50: @object = if scope_arity(scope) < 1 && args == true
51: @object.public_send(scope)
52: else
53: @object.public_send(scope, *args)
54: end
55: end
[1] pry(#<Ransack::Adapters::ActiveRecord::Context>)> args
=> true
47: def chain_scope(scope, args)
48: binding.pry
49: return unless @klass.method(scope) && args != false
50: @object = if scope_arity(scope) < 1 && args == true
=> 51: @object.public_send(scope)
52: else
53: @object.public_send(scope, *args)
54: end
55: end
ArgumentError (wrong number of arguments (given 0, expected 1)):
By this sanitize scope method, For what reason "1" character convert from "1" to "true"?
Is there any other solution, better than adding a default value to the scope eg. ?
scope :scope_name, ->(string = '1') { sql }
Even more, if you pass '0' to the ransack scope this scope isn't called at all.
Solved in https://github.com/activerecord-hackery/ransack/issues/924, just add
def self.ransackable_scopes_skip_sanitize_args
[:scope_name]
end
to the model.
Hi,
I noticed I have the same issue with the letter t
, and not just with 1
and when I replace ransackable_scopes
with ransackable_scopes_skip_sanitize_args
, then my ransack start behaving wrongly.
Adding my repro app to help:
ransack: 3.0.0 rails: ~> 7.0.0 ruby: 3.0.0p0
class User < ApplicationRecord
scope :by_first_or_last_name, lambda { |name|
where('lower(first_name) LIKE :prefix', prefix: "#{name.downcase}%")
.or(where('lower(last_name) LIKE :prefix', prefix: "#{name.downcase}%"))
}
def self.ransackable_scopes(_auth_object = nil)
[:by_first_or_last_name]
end
end
class UsersController < ApplicationController
def index
users = User.ransack(by_first_or_last_name: params[:by_first_or_last_name]).result
render json: users
end
end
class UsersControllerTest < ActionDispatch::IntegrationTest
test 'should get index' do
User.create!(first_name: 'John', last_name: 'Doe')
User.create!(first_name: 'Joe', last_name: 'Dohn')
get '/users'
assert_response :success
response_body = JSON.parse(response.body)
assert_equal(response_body.size, 2)
end
test 'should get index with filter' do
User.create!(first_name: 'John', last_name: 'Doe')
User.create!(first_name: 'Joe', last_name: 'Dohn')
get '/users?by_first_or_last_name=John'
assert_response :success
response_body = JSON.parse(response.body)
# new issue here:
assert_equal(response_body.size, 1) # fails with ransackable_scopes_skip_sanitize_args (returns both users instead of the only matching one)
end
test 'should get index with filter - fails with letter t o_O' do # my initial issue
User.create!(first_name: 'John', last_name: 'Doe')
User.create!(first_name: 'Joe', last_name: 'Dohn')
assert_raise do
get '/users?by_first_or_last_name=t'
end
end
end
Version
Source code
Model
app/model/user.rb
Controller
If not "1" arguments
debug
But If "1" arguments
Why If pass arguments "1" value to the scope method for ransackable_scopes, Argument Error?