Displaying data when searching through external API - ruby-on-rails

So, I am trying to search through an external API (Nutrionix) and am having trouble figuring out how to display the results.
I currently have a form for searching
<form action = "/foods" method = "get">
<div class = "field">
<input type = "text" name = "searched_value" alt = "Search Foods" />
</div>
<div class = "btn">
<input type = "submit" name ="btn" value = "Search Foods">
</div>
</form>
Then I have in my FoodsController:
class FoodsController < ApplicationController
require 'faraday'
require 'json'
def search
#searched_food = params[:searched_value].split(" ").join("%20")
#response_body = Faraday.get("https://api.nutritionix.com/v1_1/search/#{#searched_value}?format=json?fields=item_name%2Citem_id%2Cbrand_name%2Cnf_calories%2Cnf_total_fat&appId=[MYAPPID]&appKey=[MYAPPKEY]").body
#parsed_response = JSON.load(#response_body)
end
end
My relevant routes are:
Rails.application.routes.draw do
get 'food_form' => 'foods#food_form'
get 'foods' => 'foods#foods'
get 'search' => 'foods#search'
end
It then just goes back to the page that links to the "add foods" page where I'm currently just trying to get stuff to show up so I have:
<div class = "description">
<%= link_to "Add foods", food_form_path %>
<%= #parsed_response%>
<%= #response_body%>
<%= #searched_food %>
</div>
I currently get nothing for my results as just the link to the form appears. However, when I just put the controller info on an html page I can see results and if I go to the nutrionix link myself, I get results.
Help would be much appreciated. :)

The search form isn't hitting the action it supposed to because it has action = "/foods" which should be action = "/foods/search". Changing it should solve your problem.
<form action = "/foods/search" method = "get">
<div class = "field">
<input type = "text" name = "searched_value" alt = "Search Foods" />
</div>
<div class = "btn">
<input type = "submit" name ="btn" value = "Search Foods">
</div>
</form>

Related

How to pass a view value to a controller on rails

I have a controller called items_controller, I need to send a value to it using my unanswered.html.erb view.
But I'm not getting it, my view makes an each and I need each value of that each to call the controller and receive the value of that controller
items_controller.erb
class MercadoLivre::ItemsController < ApplicationController
before_action :set_items
def items
#details = #get_item_service.item_details
#item = #details.body
end
private
def set_items
#get_item_service = MercadoLivre::Items.new
end
end
My service items.rb
module MercadoLivre
class Items
include HTTParty
base_uri 'https://api.mercadolibre.com'
def initialize(mlb_code_id)
#mlb_code = mlb_code_id
#options = {
headers: {
Authorization: 'Bearer ****'
}
}
end
def item_details
self.class.get("/items/#{#mlb_code}", #options)
end
end
end
my view unanswered.html.erb
<div>
<p class="text-2xl mb-3">Perguntas não respondidas</p>
<%= button_to "Ver perguntas respondidas", questions_answered_path, method: :get, class: "mb-5 mt-5 text-red-700" %>
<div>
<% #list['questions'].each do |q| %>
<div class="flex flex-col">
<div>
<p class="font-bold">Pergunta: </p>
<p><%= q['text'] %> </p>
</div>
<div>
<p class="font-bold">Item:</p>
<p><%= q['item_id'] %> </p>
<%# pass value to controller items_controllers.rb here %>
</div>
<textarea name="" id="" cols="30" rows="10">
</textarea>
<button class="mt-5">Responder</button>
</div>
<% end %>
</div>
</div>
You can try creating a new instance of MercadoLivre::Items with the correct number of parameters it was defined;
def set_items
#get_item_service = MercadoLivre::Items.new(1) # you need a value for +mlb_code+
end

how do i parse a div on website with jsoup

i want to parse something like this:
<div class = "1">
<div class = "2">
<div class = "3">
<div class = "4">
<div class = "5"> value </div>
</div>
</div>
</div>
but when i'm using
Document d = Jsoup.connect("https://example").get();
Elements elements = d.getElementsByClass("5");
System.out.println(elements);
i'm getting nothing ;( i've tried a ton of variants but nothing seems to work. How do i do that?

Modal for tr - different id index page

I have an index page with different software in a table.
I want to display additional information (in a modal) when we click on a tr.
Everything works but I have the information of a single software that appears in my modal and is the same for each tr.
I would like to display the information of each software in the corresponding modals.
My script :
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal').modal('show');
}
});
My view :
<% #nonpremium.each do |software| %>
<table>
<tr class="clickable">
<td class="hey1">
<%= link_to software_path(software), class: "no-click" do %>
<%= image_tag software.logo.url(:medium), class:"no-click"%>
<% end %>
</td>
<td class="hey3">
<h6><%= software.slogan %></h6>
<p><%= software.largeslogan %></p>
</td>
</tr>
</table>
<div class="modal fade bd-example-modal-lg" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<%= link_to software.software_name, software_path(software), class:"no-click" %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<% end %>
I tried something like this in my script, but it does not work ..
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal-<%= #software.id %>').modal('show');
}
});
Thx for you help
EDIT :
Controller/pages
class PagesController < ApplicationController
before_action :click, only: :index
def home
#softwares = Software.all.order(:cached_votes_up => :desc )
#premium = Software.includes(:user).where(users: { subscribed: true }).order("RANDOM()").limit(2)
#nonpremium = #softwares - #premium
end
def search
#softwares = Software.ransack(name_cont: params[:q]).result(distinct: true)
#categories = Category.ransack(name_cont: params[:q]).result(distinct: true)
respond_to do |format|
format.html {}
format.json {
#softwares = #softwares.limit(5)
#categories = #categories.limit(5)
}
end
end
end
EDIT 2 :
I have the desired result by putting in my table the information that I want to recover, then I put a "display: none".
<style>
td.test {
display:none;
}
</style>
<td class="test">
<span><%= software.software_description %></span>
<span><%= get_video_iframe(software.youtube_id) %></span>
</td>
Then I get the information from my table in my script:
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
var description = this.childNodes[3].innerHTML;
var name = this.childNodes[5].innerHTML;
document.getElementById("myModalName").innerHTML = name;
document.getElementById("myModalDesc").innerHTML = description;
$('#exampleModal').modal('show');
}
});
For then displayed in my modal:
...
<div class="modal-body" id="myModalName">
Name
</div>
<div class="modal-body" id="myModalDesc">
Description
</div>
...
There is probably better to do, but being a beginner is how I achieve the desired result.
However I would like to post videos in my modals.
Am I not going to overload my home page by hiding youtube videos with my display: none?
You won't be able to use erb in your script (unless this is in a script tag within your view, in which case your code should work) - better using a data attribute. For example, if you update your tr to the following:
<%= content_tag :tr, class: "clickable", data: { software_id: #software.id } do %>
# the rest of your code within the tr
<% end %>
# Equivalent of using:
# <tr class="clickable" data-software_id="<%= #software.id %>">
This attaches the relevant software_id to the tr in the DOM. You can then use the following in your script, accessing this new attribute:
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal-' + $(e.target).data('software_id')).modal('show');
}
});
And everything should work as desired.
Let me know how you get on or if you have any questions. Hope this helps!
Edit based on your comment:
That error you're seeing will come because #software is nil and you are, therefore, attempting to call id on nil.
It's a common error, and means to need to ensure #software is correctly set in your controller. If you post your controller code, I might be able to help with this.
Alternatively, you can 'safely' try the method, using #software&.id with newer versions of Ruby / Rails (or #software.try(:id) on older versions). However, that's not likely to be helpful here, more of a side note :)
Edit 2:
So, in your controller, you're not actually assigning the singular #software, rather the plural #softwares:
#softwares = Software.all.order(:cached_votes_up => :desc )
#premium = Software.includes(:user).where(users: { subscribed: true }).order("RANDOM()").limit(2)
#nonpremium = #softwares - #premium
Then, in your view, you're looping through #nonpremium using the local variable software. So, you can either:
assign #software in the controller if it should always use the same data in the modal
go back to the previous option, assigning a data attribute to the tr, which is what I'd recommend. Using that should work, although you'll need to alter the code to use software without the # to address the correct variable.
I.E.
<%= content_tag :tr, class: "clickable", data: { software_id: software.id } do %>
# the rest of your code within the tr
<% end %>
This ensures the script addresses the click based on the element clicked, and pulls the id directly from there, which is within the scope of your software loop.
That do it for ya?

How do I pass a specific string to my partial depending on the value of another variable also being passed to it?

I have the following partial (_card_brand.html.erb), which looks like this:
<div class="payment-card">
<i class="fa fa-cc-<%= brand.downcase %> payment-icon-big text-success"></i>
</div>
That renders HTML that looks like this:
<div class="payment-card">
<i class="fa fa-cc-visa payment-icon-big text-success"></i>
</div>
The above is rendered with this:
<%= render partial: "subscriptions/card_brand", locals: { brand: current_user.card_brand } %>
What I want to do is change the class text-success, to be either: text-warning, text-primary, text-danger, etc. depending on if the card has brand: visa, amex, mastercard, discovery, etc.
So:
Visa = Success
AMEX = Warning
Mastercard = Primary
Discovery = Danger
Any other cards would be other classes.
How do I elegantly represent that in my view that renders the partial?
You may create a helper and use it so that it will be easy to add new classes as well.
application_helper.rb
CARD_CLASS = {
'visa' => 'success',
'amex' => 'warning',
'mastercard' => 'primary',
'discovery' => 'danger'
}
def payment_class(type)
CARD_CLASS[type.downcase]
end
_card_brand.html.erb
<div class="payment-card">
<i class="fa fa-cc-<%= brand.downcase %> payment-icon-big text-text-<%= payment_class(brand.downcase) %>"></i>
</div>

TypeError: Cannot set property 'chat_room_id' of undefined when using ng-if

I'm running into a bit of a road block here.
I'm working on a chat feature, which is currently within a rails partial in the application.html.erb file.
What I'm looking to do is have a list of a user's friends display in the chat area initially. When the user clicks on a friend's name, the corresponding chat room opens and the messages between the user and friend are displayed. If the user wishes to exit the chat, and view his friends list again, the user would simply click a button (currently "View Friends").
I am currently toggling between friends and rooms/messages using the ng-if directive.
I have not completely set this up yet, so I know there are bugs. I have created user friendships within rails, set up my REST API in rails, and can GET and POST resources via Angular and Restangular.
However, the issue at hand is that ever since I implemented the ng-if directives in the partial, I am getting the following error:
TypeError: Cannot set property 'chat_room_id' of undefined
If I am to remove the ng-if directives and all of the corresponding $scope.messagesVisible and $scope.friendsVisible variable references within the controller, the form submit works, so I know it has something to do with my implementation of the ng-if directives, and the fact that newMessage is undefined, but I'm not sure why.
I suspect it has something to do with Angular promises or my lack of understanding in regards to both Angular promises and the ng-if directive, but if anyone could shed some light on why this may be happening (and offer a solution) that would be amazing.
Thanks, guys!
Code below (please excuse terrible styling - it's a placeholder)
rails_partial:
<section ng-app="atmosphere" ng-controller="AtmoChatCtrl" style="position:relative; top:32%; float:right; right:5px; margin-bottom:10px; margin-top:30px;">
<div ng-if="friendsVisible" style="position:relative; left:35px; width:100px;">
<% user_friendships.each do |friendship| %>
<ul>
<% friend = friendship.friend %>
<% if friendship.accepted? %>
<li style="cursor:pointer;" ng-click="setChatAttributes(<%= friend.id %>, <%= current_user.id %> );"><%= friend.name %></li>
</ul>
<% end %>
<% end %>
</div>
<div ng-if="messagesVisible" style="position:absolute; top:60%; width: 150px; height:40%; right:-80px; margin-top:100px">
<div>
<p ng-repeat="message in messages">{{message.user_id}}: {{message.body}}</p>
<form ng-submit="saveMessage();">
<input type="text" ng-model="newMessage.body">
</form>
</div>
</div>
<div style="position:absolute; top:300px;">
<button ng-if="messagesVisible" ng-click="viewFriends();">View Friends</button>
</div>
</section>
<%= javascript_include_tag "angular/application" %>
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular-resource.min.js" %>
angular_controller:
angular.module('AtmoChatCtrl', [])
.controller('AtmoChatCtrl', ['$scope', '$resource', '$interval','Pusher','Restangular', function ($scope, $resource, $interval, Pusher, Restangular) {
$scope.baseMessages = Restangular.one('api/chat_rooms', 2).all('chat_messages');
$scope.roomId = '2';
$scope.messagesVisible = false;
$scope.friendsVisible = true;
console.log("SET ROOM");
$interval(function(){
$scope.baseMessages.getList().then(function(messages) {
$scope.messages = messages;
});
console.log("POLLING");
}, 1000);
$scope.saveMessage = function() {
$scope.newMessage.chat_room_id = $scope.roomId;
$scope.newMessage.user_id = $scope.userId;
$scope.baseMessages.post($scope.newMessage).then(function(newMessage){
$scope.messages.push(newMessage);
console.log("SAVED");
})
}
$scope.setChatAttributes = function(roomId, userId) {
$scope.baseMessages = Restangular.one('api/chat_rooms', roomId).all('chat_messages');
$scope.roomId = roomId;
$scope.userId = userId;
$scope.messagesVisible = true;
$scope.friendsVisible = false;
console.log(roomId)
console.log(userId)
}
$scope.viewFriends = function() {
$scope.friendsVisible = true;
$scope.messagesVisible = false;
}
}]);
NVM. I'm an idiot. Solved by setting $scope.newMessage = {}; after the first $scope.friendsVisible = true;

Resources