trying to use a news API with rails application - api

I'm trying to get information from newsapi. I've used the basic structure i found elsewhere for another api to start with but i'm very new to this and not sure what is wrong/how to fix etc. all i'm trying to do is display the titles of the articles on my index page. At the moment, everything displays on the page, like title, author etc as an array but i just want to narrow things down and the syntax for doing so in the view. i've changed my api key to '?' for the time being(i know it should be in the .env file).ive looked at a lot of docs but i cant seem to find an answer. apologies if
this is a broad question.
class TestsController < ApplicationController
require "open-uri"
def index
url = 'https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=????????????????????????'
article_serialized = open(url).read
#articles = JSON.parse(article_serialized)
end
end
<% #articles.each do |article| %>
<%= article[1] %>
<% end %>

This should do it
<% #articles["articles"].each do |article| %>
<%= article["title"] %>
<% end %>
Edit : This is what my ruby script looks like that I used for testing
require 'json'
file = File.read 'output.json'
data = JSON.parse(file)
data["articles"].each do |item|
print item["title"]
end

Related

Argument error when trying to create a mission

I have a form for creating new Missions with an Admin account. Each Mission is linked to an account. When I visit admin/missions/new I get an error "ArgumentError in Admin::Missions#new". Can anyone point to what I'm doing wrong?
When I checked the rails console a mission id and name does show up, but I guess I'm missing the Admin for the mission.
Here's my Controller
class Admin::MissionsController < Admin::ApplicationController
def index
#missions = missions
end
def new
#mission = current_account.missions.new(params[:mission])
#mission.save
end
def create
render plain: params[:mission].inspect
end
def edit
#mission = missions.find(params[:id])
end
private
def missions
#missions ||= current_account.missions
end
end
Here's my form
<%= form_with [:admin, #mission] do |f| %>
<div>
<label>Name</label>
<%= f.text_field :name %>
</div>
<div>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
I'm expecting the url admin/missions/new to take me to the form, but I I get the argument error wrong number of arguments (given 1, expected 0)
You don't have params yet in the new action as the view (where the form which has to collect the params is) is rendered after the controller code. The object should be created in the create action:
def create
current_account.missions.create(params[:mission])
end
And the new action should be just:
def new
#mission = current_account.missions.new
end
Check the Binding a Form to an Object section of the Rails guide.
The form code seems also to be wrong, as form_with [:admin, #mission] do |f| is not a valid syntax. It should be:
<%= form_with model: [:admin, #mission] do |form| %>
Check form_with documentation for more details.
Ideally new method is just for creating a new instance and create method is for saving records. Changing to what Ana Maria is suggesting should fix your issue. Thanks.

Ruby on Rails website is slow; could it be the SQL queries?

I have been working on a web application made with Ruby on Rails. I've "completed" the site, but it runs very slow and pages sometimes take on the order of ten seconds to load. I've broken this post up into three sections:
Overview
Diagnosis
Possible Ideas
Overview
As a very rough overview, this website displays personal projects, each of which have their own page. Each project (which I call a “post” in the code) is stored in a table. I’m not sure if it’s a bad idea to store a whole post in a database as some posts have a decent amount of text and images in their body. Each entry in the posts table has the following attributes:
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string
# body :text
# description :text
# slug :string
# created_at :datetime not null
# updated_at :datetime not null
# image_file_name :string
# image_content_type :string
# image_file_size :integer
# image_updated_at :datetime
# thumbnail_file_name :string
# thumbnail_content_type :string
# thumbnail_file_size :integer
# thumbnail_updated_at :datetime
# published :boolean default("f")
# published_at :datetime
#
Diagnosis
I’m using Heroku to host the application. I’ve upgraded to Hobby level dynos, so I could have access to some of the metrics they provide, like throughput, memory usage, etc. I don’t think Heroku is what is making the website slow, but rather my code. In an effort to debug, I've added a third party addon, Scout, that tracks the bottlenecks in the application.
Scout offers a trace feature that quantizes which code paths are taking the most time in the application. You can see below (in the bottom half of the picture) that there are a significant amount of traces that take upwards of ten seconds. Not very good…
When I click on the second line (6/17 2:04 PM), it gives a breakdown of the response time:
Expanding the SQL statements shows that most of the time intensive queries are from acting on the posts database, and sometimes sorting/ordering the posts (see below).
Possible Ideas
Is there anything obvious I am doing wrong here? I am pretty stuck, and not sure how to speed things up. Given what Scout is saying, I have two ideas:
Controller/SQL queries the controller invokes are slow
Embedded Ruby code in HTML is slow.
Controller/SQL queries the controller invokes are slow:
The code below shows the code where I am assigning #posts in the PostsController. The home method is run when the user visits the home page, and the index method is run when the user goes to the posts page. Could these queries be slow because there is a fair amount of data in the database (5 posts worth of text and images)?
class PostsController < ApplicationController
#before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy, :publish, :unpublish]
def home
#posts = Post.all.published.order('published_at DESC')
end
# GET /posts
# GET /posts.json
def index
if user_signed_in? and current_user.admin
#posts = Post.all.order("id")
else
#posts = Post.all.published
end
end
Embedded Ruby Code in HTML is slow:
I am using Ruby in some of my HTML code to sort the posts by date and to determine the most recent post. For example, in the sidebar of the website (to the left of the home page), there is section that displays “Recent”, and the logic behind that is:
<h4 style="border-bottom: 1px solid #bbb">Recent</h4>
<% #post=Post.all.published.order("published_at").last %>
<% if #post == nil or #post.published_at == nil %>
<div class="temp_sidebar">Coming Soon!</div>
<% else %>
<%= render partial: "layouts/media", locals: {post: #post} %>
<% end %>
Similarly, in the “Archives” section of the sidebar, I’m sorting the posts by date, and am doing this logic:
<% if Post.published.length != 0 %>
<h4>Archives</h4>
<div id="sidebar" class="list-group">
<% #published_posts = Post.published %>
<% archives = Hash.new(0) %>
<% #published_posts.each do |post| %>
<% if archives[post.date] == 0 %>
<% archives[post.date] = 1%>
<% else %>
<% archives[post.date] += 1 %>
<% end %>
<% end %>
<% archives.each do |key, value| %>
<button class="accordion"><%= key %> <span class="badge"> <%= value %></span></button>
<div class="panel">
<% #published_posts.each do |post| %>
<% if post.date == key %>
<p><%= link_to post.title, post_path(#post) %></p>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
My idea is that maybe iterating over posts is taking a very long time, but I’m not entirely sure. I feel like this is valid code that is ok to be used, but maybe something about it is very slow. Would you guys have any ideas here? It may also be good to note here that the app's memory usage is pretty high: around 500MB. Maybe these queries are slow because of all the data that is getting fetched, but that said, I'm am not quite sure what "a lot" of data is for a web app like this. And of course, my hypothesis as to why this site is slow could be totally wrong, so I'm very open to your thoughts. Lastly, if the SQL queries/code I am using is slow, are there ways I could speed it up/improve its performance? Thank you for any help in advance!
I see two problems: a lack of SQL indexes, and too many calls to Post.all.
Your slow queries involve WHERE published = ?. If posts.published is not indexed, this will have to scan the entire table, not just the published posts. You also tend to sort by posts.published_at and without an index this will also be slow.
To fix this, add an index on posts.published and posts.published_at in a migration.
add_index(:posts, :published)
add_index(:posts, :published_at)
You can read more about indexes in the answers to What is an index in SQL?
Using Post.all or Post.published means loading every post from the database into memory. If you're not using them all, it's a huge waste of time.
For example, it's unwieldy to display every post on your index and home pages. Instead you should use pagination to fetch and display only a page of posts at a time. There are gems for this such as kaminari and will_paginate as well as larger administrative solutions such as ActiveAdmin. And if you don't like page links, if you look around you can find examples of using them for "infinite scroll".
Finally, you can add caching. Since your site isn't going to update very frequently, you can cache at various levels. Have a read through Caching with Rails: An Overview.
But caching brings its own problems. Consider if you need it after you do basic performance optimizations.
Schwern,
Thank you for the pointers! With the help of your post, I was able to minimize the number of calls to Post.all. These were killing my response time big time. I did not realize that calling Post.all loaded the all of the posts and their attributes to memory (it's a learning process haha).
For places where I did not need to load every attribute of a post, I ended up doing Post.select("attribute"). For example, originally in the home method of the PostsController, I had:
def home
#posts = Post.all.published.order('published_at DESC')
end
Running Post.all.published.order('published_at DESC') in the rails console shows that this query takes approximately 4 seconds:
Updating the home method to use Post.select, as opposed to Post.all (as shown below) significantly improved the response time of the query.
def home
#SLOW: loads everything from a post
##posts = Post.all.published.order('published_at DESC')
#FAST: only loads the necessary elements from a post, and does not waste time loading body (body = lots of data)
#posts = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").published.order('published_at DESC')
end
Running #posts = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").published.order('published_at DESC') in the rails console shows that this query takes approximately 2ms! Huge improvement! This is because I am not loading the body attribute, among other things of the post, which contain a lot of data, and thus consume a lot of time to load into memory. No point of loading it into memory if you're not going to use it!
In a similar spirit, I was able to improve the performance of the other sections of code (see below for fixes) and ultimately make the website have significantly faster response times!
Controller fix:
class PostsController < ApplicationController
#before_action :authenticate_user!
before_action :set_post, only: [:show, :edit, :update, :destroy, :publish, :unpublish]
def home
#SLOW: loads everything from a post
##posts = Post.all.published.order('published_at DESC')
#FAST: only loads the necessary elements from a post, and does not waste time loading body (body = lots of data)
#posts = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").published.order('published_at DESC')
end
# GET /posts
# GET /posts.json
def index
if user_signed_in? and current_user.admin
#SLOW loads everything from a post
##posts = Post.all.order("id")
#FAST: only loads the necessary elements from a post, and does not waste time loading body (body = lots of data)
#posts = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").order('id')
else
#SLOW loads everything from a post
##posts = Post.all.published
#FAST: only loads the necessary elements from a post, and does not waste time loading body (body = lots of data)
#posts = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").published
end
end
Embedded Ruby Code in HTML fix:
"Recent" section fix:
<h4 style="border-bottom: 1px solid #bbb">Recent</h4>
<!-- LINE BELOW IS SLOW!!! (to test, uncomment line, and embrace in "<% %>") -->
<!-- #post = Post.all.published.order(:published_at).last -->
<!-- FAST! Line below replaces line above and is much faster! -->
<% #post = Post.select("id", "title", "description", "slug", "created_at", "updated_at", "image_file_name", "thumbnail_file_name", "published", "published_at", "date").published.order('published_at DESC').first %>
<% if #post == nil or #post.published_at == nil %>
<div class="temp_sidebar">Coming Soon!</div>
<% else %>
<%= render partial: "layouts/media", locals: {post: #post} %>
<% end %>
"Archives" section fix:
<!-- LINE BELOW IS SLOW!!! (to test, uncomment line, and embrace in "<% %>") -->
<!-- if Post.published.length != 0 -->
<!-- FAST! Line below replaces line above and is much faster! -->
<% if Post.select("id").published.count("id") != 0 %>
<h4>Archives</h4>
<div id="sidebar" class="list-group">
<!-- LINE BELOW IS SLOW!!! (to test, uncomment line, and embrace in "<% %>") -->
<!-- #published_posts = Post.published -->
<!-- FAST! Line below replaces line above and is much faster! -->
<% #published_posts = Post.select("id", "title", "date").published %>
<% archives = Hash.new(0) %>
<% #published_posts.each do |post| %>
<% if archives[post.date] == 0 %>
<% archives[post.date] = 1%>
<% else %>
<% archives[post.date] += 1 %>
<% end %>
<% end %>
<% archives.each do |key, value| %>
<button class="accordion"><%= key %> <span class="badge"> <%= value %></span></button>
<div class="panel">
<% #published_posts.each do |post| %>
<% if post.date == key %>
<p><%= link_to post.title, post_path(post.id) %></p>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>

rails routes - Resource not appending _path

I am attempting to use resources to auto generate routes for my resource. The namespace is admin and the resource is author. The following code seems to work for most instances.
namespace :admin do
resources :author
end
When I run
rake routes
I get the following
admin_author_index GET /admin/author(.:format) admin/author#index
POST /admin/author(.:format) admin/author#create
new_admin_author GET /admin/author/new(.:format) admin/author#new
edit_admin_author GET /admin/author/:id/edit(.:format) admin/author#edit
admin_author GET /admin/author/:id(.:format) admin/author#show
PUT /admin/author/:id(.:format) admin/author#update
DELETE /admin/author/:id(.:format) admin/author#destroy
From what I can tell I am expecting the named paths to have a
_path
at the end. I am rather green at this. I have searched and searched but I could just be using the wrong terms to find the answer. Any help is appreciated. Thanks!
-edit- I should add that
<%= form_for [:admin, #author] do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.submit %>
<% end %>
Gives me errors saying it can not find admin_author_path
You can append either _path or _url to these. Basically everything looks good.
So for example
admin_author_index GET /admin/author(.:format) admin/author#index
the helper method can be admin_author_index_path or admin_author_index_url. These helpers can be used in controllers and views to point to a controller/action or url. Read this link http://guides.rubyonrails.org/routing.html to understand more.
No. The route name does not have the _path suffix.
Refer to Rails routing from inside in for more information. It explains routing in great detail.

Redirecting outside a web app?

This is my first time developing a rails app from scratch. The goal of my code is to use a title and link (both stored in a database table) to redirect users to the link. (Problem) When I click the link title, I'm redirected to localhost:3000/google.com instead of google.com. (Assuming google.com was the value in link.link)
<h1>Links#index</h1>
<% #links.each do |link| %>
<p>
<%= link_to link.title, link.link %>
</p>
<% end %>
Notes:
(1) Using Rails 3.1
(2) The contents of my routes.rb file are below (Not sure if the use of resources :links has something to do with my problem)
CodeHed::Application.routes.draw do
resources :links
get "links/index"
root :to => "links#index"
end
Are your links prefixed with "http://"? If not, try adding that in programmatically with something like:
def add_http(link)
if (link =~ /http(?:s)?:\/\//)
link
else
"http://#{link}"
end
end
If that doesn't work then you could simply enter raw html:
<h1>Links#index</h1>
<% #links.each do |link| %>
<p>
<%= link_to title, add_http(link) %>
</p>
<% end %>
(I haven't checked this code)

how can i use fb_server_fbml helper method in facebooker2?

I am developing a facebook app using rails 3 and facebooker2
i cannot find any example on how to use fb_server_fbml helper method.
what is "proc" in its paramter. Can anyone provide me with sample code?
Thanks
The &proc parameter is used as a content block that is inserted between the <fb:serverFbml> tags. You can learn more about block helpers and differences between Rails 2.3 and Rails 3 here: Block Helpers in Rails 3
So, try something like this:
<% fb_server_fbml do %>
<%#Insert here your content %>
<% end %>
If you want to use the request form, try the following:
<% fb_server_fbml do %>
<% fb_request_form("Your app name","http://www.example.com/callback","Try this out!") do %>
<%= fb_multi_friend_selector("Invite your friends:", {:rows => 3}) %>
<% end %>
<% end %>