jbox-web / ajax-datatables-rails

A wrapper around DataTable's ajax methods that allow synchronization with server-side pagination in a Rails app
MIT License
590 stars 227 forks source link

undefined method `to_unsafe_h' for nil:NilClass #246

Closed adamw005 closed 6 years ago

adamw005 commented 7 years ago

I am getting Error 1 when trying to load the datatable view. When I visit the .json page at 'prices/index.json' I see this:

NoMethodError in PricesController#index undefined method `to_unsafe_h' for nil:NilClass

  respond_to do |format|
      format.html
      format.json { render json: PricesDatatable.new(view_context) }
    end
  end
adamw005 commented 7 years ago
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/datatable/datatable.rb:74:in `get_param'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/datatable/datatable.rb:43:in `columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/datatable/datatable.rb:49:in `column_by'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:56:in `block in connected_columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:55:in `map'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:55:in `connected_columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:63:in `searchable_columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:69:in `search_columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/orm/active_record.rb:48:in `build_conditions_for_selected_columns'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/orm/active_record.rb:31:in `build_conditions'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/orm/active_record.rb:10:in `filter_records'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:98:in `records_filtered_count'
vendor/bundle/ruby/2.3.0/gems/ajax-datatables-rails-0.4.0/lib/ajax-datatables-rails/base.rb:43:in `as_json'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/json/encoding.rb:35:in `encode'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/json/encoding.rb:22:in `encode'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/object/json.rb:37:in `to_json_with_active_support_encoder'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb:116:in `block in <module:Renderers>'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb:45:in `block in _render_to_body_with_renderer'
vendor/ruby-2.3.4/lib/ruby/2.3.0/set.rb:306:in `each_key'
vendor/ruby-2.3.4/lib/ruby/2.3.0/set.rb:306:in `each'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb:41:in `_render_to_body_with_renderer'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/renderers.rb:37:in `render_to_body'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/rendering.rb:25:in `render'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/rendering.rb:16:in `render'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
vendor/ruby-2.3.4/lib/ruby/2.3.0/benchmark.rb:308:in `realtime'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/core_ext/benchmark.rb:12:in `ms'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:44:in `block in render'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:87:in `cleanup_view_runtime'
vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.6/lib/active_record/railties/controller_runtime.rb:25:in `cleanup_view_runtime'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:43:in `render'
app/controllers/prices_controller.rb:6:in `block (2 levels) in index'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/mime_responds.rb:217:in `respond_to'
app/controllers/prices_controller.rb:4:in `index'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/base.rb:198:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/rendering.rb:10:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:117:in `call'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:505:in `call'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/callbacks.rb:19:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/rescue.rb:29:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications.rb:164:in `block in instrument'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/notifications.rb:164:in `instrument'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.6/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/abstract_controller/base.rb:137:in `process'
vendor/bundle/ruby/2.3.0/gems/actionview-4.2.6/lib/action_view/rendering.rb:30:in `process'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal.rb:196:in `dispatch'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_controller/metal.rb:237:in `block in action'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/routing/route_set.rb:43:in `serve'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/journey/router.rb:43:in `block in serve'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/journey/router.rb:30:in `each'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/journey/router.rb:30:in `serve'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/routing/route_set.rb:817:in `call'
vendor/bundle/ruby/2.3.0/gems/warden-1.2.7/lib/warden/manager.rb:36:in `block in call'
vendor/bundle/ruby/2.3.0/gems/warden-1.2.7/lib/warden/manager.rb:35:in `catch'
vendor/bundle/ruby/2.3.0/gems/warden-1.2.7/lib/warden/manager.rb:35:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/etag.rb:24:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/conditionalget.rb:25:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/head.rb:13:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/params_parser.rb:27:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/flash.rb:260:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/session/abstract/id.rb:225:in `context'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/session/abstract/id.rb:220:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/cookies.rb:560:in `call'
vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.6/lib/active_record/query_cache.rb:36:in `call'
vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.6/lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:88:in `__run_callbacks__'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/callbacks.rb:27:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/rack/logger.rb:38:in `call_app'
vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/rack/logger.rb:20:in `block in call'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb:68:in `block in tagged'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb:26:in `tagged'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/tagged_logging.rb:68:in `tagged'
vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/rack/logger.rb:20:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/request_id.rb:21:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/methodoverride.rb:22:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/runtime.rb:18:in `call'
vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.6/lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
vendor/bundle/ruby/2.3.0/gems/actionpack-4.2.6/lib/action_dispatch/middleware/static.rb:120:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/sendfile.rb:113:in `call'
vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:518:in `call'
vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/application.rb:165:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/lock.rb:17:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/content_length.rb:15:in `call'
vendor/bundle/ruby/2.3.0/gems/rack-1.6.8/lib/rack/handler/webrick.rb:88:in `service'
vendor/ruby-2.3.4/lib/ruby/2.3.0/webrick/httpserver.rb:140:in `service'
vendor/ruby-2.3.4/lib/ruby/2.3.0/webrick/httpserver.rb:96:in `run'
vendor/ruby-2.3.4/lib/ruby/2.3.0/webrick/server.rb:296:in `block in start_thread'
mrudult commented 7 years ago

@adamw005 Had the same issue. Downgrading to 0.3.1 worked for me.

Basically the change is here

adamw005 commented 7 years ago

Thanks! That fixed the error on prices/index.json. My view is now showing a /tn/1 error though.

edit: Never mind, the error was in my view

Going back to v0..3 means I need to change my Map Data to something like this?

class PricesDatatable < AjaxDatatablesRails::Base

  def view_columns
    @view_columns ||= {
      brand: {source: 'Price.brand' },
      sku: {source: 'Price.sku' },
      # title: {source: 'Price.title' },
      price: {source: 'Price.price' }
    }
  end

  **def data
    records.map do |record|
      [
        record.brand,
        record.sku,
        # title: record.title,
        record.price
      ]
    end
  end**

  private

  def get_raw_records
    Price.all
  end

end

My json result:

{"draw":0,"recordsTotal":139831,"recordsFiltered":139831,"data":[["Delta","52671-WC20-BG","7.47"],["Brizo","RP62371-1.2","11.02"],["Delta","RP72800","15.1"],["Delta","BT13210-SS","47.55"],["Delta","T14461-SS","192.4"],["Delta","BT13210","39.83"],["Delta","T14461","137.41"],["Delta","RP5651SS","70.53"],["Delta","RP5651CZ","70.53"],["Delta","RP5651","39.26"]]}
mrudult commented 7 years ago

@adamw005 No. You need to change it to the syntax mentioned here

trh commented 7 years ago

It's because prices/index.json doesn't have the column definition in the URL. The options hash contains the params from the URL and as such needs all of the column information. It didn't used to be this way, you used to be able to call the .json on the URL and just get the raw json, but now to do that you have to add the column defs to the URL.

You can manually build it if you need to, note that the URL is available in the js console of the page (not for json only obviously, but for your regular datatables page request).

The pieces of data that are necessary are:

columns[0][data]=id&
columns[0][name]=&
columns[0][searchable]=true&
columns[0][orderable]=true&
columns[0][search][value]=&
columns[0][search][regex]=false&

The index of the columns array has to match the index of your data records array (or hash), as does the data attribute. Once you've populated the data for ALL the columns you want, open the console and run your string through URI to encode it.

2.3.4 (main):0 > URI.encode("columns[0][data]=id&
2.3.4 (main):0 * columns[0][name]=&
2.3.4 (main):0 * columns[0][searchable]=true&
2.3.4 (main):0 * columns[0][orderable]=true&
2.3.4 (main):0 * columns[0][search][value]=&
2.3.4 (main):0 * columns[0][search][regex]=false&
2.3.4 (main):0 * ")

You'll get something like this:

"columns[0][data]=id&%0Acolumns[0][name]=&%0Acolumns[0][searchable]=true&%0Acolumns[0][orderable]=true&%0Acolumns[0][search][value]=&%0Acolumns[0][search][regex]=false&%0A"

Add the encoded string to your URL (domain + path) and the json should load without error.

rajeevkhangar commented 7 years ago

I am using ajax-datatables-rails (0.4.0) and still getting same error .... undefined method to_unsafe_h' for nil:NilClass

I am using latest version and this version have updated code here https://github.com/jbox-web/ajax-datatables-rails/blob/master/lib/ajax-datatables-rails/datatable/datatable.rb

Instead of that I am still getting same problem. Please suggest me what should I do. Thanks

mrudult commented 7 years ago

@rajeev-khangar As @trh suggests, are you passing column definitions/options to the request?

Svashta commented 7 years ago

I have same problem here. I don't understand where I should build these definitions to be passed, and foremost why? This is just wierd and wrong imho.

rajeevkhangar commented 7 years ago

@mrudult I think this issue is coming when we have slow internet speed or loading issue. otherwise it is working fine.

mrudult commented 6 years ago

@rajeev-khangar I don't think this has anything to with internet speed.

SimonVillage commented 6 years ago

problem exist for us as well. any solution except downgrading?

ahmdqader commented 6 years ago

how to fix this error?

def index
        respond_to do |format|
            format.html
            format.json { render json: CategoryDatatable.new(view_context) }
        end
end

class CategoryDatatable < AjaxDatatablesRails::Base

  def view_columns
    # Declare strings in this format: ModelName.column_name
    # or in aliased_join_table.column_name format
    @view_columns ||= {
      id: { source: "Category.id", cond: :eq },
      name: { source: "Category.name", cond: :like }
    }
  end

  def data
    records.map do |record|
      {
        # example:
        id: record.id,
        name: record.name
      }
    end
  end

  def get_raw_records
    # insert query here
    Category.all
  end

end
<table class="table tabel-striped" id="categories-datatable" data-source="<%= admin_categories_path(format: :json) %>">
  <thead>
    <tr>
      <th>ID</th>
      <th>Name</th>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>
$ ->
  $('#categories-datatable').dataTable
    processing: true
    serverSide: true
    ajax: $('#categories-datatable').data('source')
    pagingType: 'full_numbers'
    columns: [
      {data: 'id'}
      {data: 'name'}
    ]
    # pagingType is optional, if you want full pagination controls.
    # Check dataTables documentation to learn more about
    # available options.
MichaelBK commented 6 years ago

undefined method `to_unsafe_h' for nil:NilClass problem exist for us as well. any solution except downgrading?

put it in the controller before calling Datatable

params["columns"] ||= { "0" => {"data" => "" } }
params["length"]  ||= -1
demir commented 6 years ago

Problem is still going on. Anyone find a solution?

LuisUrrutia commented 6 years ago

@demir the solution of @MichaelBK works

epipheus commented 5 years ago

It's 2019 and I still see this problem. Is there any real fix for it?

haohaodehao commented 5 years ago

In 2019.5.29 and I use sqlite and create a model with no any records. I see this problem. i use rails api only with this gem.

osdakira commented 5 years ago

The error occurred in get_param method. Our params that is first argument must be a ActionController::Parameters instance. Because the to_unsafe_h is a method of ActionController::Parameters. When you change the params to a hash you have the error.

File: vendor/bundle/gems/ajax-datatables-rails-1.0.0/lib/ajax-datatables-rails/datatable/datatable.rb
70:       def get_param(param)
71:         options[param].to_unsafe_h.with_indifferent_access
72:       end
autotelik commented 5 years ago

Had this issue .. In my case was related to link to access the page. I had a link to the data tables pages with format :json - <%= link_to 'Files', files_path(format: :json) %> which caused this error - since the call does not have all the required params/options

Replacing with <%= link_to 'Files', files_path() %> fixed it - since now the first call renders the HTML view/table, and then the javascript then takes care of populating the table with further automatic calls to the :json format end point

diesl commented 5 years ago

I suppose this is fixed in #315, but a new version has not been released yet