Improving API calls and responses - ruby-on-rails

TheChamp helped me out to sort out with the array of hashes issue. Thanks. Now I would like to improve on that. It is really messy in the views
Move the code to model, so only calling the instance variable will show the desired result. Like one variable for flight types, the departure times, price structure, etc.
Have the result sorted in the model itself, based on some conditions. Like for price, default to lowest first.
It takes a lot of time to get the API response. What are the various options to cache the response, so results are instantaneous. Also, what values need to be checked to ensure the cache is fresh.
This is my code base. (for ur consideration, a portion of API response - http://jsfiddle.net/PP9N5/)
Model
class Cleartrip
include HTTParty
debug_output $stdout
base_uri "api.staging.cleartrip.com/air/1.0/search"
headers 'X-CT-API-KEY' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
format :xml
def self.get_flight
response = get("?from=DEL&to=BLR&depart-date=2014-08-10&adults=1&children=0&infants=0")
if response.success?
response
else
raise response.message
end
end
Controller
# This does nothing
expires_in 20.minutes, public: true
#flight = Cleartrip.get_flight
Views
<table>
<tbody>
<% #flight["air_search_result"]["onward_solutions"]["solution"].each do |h| %>
<tr>
<td> # This gets the flight info
<% Array.wrap(h["flights"]["flight"]["segments"]["segment"]).each do |segment| %>
<strong><%= segment['airline'] %></strong> <br>
<%= segment['departure_airport'] %> - <%= segment['departure_date_time'] %> ||
<%= segment['arrival_airport'] %> - <%= segment['arrival_date_time'] %> <br>
<% end %>
<hr>
</td>
<td> # this gets the type of fare, Refundable/ Non-refundable
<%= h["pax_pricing_info_list"]["pax_pricing_info"]["pricing_info_list"]["pricing_info"]["fare_type"] %>
</td>
<td> # This gets the fare structure
<% h["pax_pricing_info_list"]["pax_pricing_info"]["pricing_info_list"]["pricing_info"]["pricing_elements"]["pricing_element"].each do |f| %>
<%= f['category']%> - <%= f['amount'] %> <br>
<% end %>
</td>
<td> # The pricing summary
<strong><%=h["pricing_summary"]["total_fare"] %></strong>
</td>
</tr>
<% end %>
</tbody>
</table>
Appreciate general guidelines.
Thanks.

Related

Ruby HABTM association loop

i want to achieve a nested loop without duplicates in a have and belongs to many relationship
i have a model 'campaign' and for each campaign i also have campaign data.
i want to display each campaign with its campaign data in a table. (nested)
#campaigns = current_user.campaigns
<% #campaigns.each do |item| %>
<% i = item.campaign_data %>
<% i.each do |cdata| %>
<%= cdata.date %>
<tr>
<td>
<%= item.name %>
</td>
<td>
<%= cdata.date %>
</td>
<td>
</td>
</tr>
<% end %>
<% end %>
my problem is that my campaigns get duplicated.
I want to achieve something like this:
Each campaign is listed in the table with its corresponding campaign_data directly below it, and if no campaign_data is left the next loop begins with the next campaign - is this possible?
best regard
You might be getting duplicated campaigns as you are using <%= item.name %> inside the <% i.each do |cdata| %> loop. So, if one campaign has 4 campaign_datas you will see the campaign name 4 times.
You should use naming conventions properly, if the campaign has many data campaign_data then you should specify so in association i.e. has_many :campaign_datas
Also, the Following code should be in the controller
#campaigns = current_user.campaigns.include(:campaign_datas)
Note:- I used include to avoid n + 1, please read here.
In view
<% for campaign in #campaigns %>
<% next if #campaigns.campaign_datas.blank? %>
<tr>
<td><%= item.name %></td>
</tr>
<% for campaign_data in #campaigns.campaign_datas %>
<tr>
<td><%= campaign_data.date %></td>
</tr>
<% end %>
<% end %>
Note:-
<% next if #campaigns.campaign_datas.blank? %> line is used to skip the campaign if it has no campaign data.

Error when trying to link to patient profile

I'm getting an error when trying to link_to a patient profile when a provider views his patients list. I have no problem displaying all the names of the patients that belong to the provider but when trying to link to the patient profile I get an undefined method 'id'.
So the way it works is, patients can search for providers and add them to the List model. On the provider side, I just list out all the patients that added that specific provider. Here is my erb code below,
<div class="body">
<div class="body">
<% if #active_patients.count > 0 %>
<table>
<thead>
<tr>
<th>Patient Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div class="no-records">
<%= image_tag "icon-no-records", class: "image" %>
<div class="text">You have no patients.</div>
</div><!--no-records-->
<% end %>
</div><!--body-->
</div>
Here is my List model,
class List < ApplicationRecord
belongs_to :membershipable, :polymorphic => true
belongs_to :provider
def patient
membershipable_type=='Patient' ? membershipable : nil
end
def provider_user
patient.try(:user)
end
end
Also here's the error message ->
Let Rails do the work of building the path. Each ActiveRecord model has a to_param method which decides how the instance will be encoded in an URL. By default it returns the model id but it could also be a slug based on the title or another property of the model.
Calling your helper like patient_path(patient) should do the trick.
Additionally, in your current code, you're referring to the previously unused #patient variable, even though it looks like you want to refer to list.patient instead.
Here:
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
you have the variable list available to you. It appears that you get the patient by doing list.patient, as you do here:
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
But, then you try to use a variable called #patient, here:
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> .
when you don't have the variable #patient. So, you get your nil error.
Instead, it seems you should do:
<%= link_to patient_path(id: list.patient.id), class: "btn" do %>View<% end %> .
Or, as milgner points out, you could simply do:
<%= link_to patient_path(list.patient), class: "btn" do %>View<% end %> .
Also, you might want to look into the Law of Demeter, which you violate (IMO) when you do:
list.patient.role.user.first_name

rails else statement repeating multiple times

So i have this in my view
<% #events.each do |event| %>
<% if event.eventcomplete %>
<% else %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
This is on my search results page,
However what im wanting if there is no eventcomplete, Just display one No events found,
At the moment i'm gettting around 100 events found but, None of them are complete. So i'm getting around 100 "No Events could be found"
Thanks for any help
Sam
I don't know what your code looks like, but something smells wrong to me that you're filtering by eventcomplete in your view both for determining which rows to display and for whether or not to show your "No results" message. Presumably you will later want to do other things using this collection (like pagination), so I'd suggest filtering the collection in the controller:
# controller code
#in_progress_events = #events.where(eventcomplete: false)
Once the collection is being properly filtered before it hits the view, check out the points in this answer for tips on display: Rails: An elegant way to display a message when there are no elements in database
Your code is missing an <% end %> tag.
<% #events.each do |event| %>
<% if event.eventcomplete %>
[insert view code to show if event.eventcomplete is true]
<% else %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
<% end %>
Actually the code is doing exactly what it should do,
your html Block was defined in your each block, this is why it got raised 100 times.
I just fixed it with Helper Variables, but it is just a workaround
You should make use of more static methods in your models, just define it
Please make sure your business logic holds place in your models:
Fat models, Thin Controllers/Views
this should work
<% #there_is_no_eventcomplete = false %>
<% #events.each do |event| %>
<% if event.eventcomplete %>
#there_is_no_eventcomplete = true
<% end %>
<% end %>
<% if #there_is_no_eventcomplete == false %>
<tr>
<td colspan="7">
<p>
No Events could be found.
</p>
</td>
</tr>
<% end %>
You want to use a scope on your model which you can then call in the controller. I'm not sure how you've set up your model or how you determine if an event is completed, so lets assume you have a boolean attribute completed on your model:
event.rb
class Event
def self.completed
where(complete: false)
end
end
controller
#events = Event.completed
view
<% unless #events.nil?
<% #events.each do |event|%>
// your code
<% end %>
<% else %>
// your code
<% end %>

Fulfillment_created_at ror3 shopify api error

How to use arrays and get order date?
I get the date when the order was shipped.( order.line_items_line_item.fulfillment.created_at)
Help plz thx
I'm doing this
controller
#order = ShopifyAPI::Order.find(:all)
views -work
<% #order.each do |order| %>
<span class="highlight"><%= order.customer.email %></span>
<%= order.line_items.each do |line_item| %>
<span class="note"><% line_item.title %></span>
<% end %>
<% end %>
</ul>
<% end %>
views -don't work
<% #order.each do |order| %>
<%= order.line_items.each do |line_item| %>
<span class="note"><% line_item.created_at %></span>
<% end %>
<% end %>
</ul>
<% end %>
views -don't work
<% if #order.line_items %>
<% #order.line_items.each do |line_item| %>
<tr>
<td><%= line_item.created_at %></td>
</tr>
<% end %>
<% end %>
I’m not sure I understand your question, but if you’re looking for when an order was created, you want
#order.created_at
Take a look at the JSON responses in http://api.shopify.com/order.html or do a
puts #order.inspect
to see what kind of data comes back from an Order API call.
Line items don't have a created_at field, they're properties of the order in the same way that adress lines are part of an address.
There's a separate object that deals with order fulfillments. Here's the page on the docs: http://api.shopify.com/fulfillment.html
Using the ruby gem you can just call order.fulfillments to get an array of fulfillments. Then you can loop over those to see when the line items were fulfilled.

Rails yield - content_for problem

I have the following requirement.
Ex: There is a transaction table where it has columns say, transaction_name and amount. I want to loop through the transactions and display their details (transaction_name and amount) and finally I want to display the total amount (sum of all the amounts) in the head (before the loop) section of my page. (Think about it as a summary display)
Example page structure would be like
Sum of all the transactions - 200
transaction amount
trn1 100
trn2 50
trn3 50
And I tried to use yield and content_for tag but no luck.
my code is as follows (i'm calling inside my erb file.)
<%= yield :transaction_summary %>
<table>
<% total_amount = 0%>
<%for transaction in #transactions%>
<tr>
<td><%= transaction.transaction_name %></td>
<td><%= transaction.amount %></td>
<% total_amount += transaction.amount %>
</tr>
<%end%>
</table>
<% content_for :transaction_summary do %>
<h1>
Sum of all the transactions - <%= total_amount %>
</h1>
<% end %>
And
I'm using with inside a view (not inside a layout)
I'm using rails 2.2.2
Please help me and let me know if there is a better way
thanks in advance
cheers
sameera
EDIT:
Actually what I want to do is , Display some details before a particular loop where those details can be collected after the loop
Ex: If i have an array of transaction objects, I want to show a count of pass and failed transactions before the transactions loop in my view
thanks
In other cases where you really need to reuse content_for, the following may be useful.
In Rails 4, you can pass :flush => true as an option to content_for:
<% content_for :example, flush: true do %>
<h1>Deletes previous content</h1>
<% end %>
In Rails 3.1.1 (approx) you can delete the content from the view_flow when you yield by defining and using the following (eg in application_helper):
def yield_and_flush!(content_key)
view_flow.content.delete(content_key)
end
I think you have the wrong idea about content_for and yield. :) http://guides.rubyonrails.org/layouts_and_rendering.html
<h1>
<%= #transactions.collect(&:amount).sum -%>
</h1>
<table>
<%for transaction in #transactions%>
<tr>
<td><%= transaction.transaction_name %></td>
<td><%= transaction.amount %></td>
</tr>
<%end%>
</table>
edit -
Regarding collecting data, I suggest you put them in helper methods:
#transactions_helper.rb
def transactions_total transactions
#transactions_total ||= #transactions.collect(&:amount).sum
end
def passed_transactions transactions
#passed_transactions ||= #transactions.collect{|transaction| transaction.passed == true}
end
def failed_transactions transactions
#failed_transactions ||= transactions - passed_transactions(transactions)
end
Just noticed your comment to theTRON. The whole dry principle doesn't really apply to executing tiny logic such as looping through a array.
I would write a helper method which calculates the total separately, perhaps something along the lines of:
# app/helpers/transactions_helper.rb
def calculate_total(transactions)
total = 0
transactions.each {|transaction| total += transaction.amount}
total
end
Then you can display it in your view wherever you like, with:
<%= calculate_total(#transactions) %>
In Rails 3 you can yield after content_for; so your code will become:
<% content_for :transaction_table do %>
<table>
<% total_amount = 0%>
<% for transaction in #transactions do %>
<tr>
<td><%= transaction.transaction_name %></td>
<td><%= transaction.amount %></td>
<% total_amount += transaction.amount %>
</tr>
<%end%>
</table>
<% content_for :transaction_summary do %>
<h1>
Sum of all the transactions - <%= total_amount %>
</h1>
<% end %>
<% end %> <!- End content_for :transaction_table -->
<%= yield :transaction_summary %>
<%= yield :transaction_table %>
Note:
<% content_for :transaction_summary do %>
doesn't have to be inside of
<% content_for :transaction_table do %>
, but for some more complex cases it could.

Resources