In my rails app I have iterate through discussions as below code.
<% #di.each do |d| %>
//my code goes here
<% end %>
This is my application_controller.rb
def load_feed_discussions(url:)
#c = session[:council] || ''
res = RestClient.get url, api_token_hash
#di = (JSON.parse(res.body) if res.code == 200)
rescue RestClient::ExceptionWithResponse
#di = nil
end
This is my discussion_controller.rb
def index
# Load Discussions
load_feed_discussions(url: api_version_root+'/discussions/all?council='+session[:council])
end
I want to sort discussion according to the 'updated_date'. How can I do this?
EDIT : here some sample data for #di
{"id"=>"609b966e-99f1-4606-ab8d-3c99ebb8dc9c", "question"=>"tttest body", "user_id"=>"609b966e-99f1-4606-ab8d-3c99ebb8dc9c", "score_model"=>nil, "council_id"=>"98bc626f-fbef-4b63-9cc9-4f1f2bad6b06", "created_at"=>"2020-04-22T11:41:51.503Z", "updated_date"=>"2020-06-29T03:06:49.155Z", "is_anonymous"=>false, "company_id"=>nil, "topics"=>nil, "was_edited"=>nil, "startup_id"=>nil, "recipients"=>[], "visibility_team"=>"default", "title_line"=>"tttest sub", "title"=>"Engineer", "company_logo"=>nil}
It depends heavily on what's #di; if it's an array of objects that respond to updated_date then you can use Enumerable#sort_by:
<% #di.sort_by(&:updated_date).each do |d| %>
...
<% end %>
If it's an ActiveRecord_Relation instance, you can use ActiveRecord::QueryMethods#order:
<% #di.order(:updated_date).each do |d| %>
...
<% end %>
The answer was none of the proposed ones, but sort_by { |e| e['updated_at'] }.reverse.
Assuming that #di is an array of responses, you can sort in descending date as follows in the controller...
def load_feed_discussions(url:)
#c = session[:council] || ''
res = RestClient.get url, api_token_hash
#di = [] # initialize to empty array in case of res.code != 200 or exception
#di = JSON.parse(res.body) if res.code == 200
rescue RestClient::ExceptionWithResponse
else
#di = #di.sort_by{|discussion| discussion['updated_date']}.reverse
end
It's not considered good practice to sort data in the view.
Related
I was asked to fetch the Pokemon API from Ruby on Rails. But I'm struggling because I have too much logic in the controller, which is not recommended. Where and how can I make the call so I have less logic inside my controller. I have this:
def index
pokemons = []
response = HTTParty.get("https://pokeapi.co/api/v2/pokemon?limit=6&offset=1")
response = JSON.parse(response.body)
response.each do |k, value|
if k == "results"
value.each do |key, val|
response = HTTParty.get(key["url"])
response = JSON.parse(response.body)
pokemons.push(response)
end
end
end
#poke_json = pokemons.map do |poke|
Pokemon.new(img:poke['sprites']['other']['dream_world']["front_default"], name: poke['forms'][0]['name'], weight: poke['weight'], poke_type: poke['types'][0]['type']['name'], poke_ability: poke['abilities'][0]['ability']['name'], poke_id: poke['id'])
end
render json: { pokemons: #poke_json }
end ```
As a first step you could extract the API client depending code into a class on its own:
# in app/models/pokemon_api.rb
class PokemonApi
def self.to_json
pokemons = []
response = HTTParty.get("https://pokeapi.co/api/v2/pokemon?limit=6&offset=1")
response = JSON.parse(response.body)
response.each do |k, value|
if k == "results"
value.each do |key, val|
response = HTTParty.get(key["url"])
response = JSON.parse(response.body)
pokemons.push(response)
end
end
end
pokemons.map do |poke|
Pokemon.new(
img:poke['sprites']['other']['dream_world']["front_default"],
name: poke['forms'][0]['name'], weight: poke['weight'],
poke_type: poke['types'][0]['type']['name'],
poke_ability: poke['abilities'][0]['ability']['name'],
poke_id: poke['id']
)
end
end
end
and then just call that method in your controller
def index
render json: { pokemons: PokemonApi.to_json }
end
I'm trying to get data out of this datamapper object and then putting it into a loop and getting the data out of the object that way, but it doesn't seem to be working, this is the code I have:
#user = User.get(session[:user])
#polls = []
polls = Poll.all(:user_id => #user)
polls.each do |poll|
pollname << poll.name
#polls << pollname
end
and in my erb file:
<% #polls.each do |poll| %>
<p><%= poll %></p>
<% end %>
I thinks what you want is:
#user = User.get(session[:user])
#polls = Poll.where(user_id: #user.id).all.collect { |p| p.name }
In my Rails app I am doing two things - comparing an Active Record result to an array built from a JSON response from external API.
First step is checking which results are in the database and not in the API and I do this as follows:
def self.orphaned_in_db
db_numbers = self.find(:all).map{|x| x.number}
listed_numbers = self.all_telco.map{|x| x.number} # gets JSON from API
orphaned_numbers = db_numbers - listed_numbers
orphaned_results = self.find_all_by_number(orphaned_numbers)
return orphaned_results
end
This is the new version as the old version was taking far too long after the result sets of each increased dramatically in the last few weeks.
# def self.orphaned_in_db
# old version
# db_numbers = self.find(:all)
# listed_numbers = self.all_telco
# orphaned_numbers = []
# db_numbers.each do |db|
# scan = listed_numbers.select{ |l| l.number == db.number}
# orphaned_numbers.push(db) if scan.empty?
# end
# return orphaned_numbers
# end
I am now finding it tricky to do the opposite of this - find numbers in the API array that are not in my database table.
def self.orphaned_in_telco
db_numbers = self.find(:all).map{|x| x.number}
all_numbers = self.all_telco
listed_numbers = all_numbers.map{|x| x.number}
orphaned_numbers = listed_numbers - db_numbers
orphaned_results = # how to filter all_numbers by orphaned_numbers?
return oprhaned_results
end
Again, the old way that now fails to work because it's so slow:
# def self.orphaned_in_telco
# original, inefficient way
# db_numbers = self.find(:all)
# listed_numbers = self.all_telco
# orphaned_numbers = []
# listed_numbers.each do |l|
# scan = db_numbers.select{ |db| l.number == db.number}
# orphaned_numbers.push(l) if scan.empty?
# end
# return orphaned_numbers
# end
I am finding this difficult because it's the same view and partial that was used before to display these orphaned numbers (both iterations) but it's legacy code so I've never seen it working in action but I'm just confused how it worked before with Active Record results and a normal array.
The view is just:
<%= render :partial => 'list_item', :collection => #telco_numbers ) %>
Where #telco_numbers is set to the return value of the above methods. (#telco_numbers = TelcoNumber.orphaned_in_telco params[:page])
The partial is as follows:
<tr>
<td>
<%= (link_to list_item.organisation.name.truncate(30), :controller => 'organisation', :action => 'update', :id => list_item.organisation.id) if list_item.organisation %>
</td>
<td class="centre"> <%= link_to ((list_item.countrycode == "44" ? Telco.format_uk_number(list_item.number) : "+#{list_item.countrycode} #{list_item.number}")), {:action => 'update', :id => list_item.id} %></td>
<td class="centre"><%= list_item.route_technology %></td>
<td><%= list_item.route_destination if list_item.route_destination %></td>
<td class="centre">
<% if !list_item.new_record? %>
[ <%= link_to 'Edit', {:action => 'update', :id => list_item.id} %> ]
<% else %>
[ <%= link_to 'Add New', {:action => 'update', :telco_number => list_item.attributes } %> ]
<% end %>
</td>
So as I understand it, for the the version I am trying to fix, instead of having an Edit action, it would have an Add New link since it's not in my database table yet so I am just trying to figure out how to refactor the inefficient version so that it will still work with the shared view.
If it helps, the format of the JSON API response is :
[{"country_code":"44","number":"1133508889","block":null,"type":"Legacy","SMS":"0"},
So only country_code and number correspond to columns in my database table, the rest isn't necessary, hence the if statements in the partial to only show certain parameters if they are available.
UPDATE
After changing the method to the following as suggested by Chris Vo, it finally works after taking ages to complete but it's still not quite right.
def self.orphaned_in_telco
# original, inefficient way
db_numbers = self.find(:all)
listed_numbers = self.all_telco
orphaned_numbers = listed_numbers - db_numbers
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.id = n
orphaned_results.push(item)
end
return orphaned_results
end
The number column in my view html table just contains the + character and the Add New link doesn't have any value for the countrycode and number url parameters (link url is correct and all parameters are in the query string but they are all empty).
Some of the methods in my model:
def self.max_search_results
return ##max_search_results
end
#for pagination
def self.per_page
20
end
def self.some_telco(per_page, page = 1)
page = 1 if page.nil?
api_call = TelcoApiv3.new("post", "/numbers/#{TelcoApiv3.account_id}/allocated/all")
listed_numbers = TelcoApiv3.poll(api_call.response["link"])
return listed_numbers.collect do |ln|
ln.store("countrycode", ln["country_code"])
TelcoNumber.new ln
end
end
def self.all_telco(page = 1)
listed_numbers = some_telco(##max_nlist_results, page)
if listed_numbers.length == ##max_nlist_results
return listed_numbers.concat(all_telco(page + 1))
else
return listed_numbers
end
end
What if, for the orphaned_in_telco method, after you find the orphaned_numbers you create an instance of your model for every number in that set and then push it in a table to return them... or at least something in that direction. e.g.
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.id = n
orphaned_results.push(item)
end
return orphaned_results
And then from the partial when you call Add new you would only need to call save on that instance.
This way you won't have the problem of Active Record and array for the partial, since you will be returning an array of Active record instances.
Also, my suggestion for speeding up things, would be to use a Hash to store the keys/numbers.
Hope it helps!
UPDATE
In order to have the countrycode and speed up things a little, I will continue with my Hash suggestion:
So, let's start from your initial implementation:
#this returns everything from the API
all_numbers = self.all_telco
#this returns a Hash in the form {:number => :country_code}
listed_numbers = Hash[all_numbers.map{|x| [x.number,x.country_code]}]
#so now you can do
orphaned_numbers = listed_numbers.keys - db_numbers
orphaned_results = []
orphaned_numbers.each do |n|
item = self.new()
item.number = n
item.countrycode = listed_numbers[n]
orphaned_results.push(item)
end
return orphaned_results
This should give it a boost and also send the country_code to the front side.
But first you're going to want to cut down on your db calls.
self.find(:all) #stupid slow
I'll point you in a right direction with
self.where('number NOT IN (?)', array_of_phone_numbers)
This will find all records that are not in the json data.
This is a very beginner question, but I've searched and can't find anything. I'm attempting to loop through an object, then store the information in an array (or object?) so that I can spit out a string of the items.
<% #da = [] %>
<% #report.data_items.each do |di| %>
<% if di.status == "Complete" %>
<% #da += di.url_metric.da %> #not sure how to append to the end of the array
<% end %>
<% end %>
Help? Should I use an array or object?
Seems that you're doing this in ERB template for some reason. Don't. Keep templates clear and simple. Do this kind of calculations in controller.
Here's a better version:
#da = #report.data_items.select {|di| di.status == 'Complete'}.
map{|di| di.url_metric.da }
#da = #report.data_items.collect{|di| di.url_metric.da if di.status == "Complete"}.compact
Here's shorted varian of what you're trying to accomplish:
#da = #report.data_items.select do |item|
item.status == "Complete"
end.map { |item| item.url_metric.da }.join(", ")
So im creating a website, and on that website people can post links. Depending on what the link is, the post will render differently. For example, a post with a link to youtube.com/somevideo will render an embeded video. A link ending in JPG will display that image.
I have written the following in my view
<% link_type = extract_content_from_url(post.link) %>
<div class ="preview_of_post">
<% if post.link %>
<% if link_type == "youtube" %>
<%= youtube_embed(post.link) %>
<% end %>
<br />
<%= link_to (post.link), (post.link) %>
<% end %>
And in my helper, I have this:
module PostsHelper
def extract_content_from_url(url)
if url != ""
unless url.include?("http://")
post.link = "http://#{post.link.downcase}"
end
else
return "nil"
end
if url.include? == "youtube.com/watch" #youtube link
return "youtube"
end
if File.extname(url) == ".gif" || File.extname(url) == ".jpg" ||
File.extname(url) == ".png" || File.extname(url) == ".jpeg"
return"picture"
end
end
def youtube_embed(youtube_url)
if youtube_url[/youtu\.be\/([^\?]*)/]
youtube_id = $1
else
youtube_url[/^.*((v\/)|(embed\/)|(watch\?))\??v?=?([^\&\?]*).*/]
youtube_id = $5
end
render(:inline=> "<iframe title='YouTube video player' width='640' height='390' src='http://www.youtube.com/embed/#{ youtube_id }' frameborder='0' allowfullscreen></iframe>")
end
end
When running my code, I get the following error:
Any suggestions?
Thanks.
url.include? == "youtube.com/watch" is not valid. include? is a method which takes an argument. You probably mean url.include? "youtube.com/watch".