Writing a conditional within an each block - ruby-on-rails

I have an array of Twilio Recording SIDs that I'm using to generate links to a users call recording. When I use them in a table and the SID is empty, I'd like to print "No Recording".
<tr>
<% #empty_check.each do |rec| %>
<% if rec.empty? %>
<td><%= "No Recording" %></td>
<% else %>
<td><%=link_to 'listen', "https://api.twilio.com/2010-04-01/Accounts/{#account_sid}/Recordings/" + rec, :target => "_blank"%></td>
<% end %>
<% end %>
</tr>
Even though I know one of the values in that given array is empty, it still prints the else code.
Furthermore, when I do something like this
#empty_check.each {|m| print m.empty?}
falsefalsefalsefalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalse
I see a true value.
What am I missing in that conditional above that its not recognizing the empty value?
**Update
The #empty_check example was me trying to isolate what I thought was the problem and debugging.
Here is the actual controller code:
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#calls = #subaccount.calls
#callslist = #calls.list({:page_size => #page_size, :page => #page, :"start_time>" => #start_date, :"start_time<" => #end_date})
#callsids = #callslist.map {|m| m.parent_call_sid}.compact
And the actual view code:
<% #callsids.each do |c| %>
<tr>
<% #call = #calls.get(c) %>
<td><%= Date.parse(#call.date_created).strftime("%m/%d/%y") %></td>
<td><%= Time.parse(#call.start_time).strftime("%I:%M%P") %></td>
<td><%= #call.from %></td>
<td><%= #call.to %></td>
<td><%= ChronicDuration.output(#call.duration.to_i, :format => :short) %></td>
<% #recording = #recordings.get(c) %>
<% #calls.get(#call.sid).recordings.list.each do |rec| %>
<% if rec.sid.empty? %>
<td><%= "No Recording" %></td>
<% else %>
<td><%=link_to 'listen', "https://api.twilio.com/2010-04-01/Accounts/#{#account_sid}/Recordings/" + rec.sid, :target => "_blank"%></td>
<% end %>
<% end %>
</tr>
<% end %>

Are you sure you are accessing the same variable in your print test and the main code block? Try outputting the value of #empty_check within the template just before the test you are interested in (optionally in a comment).
Update to respond to updated question:
<% #calls.get(#call.sid).recordings.list.each do |rec| %>
Isn't that line the issue? If the call has no recordings the whole block will be skipped so it will never write "No recordings.". I'm making guesses about the Twilio API but are you sure that recording objects are returned that have a sid value that returns true for .empty?
Couldn't the above line be simplified to:
<% #calls.get(c).recordings.list.each do |rec| %>
or even:
<% #call.recordings.list.each do |rec| %>
And don't you want to (and try this with the API first) do the if xxx.empty? outside of the each in this case.
<% reclist = #call.recordings.list %>
<% if reclist.empty? %>
<td><%= "No Recording" %></td>
<% else %>
<% reclist.each do |rec| %>
<td><%=link_to 'listen', "https://api.twilio.com/2010-04-01/Accounts/#{#account_sid}/Recordings/" + rec.sid, :target => "_blank"%></td>
<% end %>
<% end %>
Simplified version added after answer accepted. Pulls the tag outside the if (and the each) so that all the links go together in the same table cell if there are multiple recordings for the call.
<% reclist = #call.recordings.list %>
<td>
<% if reclist.empty? %>
No Recording
<% else %>
<% reclist.each do |rec| %>
<%=link_to 'listen', "https://api.twilio.com/2010-04-01/Accounts/#{#account_sid}/Recordings/" + rec.sid, :target => "_blank"%>
<% end %>
<% end %>
</td>

Related

How to iterate over multiple hash values with Espinita in Rails

I am using Espinita to keep track of changes to my model and have multiple attributes that I would like to display in the view.
I haven't figured out how to iterate over each value without using an || in the iterator. I want to get the attribute name, the changed value and the date.
This is show.html:
<% #contract.contract_information.history_from_audits_for([:contract_title, :assigned_to, :action_requested..:deadline]).each do |changes| %>
<tr>
<%= changes[:contract_title] || changes[:assigned_to] || changes[:deadline] %>
<%= changes[:changed_at].strftime("%m/%d/%Y") %>
</tr>
<% end %>
How do I iterate over each audit without referencing the attribute name?
UPDATE
After making the recommended changes. I now receive the attributes/values in array form. Is there a way to beautify the results in the view?
Output
11/20/2019 [:contract_stage, ""] [:action_requested, ""] [:reason_for_contract_request, ""] [:existing_or_returning, ""] [:background_check_status, ""] [:priority, ""] [:deadline_date, Wed, 20 Nov 2019] [:commencement_date, Wed, 20 Nov 2019] davie200
View
<% #contract.contract_information.history_from_audits_for([:contract_stage, :action_requested, :reason_for_contract_request, :deadline_date, :commencement_date, :existing_or_returning, :background_check_status, :priority]).each do |audit| %>
<% audit.except(:changed_at).each do |attribute, value| %>
<tr>
<td><%= audit[:changed_at].strftime("%m/%d/%Y") %></td>
<td>
<% value.each do |val| %>
<%= val %>
<% end %>
</td>
<td><%= #contract.contract_information.audits.last.user.username %></td>
</tr>
<% end %>
<% end %>
If you have an opportunity to update Espinita in your project, I would recommend you to do it because they changed the format of the hash returned by history_from_audits_for.
In the newer version, you will have something like this in the "History and Restoration" documentation:
model.history_from_audits_for([:name, :settings])
=> [{:changes=>{:name=>"Baz", :settings=>""}, :changed_at=>2015-05-03 15:33:58 -0700},
{:changes=>{:name=>"Arglebargle", :settings=>"IHOP"}, :changed_at=>2015-03-24 15:33:58 -0700},
{:changes=>{:name=>"Walrus"}, :changed_at=>2014-05-13 15:33:58 -0700}]
and your iteration will be as simple as:
<% #contract.contract_information.history_from_audits_for([:contract_title, :assigned_to, :deadline]).each do |audit| %>
<% audit[:changes].each do |attribute, value| %>
<tr>
<%= value %>
<%= audit[:changed_at].strftime("%m/%d/%Y") %>
</tr>
<% end %>
<% end %>
But, if you don't have a chance and you are using Rails > 3.0.0 consider the following approach:
<% #contract.contract_information.history_from_audits_for([:contract_title, :assigned_to, :deadline]).each do |audit| %>
<% audit.except(:changed_at).each do |attribute, value| %>
<tr>
<%= value %>
<%= audit[:changed_at].strftime("%m/%d/%Y") %>
</tr>
<% end %>
<% end %>
using Hash#except.
Retrieve User from Audit
<%= #contract.contract_information.audits.last.user.username %>

Create/New DB record for each generated set of fields

I have got a problem with saving multiple record.
This script wil load a list of instruments that belong to a department through a join table.
This form will make a new record for another join table, the problem is when I'f got 4 instruments it only will save the last instrument.
Image generated list
Can anybody help me out to solve this problem or point me into the right direction ??
<%= form_for(:joindaylisting) do |j| %>
<% #instrumentslist.each do |instrument| %>
<tr class="<%= cycle('odd', 'even') %>">
<td>
<% j.label(:instrument_id, "#{instrument.name}") %>
<%= link_to("#{instrument.name}", {:controller => 'instruments', :action => 'show_instruction', :instrument_id => instrument.id}, :onclick=>"window.open('height=670, width=675');return false;") %>
</td>
<%= j.hidden_field(:instrument_id, :value => instrument.id) %>
<td></td>
<% j.label(:ammountdesinfection, "") %>
<td><%= j.text_field(:ammountdesinfection) %></td>
<% j.label(:ammountinstruments, "") %>
<td><%= j.text_field(:ammountinstruments) %></td>
<% j.label(:ammountrelease, "") %>
<td><%= j.text_field(:ammountrelease) %></td>
<% j.label(:notes, "") %>
<td><%= j.text_area(:notes) %></td>
</tr>
<% j.label(:department_id) %>
<%= j.hidden_field(:department_id, :value => #department.id) %>
<% end %>
<% end %>
Only the last one is saved because the fields have the same name and the last one overrides all other values. See the params you are getting on the receiving controller.
You probably want/need to configure departments to accepts_nested_attributes_for :instruments and a form for the department object with fields_for: instruments. I've highlighted keywords that my help you get the information you want, the Rails Guides is a good place to start.

nil values return error undefined method `car_number' for nil:NilClass even if I check them with .nil?

when I replace the nil values manually with data, I get no errors.
<% #visits.each do |f| %>
<tr>
<td><%=f.owner.car_number unless f.owner.car_number.nil?%></td>
<td><%=f.owner.car_type unless f.owner.car_type.nil?%></td>
<td><%=f.owner.car_year unless f.owner.car_year.nil?%></td>
<td><%=f.owner.first_name unless f.owner.first_name.nil?%> <%=f.owner.last_name unless f.owner.last_name.nil?%></td>
<td><%=f.owner.phone unless f.owner.phone.nil?%></td>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
</tr>
Better you need to add validation to stop entry of nil on owner in visit or the model where the association has defined to owner with visit
here I am consider here visit model has one owner
class Visit < ActiveRecord::Base
has_one :owner
validates :owner, presence: true
end
Or another solution using try
<% #visits.each do |f| %>
<tr>
<% ["car_number", "car_type","car_year", "first_name", "last_name", "phone"].each do |meth| %>
<td><%= f.try(:owner).send(meth) %></td>
<% end %>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
</tr>
<% end %>
I am assuming #visits contains valid list of objects.
Now, lets read the error carefully:
undefined method `car_number' for nil:NilClass
Where are you applying car_number? Hint: to object f.owner. Meaning f.owner is nil , so f.owner.car_number.nil will still throw an error.
Tweak them to:
<%= f.owner.car_number if f.owner %>
Or better:
<% #visits.each do |f| %>
<tr>
<% if f.owner %>
<td><%=f.owner.car_number %></td>
<td><%=f.owner.car_type %></td>
<td><%=f.owner.car_year %></td>
<td><%=f.owner.first_name %> <%=f.owner.last_name %></td>
<td><%=f.owner.phone %></td>
<td style="direction:ltr"><%=f.created_at.strftime("%d/%m/%Y")%></td>
<td>XX NOTES </td>
<% end %>
</tr>
Check the first iteration.
Instead of :
unless f.owner.car_number.nil?
Use..
unless f.owner.nil?
Or you can check first before iterating, like:
<% unless #visits.nil? %>
<% #visits.each do |f| %>
....
<% end %>
<% end %>

Gracefully jumping to next record - ActiveRecord

Rails 3.2
I have the following in my view:
<% #organizations.each do |o| %>
<% organization = Organization.find(o.organization_id) %>
<% if organization == nil %>
<% next %>
<% end %>
<tr>
<td><%= o.org_name %></td>
<td><%= number_to_currency(o.revenue, :precision => 0) %></td>
<td><%= o.rank %></td>
</tr>
<% end %>
I was under the impression that if organization is not found, execution would jump to the next record. Instead, I am getting the "something went wrong".
Looking through the log file, one of the organization_id is not found in the organizations table, and that's what's triggering the error.
Why isn't execution jumping to the next record?
Temporary Solution: I changed
<% organization = Organization.find(o.organization_id) %>
To:
<% organization = Organization.find_by_id(o.organization_id) %>
and that gives me a nil when it does not find anything. If it's nil, the execution skips to the next record
According to http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find, Organization.find(o.organization_id) will raise an ActiveRecord::RecordNotFound for the id that does not exist in the table.
Addendum:
Try something like the following:
<% ids = #organizations.map(&:organization_id) %>
<% organizations = Organization.where(id: ids) %>
<% organizations.each do |o| %>
<tr>
<td><%= o.org_name %></td>
<td><%= number_to_currency(o.revenue, :precision => 0) %></td>
<td><%= o.rank %></td>
</tr>
<% end %>
With this method, you'll fetch all the organizations with 1 query from the DB as opposed to 1 for every organization.

serial number with pagination rails

I am using pagination for my index page where I list all the users information like name, email etc. In the table I want to display the serial number in the order [1,2,3...]. If I user the user_id and if I delete the user the number will be missing out of sequence. I use the following code in my view
<% #user.each_with_index do |d, i| %>
<tr>
<td><%= i+1 %></td>
<% if d.profile.present? %>
<td><%= link_to d.profile.first_name+ " "+d.profile.last_name, posts_individualpostlink_path(:id => d.id) %> </td>
<% else %>
<td><%= "No Profile" %></td>
<% end %>
<td><%= d.email %></td>
<% if d.profile.present? %>
<td><%= d.profile.date_of_birth %> </td>
<% else %>
<td><%= "No Profile" %></td>
<% end %>
</tr>
<% end %>
</table>
<%= will_paginate #user %>
when I am going to the second page again the serial number starts with [1,2,....]. Per Page if i am giving 10 users, the second page should show [11, 12, 13,..... in the table.
Can anyone help me to do this. Thanks
Try with
<%
count = ((params[:page] || 1).to_i - 1) * 10
#user.each_with_index do |d, i| %>
<tr>
<td><%= count + i %></td>
Before answering question, small emotional note: stop using single letter variables in Your code. It makes it completely unreadable.
Why not use <% #user.each_with_index do |user, idx| %> ? Now in You code block it's easy to understand that You always refer to user.
Now the answer. Will paginate add page parameter to the paging links. So in You controller You should be able to do this:
#page = params[:page] || 1
After that use it to calculate correct number in Your view:
<td><%= (#page - 1) * number_of_items_on_page + i+1 %></td>

Resources