ransack: Rails 4.2: NoMethodError: undefined method `asc' for # I’m in the process of upgrading a Rails 4.1.8 app to Rails 4.2.0.rc2. I’m not seeing this behavior on 4.1.8 and I’m sure the error could be on my end, but I’m not quite sure I see a link to that. Also, I’ve some wrappers (Concerns) around ransack that I’ll try to unravel to simplify this report, so forgive me if things look a little funky. Here goes…
Using MRI 2.1.0, I get the same results with master (ff0327df2c21) and the rails-4.2 branch; I’ve been using ransack 1.5.1 with my Rails 4.1.8 branch with success.
The backtrace for my failing specs all look similar to this:
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `asc' for #<Arel::Nodes::NamedFunction:0x007ffcf0ab4a88>
Shared Example Group: "a pageable controller" called from ./spec/controllers/zone_maps_controller_spec.rb:32
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:44:in `visit_Ransack_Nodes_Sort'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:52:in `visit'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:5:in `accept'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `block in visit_Array'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `map'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `visit_Array'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:52:in `visit'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:5:in `accept'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/adapters/active_record/context.rb:38:in `evaluate'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/search.rb:42:in `result'
# ./app/controllers/zone_maps_controller.rb:7:in `index'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/base.rb:198:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/rendering.rb:10:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:117:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:117:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:92:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:92:in `_run_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:81:in `run_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/callbacks.rb:19:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/rescue.rb:29:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications.rb:164:in `block in instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications.rb:164:in `instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activerecord-4.2.0.rc2/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/base.rb:137:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionview-4.2.0.rc2/lib/action_view/rendering.rb:30:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:629:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:65:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:505:in `get'
# ./spec/controllers/zone_maps_controller_spec.rb:33:in `block (4 levels) in <top (required)>'
My controller’s #index
method:
def index
@zone_maps = ZoneMap.
search_with_sort(search_params, sort_params, name: 'name').result.
page(page).per(page_limit)
respond_with @zone_maps,
meta: {
page: current_page(@zone_maps.count),
page_count: @zone_maps.total_pages,
total_count: @zone_maps.total_count
}
end
The .search_with_sort
wrapper:
module ModelSupport
module RansackSearchable
extend ActiveSupport::Concern
included do
if table_exists?
columns.each do |column|
next unless %i[string text].include? column.type
ransacker column.name.to_sym, formatter: proc(&:downcase) do |parent|
parent.table[column.name.to_sym].lower
end
end
end
# Uses ransack to search and sort. Prioritizes search criteria from
# search before sort and defaults.
#
# @param search [Hash] Search criteria for ransack.
# @param sort [Hash] Sort name and direction. Used only if search param
# didn't have valid criteria.
# example: { name: 'created_at', dir: 'desc' }
# @param defaults [Hash] Default sort criteria if all else fails.
# example: { name: 'name', dir: 'asc' }
# @return [Hash] Search params for ransack.
def self.search_with_sort(search = {}, sort = {}, defaults = {})
results = self.search(search)
defaults[:dir] ||= 'asc'
results.sorts.any?(&:valid?) || results.build_sort(sort).valid? || results.build_sort(defaults)
results
end
end
end
end
Part of the controller spec:
describe 'GET index' do
it_behaves_like 'a pageable controller' do
before { get :index }
end
end
The shared example:
RSpec.shared_examples 'a pageable controller' do |ivar_symbol|
let(:assigns_symbol) do
ivar_symbol || described_class.controller_name.to_sym
end
before do
allow(subject).to receive(:page_limit) { 25 }
end
it 'defaults to #page_limit' do
expect(assigns(assigns_symbol).default_per_page).to eq 25
end
it 'has .find result that responds to #current_page' do
expect(assigns(assigns_symbol).current_page).to eq 1
end
it 'has .find result that responds to #page.size' do
expect(assigns(assigns_symbol).page.size).to eq(assigns(assigns_symbol).count)
end
end
After that, I’m not sure what other code on my end may be pertinent. Sure smells like some changes happened in Arel…
I’m in the process of upgrading a Rails 4.1.8 app to Rails 4.2.0.rc2. I’m not seeing this behavior on 4.1.8 and I’m sure the error could be on my end, but I’m not quite sure I see a link to that. Also, I’ve some wrappers (Concerns) around ransack that I’ll try to unravel to simplify this report, so forgive me if things look a little funky. Here goes…
Using MRI 2.1.0, I get the same results with master (ff0327df2c21) and the rails-4.2 branch; I’ve been using ransack 1.5.1 with my Rails 4.1.8 branch with success.
The backtrace for my failing specs all look similar to this:
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `asc' for #<Arel::Nodes::NamedFunction:0x007ffcf0ab4a88>
Shared Example Group: "a pageable controller" called from ./spec/controllers/zone_maps_controller_spec.rb:32
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:44:in `visit_Ransack_Nodes_Sort'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:52:in `visit'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:5:in `accept'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `block in visit_Array'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `map'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:13:in `visit_Array'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:52:in `visit'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/visitor.rb:5:in `accept'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/adapters/active_record/context.rb:38:in `evaluate'
# /Users/sloveless/.gem/ruby/2.1.0/bundler/gems/ransack-ff0327df2c21/lib/ransack/search.rb:42:in `result'
# ./app/controllers/zone_maps_controller.rb:7:in `index'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/base.rb:198:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/rendering.rb:10:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:117:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:117:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:169:in `block in halting'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:92:in `call'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:92:in `_run_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/callbacks.rb:81:in `run_callbacks'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/callbacks.rb:19:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/rescue.rb:29:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications.rb:164:in `block in instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activesupport-4.2.0.rc2/lib/active_support/notifications.rb:164:in `instrument'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/activerecord-4.2.0.rc2/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/abstract_controller/base.rb:137:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionview-4.2.0.rc2/lib/action_view/rendering.rb:30:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:629:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:65:in `process'
# /Users/sloveless/.gem/ruby/2.1.0/gems/actionpack-4.2.0.rc2/lib/action_controller/test_case.rb:505:in `get'
# ./spec/controllers/zone_maps_controller_spec.rb:33:in `block (4 levels) in <top (required)>'
My controller’s #index
method:
def index
@zone_maps = ZoneMap.
search_with_sort(search_params, sort_params, name: 'name').result.
page(page).per(page_limit)
respond_with @zone_maps,
meta: {
page: current_page(@zone_maps.count),
page_count: @zone_maps.total_pages,
total_count: @zone_maps.total_count
}
end
The .search_with_sort
wrapper:
module ModelSupport
module RansackSearchable
extend ActiveSupport::Concern
included do
if table_exists?
columns.each do |column|
next unless %i[string text].include? column.type
ransacker column.name.to_sym, formatter: proc(&:downcase) do |parent|
parent.table[column.name.to_sym].lower
end
end
end
# Uses ransack to search and sort. Prioritizes search criteria from
# search before sort and defaults.
#
# @param search [Hash] Search criteria for ransack.
# @param sort [Hash] Sort name and direction. Used only if search param
# didn't have valid criteria.
# example: { name: 'created_at', dir: 'desc' }
# @param defaults [Hash] Default sort criteria if all else fails.
# example: { name: 'name', dir: 'asc' }
# @return [Hash] Search params for ransack.
def self.search_with_sort(search = {}, sort = {}, defaults = {})
results = self.search(search)
defaults[:dir] ||= 'asc'
results.sorts.any?(&:valid?) || results.build_sort(sort).valid? || results.build_sort(defaults)
results
end
end
end
end
Part of the controller spec:
describe 'GET index' do
it_behaves_like 'a pageable controller' do
before { get :index }
end
end
The shared example:
RSpec.shared_examples 'a pageable controller' do |ivar_symbol|
let(:assigns_symbol) do
ivar_symbol || described_class.controller_name.to_sym
end
before do
allow(subject).to receive(:page_limit) { 25 }
end
it 'defaults to #page_limit' do
expect(assigns(assigns_symbol).default_per_page).to eq 25
end
it 'has .find result that responds to #current_page' do
expect(assigns(assigns_symbol).current_page).to eq 1
end
it 'has .find result that responds to #page.size' do
expect(assigns(assigns_symbol).page.size).to eq(assigns(assigns_symbol).count)
end
end
After that, I’m not sure what other code on my end may be pertinent. Sure smells like some changes happened in Arel…
About this issue
- Original URL
- State: closed
- Created 10 years ago
- Comments: 15 (7 by maintainers)
Commits related to this issue
- Fixed: Rails 4.2: NoMethodError: undefined method 'asc' for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by deleted user 9 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method 'asc' for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by deleted user 9 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method asc for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by deleted user 9 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method 'asc' for #<Arel::Nodes::NamedFunction... #483 [hotfix] some code refactoring added test for case insensitive sorting freeze the asc and desc strin... — committed to roman-franko/ransack by deleted user 9 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method asc for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by deleted user 9 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method asc for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by roman-franko 6 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method asc for #<Arel::Nodes::NamedFunction... #483 — committed to roman-franko/ransack by roman-franko 6 years ago
- Fixed: Rails 4.2: NoMethodError: undefined method asc for #<Arel::Nodes::NamedFunction... #483 — committed to tekniklr/ransack by roman-franko 6 years ago
Here is my workaround:
The problem is that Ransack expects Arel nodes to have
asc
anddesc
methods defined, but some of them don’t have these methods. A temporary solution is to include these methods in Arel node that you use in your ransacker (in my case it wasArel::Nodes::NamedFunction
).