I have just implemented datatables based off Ryan Bates' rails cast #340 'http://railscasts.com/episodes/340-datatables?autoplay=true' and I am receiving this error 'undefined method `map' for nil:NilClass'. Everywhere I have looked people are saying it is because what you are trying to call is undefined but in this case I am unsure why this is an error as this is being defined and I have followed this rails cast to the last detail.
The error i'm getting is "undefined method `map' for nil:NilClass" The stack trace is as follows:
Showing /Users/calligouser/Documents/CalligoProjects/cloudcentrev2/app/views/ips/index.html.erb where line #7 raised:
<li class="left"><%= select_tag 'ip_status_id', options_for_select(@ip_statuses, @status_id), { prompt: "All" } %></li>
This error .map is being made in the controller when defining @ip_statuses. The code goes to the model where it retrieves a hash of values as follows:
STATUSES = { 0 => "Unallocated",
1 => "Allocated",
2 => "Reserved",
3 => "Transient"
}
I am trying to load a datatable of IP addresses in an IP index view.
IP Controller (index)
def index
@ips = Ip.all
respond_to do |format|
format.html
format.json { render json: IpsDatatable.new(view_context) }
end
@ip_statuses = Ip::STATUSES.map {|key,value| [value,key]}
end
ips_datatable.rb file for datatables options
class IpsDatatable
delegate :params, :h, :link_to, :number_to_currency, to: :@view
def initialise(view)
@view = view
end
def as_json(options = {})
{
sEcho: params[:sEcho].to_i
iTotalRecords: Ip.count,
iTotalDisplayRecords: ips.total_entries,
aaData: data
}
end
private
def data
ips.map do |ip|
[
link_to(ip.ip_address, ip),
h(ip.system_name),
h(ip.description),
h(ip.system_location),
h(ip.status)
]
end
end
def ips
@ips ||= fetch_ips
end
def fetch_ips
ips = Ip.order("#{sort_column} #{sort_direction}")
ips = ips.page(page).per_page(per_page)
if params[:sSearch].present?
ips = ips.where("name like :search or category like :search", search: "%#{params[:sSearch]}")
end
ips
end
def page
params[:iDisplayStart].to_i/per_page + 1
end
def per_page
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10
end
def sort_column
columns = %w[ip_address system_name system_location description status]
columns[params[:iSortCol_0].to_i]
end
def sort_direction
params[:sSortDir0] == "desc" ? "desc" : "asc"
end
end
IPs JQuery file
jQuery ->
# -------------------------------------------------------------------------
# DataTables Server Side
# -------------------------------------------------------------------------
$('#ip-table').dataTable
sPaginationType: "full_numbers"
bJQueryUI: true
bProcessing: true
bServerSide: true
sAjaxSource: $('#ip-table').data('source')
IP Table form view
<table id="ip-table" class="full display" data-source="<%= products_url(format: "json") %>">
<thead>
<tr>
<th>Ip address</th>
<th>System name</th>
<th>Description</th>
<th>System location</th>
<th>Status</th>
<th>Edit / Delete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
EDIT: I have found that the application doesn't reach beyond the respond_to block, so I attempted to debug within the ip_datatables file and the application seems to be failing before reaching the code in the file. I used a puts '....' after format.json line of code and it does reach this, but for some reason it doesn't return from within the ip_datatables file.
OK I actually found the problem to this. In the controller I removed everything other than the respond to block and placed this code above it:
@ip_statuses = Ip::STATUSES.map {|key,value| [value,key]}
if !session[:ip_status_id].nil? then @status_id = session[:ip_status_id] else @status_id = 1 end
@ips = @ips.where(status: @status_id) unless @status_id == ""
I then removed the :h from the delegation in the ips_datatable file and removed all instances of the 'h' method being used. I then filled in missing commas in the ips_datatable file.
I also had to remove the edit / delete header from the html table as the datatable won't recognise this as it isn't actually a column in the database.