Defining a method - ruby-on-rails

I am new to coding & I am taking ruby on rails online class. I have followed the lecture and documented everything but I am getting "NonMethod" error. Here what I have in my file
Controller
class CoursesController < ApplicationController
def index
#search_term = 'jhu'
#courses = Coursera.for(#search_term)
end
end
Model
class Coursera
include HTTParty
base_uri 'https://api.coursera.org/api/catalog.v1/courses'
default_params fields: "smallIcon,shortDescription", q: "search"
format :[enter image description here][1]json
def self.for term
get("", query: { query: term})["elements"]
end
end
Views
<h1>Searching for - <%= #search_term %></h1>
<table border="1">
<tr>
<th>Image</th>
<th>Name</th>
<th>Description</th>
</tr>
<% #courses.each do |course| %>
<tr class=<%= cycle('even', 'odd') %>>
<td><%= image_tag(course["smallIcon"])%></td>
<td><%= course["name"] %></td>
<td><%= course["shortDescription"] %></td>
</tr>
<% end %>
</table>
These are the messages I am getting
NoMethodError in Courses#index
Showing /Users/Dohe/my_app/app/views/courses/index.html.erb where line #11 raised:
undefined method `each' for nil:NilClass
Can any help me with what I am doing wrong
Ruby 2.2.9 and Rails 4.2.3

Check what #courses contains in the controller, and change <% end %> to <% end if #courses.present? %> in your view, Its just making sure to only try to iterate through the #courses and populate it in the view if it actually contains any data, if it is nil then nil does not have a each method defined for it so you're getting the
undefined method `each' for nil:NilClass

As Subash stated in the comment, #courses is nil, which means that:
get("", query: { query: term})["elements"]
is returning nil. So, when you try #courses.each, you're getting the NoMethod error.
If you expect:
get("", query: { query: term})["elements"]
not to be nil, then you'll have to debug that. You could show us your console logs and we might be able to help with that.
Also, to protect from the NoMethod error, you could do:
def self.for term
get("", query: { query: term})["elements"] || []
end
This says, essentially, "return an empty array if get("", query: { query: term})["elements"] is nil". This will resolve your error, but could mask other problems you might be having. So, proceed with caution.

Related

Rails 5 associated table data

Inside the console I can access a related table by doing something like this.
#eec = ExpenseExpenseCategory.last
puts #eec.expense.payee.first_name
-> Charles
but inside a template if i have something to the extent of
<% #expense_expense_categories.each do |eec| %>
<tr>
<td><%= eec.amount %></td>
<td><%= eec.expense.payee.first_name %></td>
<\tr>
<% end %>
which is set in my reports controller
def expense_expense_category_report
#expense_expense_categories = ExpenseExpenseCategory.all
respond_to do |format|
format.html {}
format.js {}
end
end
I get this error: ActionView::Template::Error (undefined method `payee' for nil:NilClass):
but, If I call expense such as
<td><%= eec.expense %></td>
I get a relation Expense:0x007f9c8ad91b28> but I get the same error when trying to access it's attributes
<td><%= eec.expense.date %></td>
I get the error ActionView::Template::Error (undefined method `date' for nil:NilClass):
How can I make certain I can access the methods like I do in the console?
It is likely that one or more of your categories does not have an expense associated with it. This sometimes happens to me if I have entered data and then added an association to a model.
This means that it is nil,and you are calling the date on a nil object, which causes your error.
You could check this in the console by running some test code like below
ExpenseExpenseCategory.all.each do |eec|
if eec.expense.nil?
puts "Expense category #{eec.id} has no expense"
end
end

Conflicting View Logic

I have a show page where I need to both show the student's units and create a unit for them. However an error is being incurred when trying to do both.
In my controller
def show
#student = Student.find(params[:id])
#unit = #student.units.build
#units = #student.units
end
In my view
<%= simple_form_for #unit, url: student_units_path(#student) %>
# form...
<% end %>
<% #units.each do |unit| %>
<tr>
<td><%= unit.course %></td>
<td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
</tr>
<% end %>
The unit.course call works and any call that is only the first child of unit, however when I call a second method on unit I get this error:
undefined method `strftime' for nil:NilClass
despite knowing that the unit exists, hence the first call working
It seems your issue is that unit.mailing_date is nil, for newly-built records.
One solution would be to define a default value for mailing_date, either at the database level or in your application. For example, you could do something like:
class Unit < ActiveRecord::Base
# ....
after_initialize :set_default_mailing_date
private
def set_default_mailing_date
self.mailing_date ||= Date.today
end
end
Or alternatively, you could leave the mailing_date as nil and handle this gracefully in the view:
<td><%= unit.mailing_date.try!(:strftime, '%m/%d/%y') %></td>
If you are using ruby version 2.3+, then I would advise using the built-in safe navigation operator, rather than ActiveSupport's try! method:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') %></td>
Finally, if you went with the above choice to leave the mailing_date as nil, then perhaps you'd like to display some default value in its place - for example:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') || 'Not set' %></td>
As an alternative, I assume you don't want the new unit bound to the form being rendered which is what is causing the error.
You could do
#units = #student.units.reject(&:new_record?)
To remove the newly built unit from the collection

Rails display table alphabetically

I want to display the entirety of the user table alphabetically, I know this needs to be done in the controller:
The code which I have been using in my controller :
class UsersController < ApplicationController
#users = User.find(:all)
#users.sort! { |a,b| a.name.downcase <=> b.name.downcase }
...
end
form code :
<% #users.each do |user| %>
<tr>
<td><%= user.name %></td>
</tr>
<% end %>
Receiving the error undefined method `downcase' for nil:NilClass
What have I missed? Thank you.
You should add an order clause to your query.
#users = User.reorder(:name)
I am not sure what you are going for but if you have a significant number of users you should probably add a limit or pagination to this.
You have a user without name, that's why you got that error.
You can avoid that error with
#users.sort! { |a,b| a.name.try(:downcase) <=> b.name.try(:downcase) }
But it is a ugly solution, the correct way is doing that directly on the query
User.order("name")
Actually I think this should belongs to model, I believe that will make your controller code more readable.
and having scope will make your conditions chain able, read more about scope
assuming u have rails 3.x
#users model
class User < ActiveRecord::Base
scope :asc_by_name, lambda {
{:order => 'name ASC'}
}
end
#users controller
#users = User.asc_by_name
and in your loop use,
<% #users.each do |user| %>
<tr>
<td><%= user.try(:name) %></td>
</tr>
<% end %>
Your database engine is usually better suited for sorting so I would sort in the query:
#user = User.order(:name)
will give you all User objects sorted by the name column. This would also work the same:
#user = User.find(:all, order: :name)

Understanding Rails: index action- how to return none when no search param present?

I have a very basic index action that accepts a search param. And it works...
def index
if params[:search]
#reports = Report.where("title LIKE ?", "%#{params[:search]}%")
else
#reports = Report.all
end
end
But, it shows ALL records when there is no search parameter...where i'd like it to show none. Tried setting #reports = nil but that threw an error.
What's the proper way to do this?
Update: adding error message per request:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
Extracted source (around line #16):
13: <th>File Type</th>
14: <th>Title</th>
15: </tr>
16: <% for report in #reports %>
17: <tr>
18: <td><%= report.serial %></td>
19: <td><%= report.file_kind %></td>
If you want #reports to be an array you could do :
#reports = params[:search].present?? Report.where("title LIKE ?", "%#{params[:search]}%").all : []
If you want to be uber-clever but not super db efficient this gives you #reports as an ActiveRelation
#reports = Report.where(params[:search].present?? ["title like ?", "%#{params[:search]}%"] : "id < 0")
But really, the controller isn't the offending portion here. When #reports is nil where does the error come from? Most likely you should do
def index
#reports = Report.where("title LIKE ?", "%#{params[:search]}%") if params[:search].present?
end
and then make sure the rest of your action can handle a nil #reports gracefully.
There is nothing wrong with setting the #reports variable to nil. I suspect that the error is thrown from either an after filter or the view itself, where you probably have some code that doesn't expect #reports to be nil. What error are you getting?
Jesse suggestion is correct. But, it still shows the error on your view page. So, you just add the if condition at the end for end section.
... <% end if #reports != nil %>

Rails: undefined method `strftime' for nil:NilClass, but value (without strftime) returns OK

I have an odd problem with a (rails 3) activerecord query.
If I submit query #1 (below) to the view (below) everything works fine...but if I submit query #2 (below), I get "undefined method `strftime' for nil:NilClass"
...However, if I strip the strtime string away from query #2, it returns the unformatted time just fine.
"Professional specialties" is a has_many :through table; I'm assuming that has something to do with it...but I can't quite figure out what.
Any idea what's going on? All suggestions appreciated:
Query #1 (works fine)
#professionals = Professional.all(:include => :user, :conditions => ["users.first_name = ? AND users.last_name = ?", params[:name][:first], params[:name][:last]])
Query #2 (breaks strtime)
#professionals = Professional.all(:include => [:user, :professional_specialties], :conditions => ["professional_specialties.profession_type_id = ?", params[:profession_type]] )
View
<% #professionals.each do |p| %>
<tr>
<td><%= link_to("%s %s" % [p.user.first_name, p.user.last_name], p) %></td>
<td><%= p.business %></td>
<td><%= p.user.role.name %></td>
<td><%= p.user.created_at %></td>
<td><%= p.user.last_sign_in_at.strftime("%Y") %></td>
</tr>
<% end %>
My best guess would be that the two queries give you different resultsets. In the second resultset, one or more of the users has a NULL value for the last_sign_in_at column.
Run Professional.all(...).map(&:users) in the Rails console (rails console in your application directory), and double-check that they all have valid timestamps.

Resources