Undefined method each Ruby - ruby-on-rails

The run down. A person can have many bids, this particular person only has one bid.
In my index action I have #bids = Bid.find_by_person_id(params[:person_id])
in my view I do
<% #bids.each do |bid| %>
<%= bid.bid_amount %>
<% end %>
I am getting NoMethodError: undefined method each' for #<Bid:0x007f988a346f00> when visting the index view for person bids.
Is this because this person only has one bid? I feel thats not the case, but other than that im at a loss..

find_by returns the first item. I think you are looking for
Bid.where(person_id: params[:person_id])

Austio's answer is correct.
However, why are you calling the Bid model directly?...
A person can have many bids
You're obviously constructing data from the person model, so why not call the following:
#person = Person.find params[:person_id]
#bids = #person.bids #-> bids belong to #person
This will build the collection without calling where.
Of course, your method only uses a single db query. But even still, the above is much more intuitive.
--
As an aside, you'll also want to use a conditional before your loop:
<% if #bids.any? %>
<% #bids.each.... %>
<% end %>
Having one bid is fine, but having none will cause the loop to spit out an error. The above resolves that issue.

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)

Rails - counting instances where boolean is true

I am trying to make an app with Rails 4.
I have a project model and a project invitations model.
Projects has many project invitations
Project invitations belong to projects
In my project show, Im trying to count how many invitations have been sent and how many have been accepted.
The first part works fine. For the acceptances, I have an attribute in my project_invitation table called :student_accepted. If that is true, I want to count the record.
<%= #project.project_invitations.size %>
<% if #project.project_invitations.student_accepted == true %>
<%= #project.project_invitations.size %>
<% else %>
'No'
<% end %>
It gives this error:
undefined method `student_accepted' for #<ActiveRecord::Associations::CollectionProxy []>
I have also tried:
<% if project.project_invitations.student_accepted == true %>
<%= project.project_invitations.size %>
It gives this error:
undefined local variable or method `project' for #<#<Class:0x007fc01d9dcbe8>:0x007fc01de04248>
Im struggling to understand how to reference attributes though associated models. I have read several books but they all assume background knowledge. I've had helpful input on related questions (below), but still not grasping the concept.
http://stackoverflow.com/questions/32916133/rails-how-to-show-attribute-of-an-associated-model
http://stackoverflow.com/questions/32898541/rails-how-to-show-attributes-from-a-parent-object
Can anyone see what I've done wrong?
You can find the number of invitations that students have accepted with:
#project.project_invitations.where(student_accepted: true).count
Rails's Active Record Query Interface guide explains how that works.
The reason you received the undefined method 'student_accepted' for #<ActiveRecord::Associations::CollectionProxy []> error is because you were calling student_accepted on a ActiveRecord::Associations::CollectionProxy, which is an object rails creates to define a collection of records.
If you wanted to iterate over that collection you could do:
<% #project.project_invitations.each do |invitation| %>
# here you can call `invitation.student_accepted`
<% end %>
This is necessary because a project has many invitations.
#project.project_invitations gives you an array and Array class does not have the method student_accepted (while each item in the array has this method).
You can use #project.project_invitations.select{|item| item.student_accepted == true}.present? as the condition.

Ruby on Rails each iteration error when one record

I am stuck on what seems should have a very simple solution, but I can not find anything that will work! I am iterating results from a table on the index page (which returns a list of states). This works without any problems when multiple records are returned. However, when a single record is returned, I get an error: undefined method 'each' for #
I know it is causing the error when only one record is returned, but I can not find any documentation on how to handle this, especially in the case that 1 or 0 records could be returned.
Code in controller:
#states = State.find(params[:id])
Code in index page:
<ul>
<% #states.each do |state| %>
<li>
<%= state.state_name %>
</li>
<% end %>
</ul>
Because you're using find, when you send multiple ids in the params, multiple records are matched; when you send a single id, a single instance is returned.
To ensure that each time, you get an ActiveRecord::Relation object that you can call each on, change your controller code to the following:
#states = State.where(id: params[:id]) # index action
You mentioned that it is the index view, so the above change should solve your problem.
If it's the show view, then you need to stick with find and change your view to display only one state.
You need to check if it responds to .each, which is the prime given for knowing if something implements the enumerable module.
if #states.respond_to?(:each)
# iteration goes here
else
# single handling goes here
Ofcourse you can also use the .where option in your query which returns always a collection
#states = State.where(id: params[:id])
Scenario 1:-
When record is queried in controller as:
#states = State.find(params[:id])
Then in view it should be like that:
<p><%= #states.state_name %></p>
Scenario 2:-
When record is queried in controller as:
#states = State.all
Then in view it should be like that:
<ul>
<% #states.each do |state| %>
<li>
<%= state.state_name %>
</li>
<% end %>
</ul>
Note:- In first scenario it is only one object but in second scenario it is a collection of object or a array of object. And only array are iterated.

Rails count and display

I am new to rails. I have three models tickets, tags and comments with relationships and it is working fine.
I want to display the total number of tickets in my ticket index view, but I don't know why...
I think that this is a really easy answer for you guys...
<%= ticket.count %> says undefined method.
Can you help me or do you need more informations? Thank you!
Assuming that in TicketController you have something like this:
def index
#tickets = Ticket.all
end
In your index view, to display the count of tickets, do as follows:
<%= #tickets.count %>
<% #tickets.each do |ticket| %>
.....
<% end %>
Call the count method on the collection object #ticket(Array of type ActiveRecord::Relation) and not on the ticket which is an instance of Ticket class.
In controller load ticket count
#ticket_count = Ticket.all.count
in view
<%= #ticket_count %>
ticket.count will not work because ticket is object of Ticket class which does not have count method defined . you can define count method for ticket and compute total of all Ticket then it will surely work.
I suggest to use Ticket.all.count which will return total no of tickets

Complex form with Rails

I have a form where I'd like to create a parent record and a child record at the same time. For a simple example let's say its a Company with the first Employee.
in my controller I do something like:
def new
#company = Company.new
#company.employees.new
end
and in my view this:
<%= form_for(#company) do |form| %>
<div>
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<%= form.fields_for :employees do |employee_form| %>
<div>
<%= employee_form.label :name %>
<%= employee_form.text_field :name %>
</div>
<% end %>
<% end %>
and back in my controller again:
def create
#company = Company.new(params[:company])
#company.employees << Employee.new(params[:company][:employees_attributes]["0"])
# save stuff
end
Question 1:
I couldn't get the employee collection on the company to be populated with the single employee created in the form. When I looked at the params I found the [:employees_attributes]["0"] stuff.
What I have works, but is there a cleaner way to do this?
Question 2:
If the validation doesn't pass for the employee I get a generic "Employees is invalid" instead of the Name required validator message. I get I am calling save on the collection and rails is doing its best to bubble a validation error up, but is there a cleaner way to do this so I can get the errors specific to the employee?
In Short
How can I clean this up so the related models are created automatically from the params, and so that I get the validation messages for a single employee.
Thanks for looking.
1) fields_for arranges for the child objects attributes to be nested inside the parent objects attributes in the params hash that gets sent back to the controller action. To get Rails to automatically update the child objects tell the parent model to accept nested attributes using the accepts_nested_attributes_for declaration.
2) There is an errors object for every ActiveRecord object. Loop through the errors list and display the messages.
Best way to achieve this is to create a partial and a view helper method that will take render the errors for you. then replace the generated errors messages in the forms with a call to your render_error_messages method. You have all the code to do this already in the generated forms. You just need to refactor that code into a partial, create the helper - which should accept an array of model names as a parameter then do what you want with the info. Wither render a partial for each model or render a partial that will deal with child objects as well as the parent object. Totally your call.
3) Change your new action to build rather that create a new child object so instead of
def new
#company = Company.new
#company.employees.new
end
do this
def new
#company = Company.new
#company.employees.build
end
4) Watch those Railscasts to see how accepts_nested_attributes works
http://railscasts.com/episodes/196-nested-model-form-part-1
and
http://railscasts.com/episodes/197-nested-model-form-part-2
Update
So how does the above information leave you in relation to your questions.
1) What I have works, but is there a cleaner way to do this?
You've fixed the new action as per point 3 above right? Now your create action can look like this
def create
#company = Company.new(params[:company])
# save stuff
end
Which is much cleaner as it has reverted to the original generated create action.
You may not think that's much of an update and therefore not that much cleaner. Well in isolation you'd be right. But consider that you could add as many relationships as you like ad add as many fields_for declarations as you like nd you could turn the user -> employee relationship into a has_many (I know that you wouldn't). You could do all that and your create and update actions stay EXACTLY the same and that's why it's cleaner.
2) is there a cleaner way to do this so I can get the errors specific to the employee?
Given my response in point 2 above you know that there is an errors object on the employee object as well as on the user object right? You also know now that you can loop through that errors object to get the messages right?
So you could do this
<% if #user.employee.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.employee.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.employee.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
At the risk of repeating myself I'll just say that you should refactor your error messages view code into a partial that will take any object as a parameter then you can call it from any view thus enabling you to change the styling and the functionality for all your forms.
Hope that's clearer

Resources