I have defined in analysis_result.rb this:
def total_matches
...
end
and I am trying to use it in a view _rable_row.haml like this:
- if analysis.results.total_matches != 0
= link_to analysis.title, analysis, class: 'js-toggle', data: { href: "loading-#{analysis.id}" }
- elsif analysis.results.total_matches == 0
= render partial: 'partials/shared/empty'
but I'm getting undefined method 'total_matches' for #<Mongoid::Criteria:
Can someone tell me why is this happening?
The error undefined method 'total_matches' arises because total_matches cannot be called directly on the results array, it is an attribute of objects present inside the results array. I.e. you are trying to call an attribute of an object on array of objects, instead of on the object itself.
Related
I have a helper method which returns array
def site
return Website::SITE.collect!{ |arr| arr if arr[1] != 'site_builder' }
end
Website::SITE return array in console
I call this method in view.
- site.each do |menu|
tr
td= menu[0]
Here it gives ActionView::Template::Error (undefined method `[]' for nil:NilClass):
Let's redefine the function like this:
def site
Website::SITE.compact.select{ |arr| arr if arr[1] != 'site_builder' }
end
It's because, the array Website::SITE contains nil value.
[["About ", "about"], ["Calendar", "calendar"], ["Gallery", "gallery"], ["Information", "information"], ["Manage ", "manage"], nil, ["Template", "website"]]
If you didn't put the method in the helpers folder but directly to the controller, then you have to add a line of code after your method to make it work.
def site
return Website::SITE.collect!{ |arr| arr if arr[1] != 'site_builder' }
end
helper_method :site
This should fix the error
I have this defined in a model called analysis_result.rb:
def total_matches
return 0 unless self.patterns
self.patterns.sum do |_, v|
matches = v.matches.try(:count) || 0
if v.additional.present? && v.additional['ggroup'].present?
bc_matches = v.additional['ggroup'].try(:count) || 0
else
bc_matches = 0
end
matches + bc_matches
end
end
I am trying to use it in in a view called _rable_row.haml in order to check beforehand if total_matches is 0 or not. If it is 0 I want to display a partial instead of letting the user go to the link.
This is the code from the view to check if analysis.results.total_matches != 0:
%tr.form-table__row{ class: ('form-table__row--disabled' if analysis.processing?) }
%td.form-table__data= check_box_tag "checkbox_object_ids[]", analysis.id
%td.form-table__data
- if analysis.results.total_matches == 0
= render partial: 'partials/shared/empty'
- elsif analysis.results.total_matches != 0
= link_to analysis.title, analysis, class: 'js-toggle', data: { href: "loading-#{analysis.id}" }
- unless analysis.viewed
%span.dashboard__icon.dashboard__icon--small.fa.fa-circle.text-info{ aria: { hidden: 'true' }, title: 'New' }
I get undefined method 'total_matches' for #<Mongoid::Criteria:0x00007fc51c5e3720>
Your problem comes from the definition of the method itself. You've declared your method total_matches on analysis_result.rb but you're calling analysis.results.total_matches.
I would write analysis.total_matches.
Bonus:
I would suggest a guard clause on top of your method total_matches
def total_matches
return 0 unless self.patterns
# ...
end
From what I could see in your updated question, your AnalysisResult belongs to Analysis. and total_matches is a instance method of Analysis.
But you are calling it like analysis.results.total_matches here, analysis.results will give you an active record array as analysis has_many results, on top of which you are trying to call total_matches.
You should try analysis.results.find the one instance and call total_matches on top of it.
For ex: analysis.results.last.total_matches(I am just taking .last for example)
I solved the problem differently:
- if analysis.results.sum(&:total_matches) != 0
only changed to this.
The problem is really simple. I want to display error notifications outside simple_form_for tag for every controller in my app.
I use the following code:
- if #user.errors.present?
.alert-box.alert{ data: { alert: true } }
%div= t('simple_form.error_notification.default_message')
Which is OK, but only for one controller with #user variable. I want to know if there is some clever way to get this class instance variable (#user) without hardcoding the name. In each controller its different but it corresponds with current controller name #user for UsersController etc.
Thanks for the help. Unfortunately I can accept only one answer :)
Possible solution
I end up with helper method:
def errors_present?
# returns string like "UsersController" with support for name-spaced controllers
controller_name = controller.class.to_s.split('::').last
# extract out the "user" portion
prefix_name = controller_name.gsub(/controller/i, '').singularize.downcase
# is there a defined instance variable with this name?
i_var = controller.instance_variable_get(:"##{prefix_name}")
return i_var.errors.present? if i_var != nil
false
end
and view code:
- if errors_present?
.alert-box.alert{ data: { alert: true } }
%div= t('simple_form.error_notification.default_message')
If all of your controllers follow the same naming convention, then the instance variable name is the singular name of the controller. You can replace #user with the following:
instance_variable_get("##{controller.controller_name.singularize}")
If you move that into a helper method in application_helper.rb:
def controller_record
instance_variable_get("##{controller.controller_name.singularize}")
end
You can then reference controller_record in your view:
- if controller_record.errors.present?
.alert-box.alert{ data: { alert: true } }
%div= t('simple_form.error_notification.default_message')
If you're going to do this in a dynamic route than you'll need to ensure that the instance variable you use matches what can be inferred from the controller name. You can then use this in a helper method.
def controller_error_present
# returns string like "UsersController" with support for name-spaced controllers
controller_name = controller.class.to_s.split('::').last
# extract out the "user" portion
prefix_name = controller_name.gsub(/controller/i, '').singularize.downcase
# is there a defined instance variable with this name?
controller.instance_variable_get(:"##{prefix_name}") != nil
end
To be used like:
- if controller_error_present
.alert-box.alert{ data: { alert: true } }
%div= t('simple_form.error_notification.default_message')
As long as you initialize a #user variable in your controller than it will be picked up by the instance variable check.
I'm bringing in xml data to my application controller, passing to an array and then passing the data stored in this array to the view and into a highchart. Can anyone help please, I've the vast majority of it done, I just can't see what I'm doing wrong.
def index
#doc = Nokogiri::XML(open("http://api.worldbank.org/countries/BRA/indicators/1.0.HCount.2.5usd?per_page=10&date=1960:2014"))
#values = Array.new(9)
for i in 0 .. 8
#values[i] = #doc.xpath('//wb:value')
end
end
I then call the data in my series:
data: [<%=#values[0]%>, <%=#values[1]%>, <%=#values[2]%>, <%=#values[3]%>, <%=#values[4]%>, <%=#values[5]%>, <%=#values[6]%>, <%=#values[7]%>, <%=#values[8]%>]
The error message is as below:
undefined method `[]' for nil:NilClass
highlighted area where the error is:
data: [<%=#values[0]%>, <%=#values[1]%>, <%=#values[2]%>, <%=#values[3]%>, <%=#values[4]%>, <%=#values[5]%>, <%=#values[6]%>, <%=#values[7]%>, <%=#values[8]%>] –
On line 6, you forgot to indicate #doc.xpath('//wb:value'), so it should be:
#values[i] = #doc.xpath('//wb:value')
doc is instance variable.
For the array issue, you could use:
#doc = Nokogiri::XML(open("http://api.worldbank.org/countries/BRA/indicators/1.0.HCount.2.5usd?per_page=10&date=1960:2014"))
m = #doc.xpath("//wb:value").collect(&:text)
#values = Array.new
m.each do |m|
#values << m
end
I was using the following piece of code without any issues. the function querytags returns a set of "products". geturl function checks if a product has an image associated with it. All products with an image are pushed to productsProxy array
#query = params[:tag]
#products = queryTags(#query)
#productsProxy = Array.new
if #products != nil
#products.each do |p|
tempProduct = ProductProxy.new(p)
if tempProduct.getUrl(tempProduct.images[0]['id'], 'small', tempProduct.images[0]['file'])
#productsProxy.push(tempProduct)
end
end
else
#productProxy = []
end
Then i tried to add another parameter in the URL and changed the querytags function accordingly.
#query = params[:tag]
#taxon = params[:taxon]
#products = queryTags(#query, #taxon)
#productsProxy = Array.new
if #products != nil
#products.each do |p|
tempProduct = ProductProxy.new(p)
if tempProduct.getUrl(tempProduct.images[0]['id'], 'small', tempProduct.images[0]['file']) #now showing error
#productsProxy.push(tempProduct)
end
end
else
#productProxy = []
end
But I stated getting undefined method[]' for nil:NilClass` on the line:
if tempProduct.getUrl(tempProduct.images[0]['id'], 'small', tempProduct.images[0]['file'])
I checked with the help of debugger that #products array is not empty. I am unable to figure out why suddenly i am getting this error. please can someone help
It's not about the "#products" array being empty or not - if it was empty, the "#products" iterator wouldn't do anything. The problem is that one of your products is either lacking an images attribute or the images[0] is not returning a hash. For debugging purposes I'd start by adding "break if p.images.nil?" to the top of your iterator and go from there.