undefined method `each' in rails - ruby-on-rails

In a rails project, I use below code to retrieve data from Assignmenttable in database and show to user:
views/assignmenttables/_form.html.erb
<% task_list = Assignmenttable.find_by_current_user_id(user.id) %>
<% if task_list.blank? %>
<h1>It's blank</h1>
<% else %>
<% task_list.each do |task| %>
<%= task.id %>
<% end %>
<% end %>
data is retrive correctly from database, if task_list isn't empty this code is correct, but when task_list is empty, I get below error:
undefined method `each' for #<Assignmenttable:0x000000069541c8>
how can I handle this error?

The error you've got is caused because the object you called the .each method for is not a collection (multiple) - it's singular
Where
The way to fix this is to either use the .where method to call your data:
<%= task_list = Assignmenttable.where(user_id: current_user.id) %>
--
Associations
Or a better way will be to refactor your code to use the ActiveRecord associations which make Rails so appealing:
#app/models/user.rb
has_many :assignments
#app/models/assignment.rb # -> notice the name
belongs_to :user
current_user.assignments #-> allows you to call this in views
--
Model Names
Another thing you need to consider is your model names need to use CamelCase (AssignmentTable)

Related

Rails to symbol problems? Error: undefined method `[]' for nil:NilClass

Background info: A Deal has many coupons (#freeDeals contains all those coupons) and a coupon belongs_to a Deal.
Controller:
#freeCoupons = Coupon.where(discount: 100).order("created_at DESC").page(params[:page])
#deals = Deal.all
This code below works exactly like I want and finds the title for the deal (hard coded in the 2 for testing purposes)
<% #freeCoupons.each do |f| %>
<%= #deals[2][:title] %>
<% end %>
But when I switch it over to trying to find the title of the deal based on the coupons association through f.deal_id
<% #freeCoupons.each do |f| %>
<%= #deals[f.deal_id][:title] %>
<% end %>
It gives me this error "undefined method `[]' for nil:NilClass". Not sure what I'm missing here. Is it a symbol problem that I'm missing? Any help would be appreciated.
In your Coupon model do
belongs_to :deal
Then in your controller, include the deals using includes - this will ensure you don't make an N+1 query:
#free_coupons = Coupon.includes(:deal).where(discount: 100).order("created_at DESC").page(params[:page])
Now in your view, you can simply call the deal method on a Coupon instance:
#free_coupons.each do |f|
<%= f.deal.title %>
end
deal_id is the id in the database, and it is NOT the index in the array. deal_id can be much bigger that the number of elements. Than you get a nil, and your error when you try to access the title
You find a Object by ID with
Deal.find(f.deal_id)

Listing users by certain string, rails

I'm trying to figure out how to list my users by a certain string. In my app I have Artist who have one Artist_profile through has_one. In my Artist_profile, I have genre, which is what I'm trying to sort them out by. I do have it working at the moment with an if statement, but it looks through every single Artist and picks out the ones with the match. For example:
<% #artists.each do |artist| if artist.artist_profile.genre == "Rock" %>
<li><%= artist.id %></li>
<% end %>
I'm trying to get it something more like this, so it's less strain on my database:
<% #artists.rock.each do |artist| %>
<li><%= artist.id %></li>
<% end %>
and my model:
def self.rock
where(Artist.artist_profile.genre == "Rock")
end
However I get this error:
undefined method `artist_profile' for #<Class:0x6962940>
I think it's something to do with the has_one method, but can't seem to get this to work no matter what I try.
You should use the Joins method. It allows you to search fields in associated models. This differs from the Includes method as the Joins method doesn't include the results in the data. For example, if you wanted to list the artist genre instead of the id, then you would want to use Includes. In your code, you should put:
#artists = Artist.joins(:artist_profile).where("artist_profiles.genre" => "Rock")
You cannot call scope as Artist.artist_profile, it's an instance method
You can defind scope rock in ArtistProfile model
The result will look like this
class ArtistProfile < ActiveRecord::Base
belongs_to :artist
scope :rock, ->{where(genre: "Rock")}
...
and use it:
#rock_profiles = ArtistProfile.rock
<% #rock_profiles.each do |profile| %>
<li><%= profile.artist_id %></li>
<% end %>

Rails 4: Looping through association

I am having some trouble while looping some association:
#=> member.rb
has_one :academic
#=> academic.rb
belongs_to :member
So far so good. However, when I loop through the association, I get:
undefined method 'each' for #<Academic:0x007fc98b2b7210>
Here's my view (show):
<% if !#member.academic.nil? %>
<% fields_academic = [:major, :second_major, :minor, :second_minor] %>
<h1>Academics</h1>
<% #member.academic.each do |academic| %>
<%= render 'database/shared/display', model_obj: academic, data: academic, fields: fields_academic %>
<% end %>
<% end %>
The code is stuck at the each method.
#member is defined as = Member.find(params[:id])
Any help will be gladly appreciated. Thank you in advance!
According to your code there are no multiple instances of academic related to the given member (it's defined using has_one relation).
The answer is: you cannot loop them.
The correct code for your view should be:
<% if #member.academic.present? %>
<% fields_academic = [:major, :second_major, :minor, :second_minor] %>
<h1>Academics</h1>
<%= render 'database/shared/display', model_obj: #memeber.academic, data: academic, fields: fields_academic %>
<% end %>
<% end %>
If your intention was to have many academics for a memeber, then use has_many instead.
class Member
has_many :academics
end
each should be used on a collection of records( I mean which results in a multiple records). Currently #member.academic will return a single record as it is a has_one relation between member and academic, so you can't loop with that. May be you should change your association to has_many :academics and loop it like <% #member.academics.each do |academic| %>
Method :each iterates over the block according to how this Enumerable was constructed. If no block is given, returns self. Enumerable is a mixin that provides to collections some useful methods. In your example academic is a not Enumerable, but single object. You should use has_many association.

Why do I get 'undefined method `>=' for nil:NilClass' in do loop?

I have the following data architecture:
:tplangroups has_many :tplans
:tplans belongs_to :tplangroups
:tplans has attr_accessible :favrank
I need to get the id of the tplan with the highest favrank from each tplangroup, this routine below is how I'm trying to accomplish that:
<% #tplangroups.each_with_index do |tplangroup, index| %>
<% #highest_favrank = 0 %>
<% #highest_id = tplangroup.tplans[0] %>
<% tplangroup.tplans.each do |tplan| %>
<% if tplan.favrank >= #highest_favrank %>
<% #highest_favrank = tplan.favrank %>
<% #highest_id = tplan.id %>
<% end %>
<% end %>
#does stuff with tplangroup
<% end %>
However, I keep getting the following error:
undefined method `>=' for nil:NilClass
Any ideas? I really have no idea why it's throwing this error. I know that all of the attributes/variables I am referencing have values, I have tested this. I am not sure where I'm going wrong, thanks in advance!
The error message is pretty obvious: Your tplan.favrank is nil, and Ruby can't compare nil using >= to #highest_favrank.
You should remove nils from that array before you try to display it, using compact, or you should figure out why you are getting a nil.
Unfortunately, we can't tell you because you didn't supply code that shows how the values are created, nor is there data we can try to recreate your structure.
Maybe your table has nil values? Maybe your code is not trapping every condition, allowing nils to leak in.

How to display only those Rails records where a specific field is not empty?

I think I'm overlooking something very simple here, but would really appreciate some help to work out what it is.
In the project show view, I'm displaying associated (has_many) tasks in a partial. I only want to display those records where a particular field is not empty. My view code looks like this.
<% for task in #tasks %>
<% unless task.user.notes.empty? %>
<tr>
<td><%= task.user.name %></td>
<td><%= task.user.notes %></td>
</tr>
<% end %>
<% end %>
This is returning undefined method 'notes' for nil:NilClass. This is strange as :notes is definitely in the User model.
The Project controller handling this is contains:
def show
#tasks = #project.tasks.paginate(:page => params[:page])
end
My models look as follows
Project
has_many :tasks
end
Task
belongs_to :project
belongs_to :user
end
User
has_many :tasks
end
What have I missed here? Am I using empty? correctly? Or should I be handling this in the controller? I currently have three partials on the Project show, all using the same Task query. Performance and/or best practice -wise, does it make more sense to have all three partials sourcing data from the same controller query, or to have a sperate query just for this case?
Thanks for any pointers.
The problem was that your User model was undefined when you called task.user.notes.
You can solve this problem as well as improve your overall design by making use of the #delegate macro provided by ActiveSupport in Rails. For example, inside of the Task model, try adding
delegate :notes, :to => :user, :prefix => true, :allow_nil => true
This adds a task.user_notes method to the Task model which will allow you to fetch the User's notes straight from the Task itself. Additionally, because we specified the allow_nil option, if there is no User associated with the Task, the result of the method will be nil instead of an exception.
You can also add this for the name attribute of the User allowing you to call task.user_name from within the view.
Resources:
delegate - http://apidock.com/rails/v3.0.9/Module/delegate
"Law of Demeter" - http://devblog.avdi.org/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/
In the controller
def show
#tasks = #project.tasks.paginate(
:page => params[:page],
:conditions=>["notes is not ? and notes !=?",nil,'']
)
end
OR, not in the controller
Write a helper method to abstract this.
Add a new helper method
def filter_tasks(tasks)
tasks.find(
:all,
:conditions=>["notes is not ? and notes !=?",nil,'']
)
end
And use helper in view
<% for task in filter_tasks(#tasks) %>
<% unless task.user.notes.empty? %>
<tr>
<td><%= task.user.name %></td>
<td><%= task.user.notes %></td>
</tr>
<% end %>
<% end %>

Resources