how to display json and parse json in ruby using httparty - ruby

I am working on a food app in ruby on rails which requires to get calorie value of food item from food api.In my controller i am getting the JSON response but i am unable to parse and display the calorie value of food item in a index.html.erb file here is my controller code.
require 'rubygems'
require 'httparty'
class FoodsController < ApplicationController
def index
#foods = Food.all
end
def show
#food = Food.find(params[:id])
end
def new
#food = Food.new
end
def edit
#food = Food.find(params[:id])
end
def create
#food = Food.new(food_params)
#response = HTTParty.get('http://api.nutritionix.com/v1_1/search/'+#food.name+'?fields=item_name%2Citem_id%2Cbrand_name%2Cnf_serving_size_unit%2Cnf_calories%2Cnf_total_fat&appId=696d1ad4&appKey=aec2c4766d40d7f6346ed89d5d82fe75')
#http_party_json = JSON.parse(#response.body)
if #food.save
redirect_to foods_path
else
render 'new'
end
end
def update
#food = Food.find(params[:id])
if #food.update(food_params)
redirect_to #food
else
render 'edit'
end
end
def destroy
#food = Food.find(params[:id])
#food.destroy
redirect_to foods_path
end
private
def food_params
params.require(:food).permit(:name, :quantity)
end
end
Any suggestions are highly welcome as i am newbie on stackoverflow so dont know proper editing forgive please! help me how to display calorie value in html page

You can add a new function to Food model to get you the Calorie:
class Food
def calorie
response = HTTParty.get("http://api.nutritionix.com/v1_1/search/#{self.name}?fields=item_name%2Citem_id%2Cbrand_name%2Cnf_serving_size_unit%2Cnf_calories%2Cnf_total_fat&appId=696d1ad4&appKey=aec2c4766d40d7f6346ed89d5d82fe75")
json = JSON.parse(response.body)
end
end
and then simply in your index.erb if you loop over foods collection you do the following:
<% #foods.each do |food| %>
<%= food.name %>
<%= food.calorie %>
<% end %>
but in that case performance will not be good, as you do remote access for each item each time you display data, so as calorie value is always the same for same food, then after its created you can do remote query and store the calorie to calorie attribute in your Food model
You can do the following:
class Food < ActiveRecord::Base
before_create :set_calorie
private
def set_calorie
response = HTTParty.get("http://api.nutritionix.com/v1_1/search/#{self.name}?fields=item_name%2Citem_id%2Cbrand_name%2Cnf_serving_size_unit%2Cnf_calories%2Cnf_total_fat&appId=696d1ad4&appKey=aec2c4766d40d7f6346ed89d5d82fe75")
self.calorie = JSON.parse(response.body)
end
end

Related

Sinatra Session data shared between browsers

I have a basic banking application running on Heroku using Sinatra.
I have tried implementing sessions to ensure each user that visits has a different version of the app. However, at the moment, if I visit it with two separate browsers, I have the same data.
There is no backend database implemented but data I add via the interface persists in every browser I visit in.
Here is my app.rb:
require 'sinatra/base'
require 'tilt/erb'
require 'require_all'
require_all 'lib'
require 'rufus-scheduler'
class BankingApp < Sinatra::Base
enable :sessions
set :session_secret, 'super secret'
get '/' do
session[:accounts] = AccountsController.instance
session[:holders] = HoldersController.instance
session[:loans] = LoansController.instance
erb :index
end
get '/holders' do
#holders = session[:holders].store
erb :holders
end
get '/holders_accounts' do
#holder = session[:holders].find(params[:id].to_i)
message = session[:accounts].get_accounts_of(params[:id].to_i)
#accounts = message.accounts
erb :holders_accounts
end
get '/new_holder' do
erb :new_holder
end
post '/new_holder' do
#message = session[:holders].create(params[:name])
#holders = session[:holders].store
erb :holders
end
get '/create_account' do
erb :create_account
end
post '/create_account' do
type = :Current
id = params[:id].to_i
#message = session[:accounts].open(type, with: id)
erb :index
end
get '/accounts' do
#accounts = session[:accounts].store
erb :accounts
end
get '/transactions' do
message = session[:accounts].get_transactions_of(params[:id].to_i)
#transactions = message.transactions
erb :transactions
end
get '/deposit' do
erb :deposit
end
post '/deposit' do
#accounts = session[:accounts].store
#message = session[:accounts].deposit(params[:amount].to_i, into: params[:id].to_i)
erb :accounts
end
get '/withdraw' do
erb :withdraw
end
post '/withdraw' do
#accounts = session[:accounts].store
#message = session[:accounts].withdraw(params[:amount].to_i, from: params[:id].to_i)
erb :accounts
end
get '/transfer' do
erb :transfer
end
post '/transfer' do
#accounts = session[:accounts].store
#message = session[:accounts].transfer(params[:amount].to_i, from: params[:donar].to_i, to: params[:recipitent].to_i)
erb :accounts
end
get '/add_holder' do
erb :add_holder
end
post '/add_holder' do
#accounts = session[:accounts].store
#message = session[:accounts].add_holder(params[:holder_id].to_i, to: params[:account_id].to_i)
erb :accounts
end
get '/enable_overdraft' do
erb :enable_overdraft
end
post '/enable_overdraft' do
#accounts = session[:accounts].store
#message = session[:accounts].activate_overdraft(params[:id].to_i, params[:amount].to_i)
erb :accounts
end
get '/disable_overdraft' do
erb :disable_overdraft
end
post '/disable_overdraft' do
#accounts = session[:accounts].store
#message = session[:accounts].deactivate_overdraft(params[:id].to_i)
erb :accounts
end
get '/loans' do
#loans = session[:loans].store
erb :loans
end
get '/loan_view' do
message = session[:loans].show(params[:id].to_i)
#transactions = message.transactions
erb :loan_view
end
get '/new_loan' do
erb :new_loan
end
post '/new_loan' do
#loans = session[:loans].store
id = params[:id].to_i
options = { borrowed: params[:amount].to_i, term: params[:term].to_i, rate: params[:rate].to_f }
#message = session[:loans].create_loan(id, options)
erb :loans
end
get '/pay_loan' do
erb :pay_loan
end
post '/pay_loan' do
#message = session[:loans].pay(params[:amount].to_i, off: params[:id].to_i)
#loans = session[:loans].store
erb :loans
end
# start the server if ruby file executed directly
run! if app_file == $0
end
I do not have a great deal of experience with Sinatra so apologies if this is an oversight on my part.
Any help greatly appreciated.
So I'm pretty sure the core of your problem is this line which you have in multiple places throughout your code. As per the ruby docs
This ensures that only one instance of Klass can be created.
You've explicitly told ruby to only ever let one copy of each class/module ever exist. I don't think that's what you want.
It's a bit hard to infer what it is you're trying to achieve exactly but I don't think using Singleton in a web app is going to be the right solution. The assumptions it imposes break down as soon as you run a 2nd instance (or dyno in Heroku parlance) of your app.
I would recommend using this
get '/logout' do
session.clear
end

Rails 4 strong parameters ActiveModel::ForbiddenAttributesError

For some reason in my current controller I am getting ActiveModel::ForbiddenAttributesError even though I believe I am using strong parameters just fine. Albeit I am using permit! for the time being to permit all model attributes. See code below, what am I missing
class HeuristicsController < ApplicationController
def index
#heuristics = Heuristic.order(:name).page params[:page]
#heuristic = Heuristic.new
end
def create
#heuristic = Heuristic.new(params[:heuristic])
if #heuristic.save
redirect_to action: 'index', :flash => {:success => "New heuristic created!" }
else
render 'new'
end
end
def new
#title = "Heuristic"
#heuristic = Heuristic.new
end
private
def heuristic_params
params.require(:heuristic).permit!
end
end
i think you did not fully understand the way that strong-params work...
you have a method
def heuristic_params
params.require(:heuristic).permit!
end
and you are not using it
Heuristic.new(params[:heuristic])

Undefined local variable or method 'id' for #<moviesController:0xb3314d64> on Rotten Potatoes

I've been working on an Edx problem Homeowrk 2 for about 2 hours. I'm officially stuck. How do you make something. This problem has to do with
What I have to do is link Movie Title to as sort, so that it would sort Movie in order.
-# This file is app/views/movies/index.html.haml
%h1 All Movies
%table#movies
%thead
%tr
%th= link_to 'Movie Title', new_movie_path
%th Rating
%th Release Date
%th More Info
%tbody
- #movies.each do |movie|
%tr
%td= movie.title
%td= movie.rating
%td= movie.release_date
%td= link_to "More about #{movie.title}", movie_path(movie)
= link_to 'Add new movie', new_movie_path
According to the homework, I'm supposed to edit the index to so that it puts "all Movies" in order. I've looked up the sort method for ruby, and it is movie.order(). I don't know what to put in the parenthesis.
class MoviesController < ApplicationController
def show
id = params[:id] # retrieve movie ID from URI route
#movie = Movie.find(id) # look up movie by unique ID
# will render app/views/movies/show.<extension> by default
end
def index
#movies = Movie.order(id)
end
def new
# default: render 'new' template
end
def create
#movie = Movie.create!(params[:movie])
flash[:notice] = "#{#movie.title} was successfully created."
redirect_to movies_path
end
def edit
#movie = Movie.find params[:id]
end
def update
#movie = Movie.find params[:id]
#movie.update_attributes!(params[:movie])
flash[:notice] = "#{#movie.title} was successfully updated."
redirect_to movie_path(#movie)
end
def destroy
#movie = Movie.find(params[:id])
#movie.destroy
flash[:notice] = "Movie '#{#movie.title}' deleted."
redirect_to movies_path
end
end
So the root problems, I dont know how to edit the method index correctly to give my "Movie" directory order, and I dont know how to assign the header Movie Title to point to index.
In the view
%th= link_to 'Movie Title', movies_path(sort_param: 'title')
and in the controller
def index
#movies = Movie.order(params[:sort_param])
end
You could do the same for other headings like 'Rating', 'Release Date' etc as well.
You can check ordering with Rails. The variable id in your index function does not exist.
Make a scope in your model. This is the most suggested way. Your controller does not need to know how to retrieve your results. Just ask model what you need!
In the scope, design it how you want. Check the doc for more info.
In your movie model file, put something like:
scope :ordered, order("id ASC")
Then in your controller index:
#movies = Movie.ordered
This will give your sorted movie collection

Why can I not save tweets into the database?

I want to save the tweets into the database, but it doesn't work! I'm using the twitter gem.
My controller:
class TweetsController < ApplicationController
def save_tweets_into_database
#tweets = Twitter.search("#em2012" "#Italy" "#Spain", :lang => "en", :rpp => 25).results
#tweets.each do |tweet|
#tweet = tweet
#tweet.create
end
end
end
My Model
require "rubygems"
require "twitter"
class Tweet < ActiveRecord::Base
end
My view
<% #title = "liste" %>
<h2>Liste der Tweets über das EM-Finale</h2>
<ul>
<% #tweets.each do |tweet| %>
<li><%= tweet %></li>
<% end %>
</ul>
my routes
Em2012tweet::Application.routes.draw do
match '/save_tweets', to: 'tweets#save_tweets_into_database'
end
This error is displayed:
undefined method `create' for Twitter::Status:0x007fac9c80a160
Rails.root: /Users/xyz/Desktop/Workspace/em2012tweet
app/controllers/tweets_controller.rb:7:in `block in save_tweets_into_database'
app/controllers/tweets_controller.rb:5:in `each'
app/controllers/tweets_controller.rb:5:in `save_tweets_into_database'
save the tweets into the database
In Rails, following REST convention, index action is associated with simply displaying all the objects of a model already stored in database. And this is actually what you did with the code as well. Your index action isn't doing anything that will save the tweets into the database.
I don't think you are trying to save tweets here. You are trying to simply display them. Try this if you want to simply display tweets in index view file.
def index
#tweets = Twitter.search("#em2012" "#italy" "#spain", :lang => "en", :rpp => 25).results
end
If you want to save tweets, create an action like this.
def save_tweets_into_database
#tweets = Twitter.search("#em2012" "#italy" "#spain", :lang => "en", :rpp => 25).results
#tweets.each do |tweet|
Tweet.save(tweet)
end
end
tweets_controller.rb:
class TweetsController < ApplicationController
def save_tweets_into_database
#tweets = Twitter.search("#em2012" "#Italy" "#Spain", :lang => "en", :rpp => 25)
#tweets.each do |tweet|
Tweet.create(twitter_tweet: tweet)
end
end
end
tweet.rb:
class Tweet < ActiveRecord::Base
serialize :twitter_tweet
end
Note that this requires you have a migration where a tweets table is created with a text column named 'twitter_tweet', e.g.
class CreateTweets < ActiveRecord::Migration
def change
create_table :tweets do |t|
t.text :twitter_tweets
t.timestamps
end
end
end
This will allow you to call save_tweets_into_database and save the 25 returned tweets into the database. This isn't a very good strategy, as you are serializing each of the Twitter::Status objects and storing them as YAML in your database. This means you lose the ability to use all the nice ActiveRecord helpers, and instead must deserialize all of the objects you want to work with before actually using them. A better strategy would be to create an ActiveRecord object that has the same attributes as those in the Twitter::Status object you wish to save. Then you can map the fetched Twitter::Status objects to the new ActiveRecord Tweet objects and retain all the benefits of using ActiveRecord.
I'll not say anything about your routing structure, other than it definitely doesn't appear to be following the 'Rails' way, which, from experience, typically leads to quite a few headaches.

ActiveRecord::Base Without Table

This came up a bit ago ( rails model attributes without corresponding column in db ) but it looks like the Rails plugin mentioned is not maintained ( http://agilewebdevelopment.com/plugins/activerecord_base_without_table ). Is there no way to do this with ActiveRecord as is?
If not, is there any way to get ActiveRecord validation rules without using ActiveRecord?
ActiveRecord wants the table to exist, of course.
This is an approach I have used in the past:
In app/models/tableless.rb
class Tableless < ActiveRecord::Base
def self.columns
#columns ||= [];
end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
sql_type.to_s, null)
end
# Override the save method to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end
In app/models/foo.rb
class Foo < Tableless
column :bar, :string
validates_presence_of :bar
end
In script/console
Loading development environment (Rails 2.2.2)
>> foo = Foo.new
=> #<Foo bar: nil>
>> foo.valid?
=> false
>> foo.errors
=> #<ActiveRecord::Errors:0x235b270 #errors={"bar"=>["can't be blank"]}, #base=#<Foo bar: nil>>
Validations are simply a module within ActiveRecord. Have you tried mixing them into your non-ActiveRecord model?
class MyModel
include ActiveRecord::Validations
# ...
end
I figure the more answers the better since this is one of the first results in google when searching for "rails 3.1 models without tables"
I've implements the same thing without using ActiveRecord::Base while including the ActiveRecord::Validations
The main goal was to get everything working in formtastic, and below I've included a sample payment that will not get saved anywhere but still has the ability to be validated using the validations we all know and love.
class Payment
include ActiveModel::Validations
attr_accessor :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state, :zip_code, :home_telephone, :email, :new_record
validates_presence_of :cc_number, :payment_type, :exp_mm, :exp_yy, :card_security, :first_name, :last_name, :address_1, :address_2, :city, :state
def initialize(options = {})
if options.blank?
new_record = true
else
new_record = false
end
options.each do |key, value|
method_object = self.method((key + "=").to_sym)
method_object.call(value)
end
end
def new_record?
return new_record
end
def to_key
end
def persisted?
return false
end
end
I hope this helps someone as I've spent a few hours trying to figure this out today.
UPDATE: For Rails 3 this can be done very easy. In Rails 3+ you can use the new ActiveModel module and its submodules. This should work now:
class Tableless
include ActiveModel::Validations
attr_accessor :name
validates_presence_of :name
end
For more info, you can check out the Railscast (or read about it on AsciiCasts) on the topic, as well as this blog post by Yehuda Katz.
OLD ANSWER FOLLOWS:
You may need to add this to the solution, proposed by John Topley in the previous comment:
class Tableless
class << self
def table_name
self.name.tableize
end
end
end
class Foo < Tableless; end
Foo.table_name # will return "foos"
This provides you with a "fake" table name, if you need one. Without this method, Foo::table_name will evaluate to "tablelesses".
Just an addition to the accepted answer:
Make your subclasses inherit the parent columns with:
class FakeAR < ActiveRecord::Base
def self.inherited(subclass)
subclass.instance_variable_set("#columns", columns)
super
end
def self.columns
#columns ||= []
end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
# Overrides save to prevent exceptions.
def save(validate = true)
validate ? valid? : true
end
end
This is a search form that presents an object called criteria that has a nested period object with beginning and end attributes.
The action in the controller is really simple yet it loads values from nested objects on the form and re-renders the same values with error messages if necessary.
Works on Rails 3.1.
The model:
class Criteria < ActiveRecord::Base
class << self
def column_defaults
{}
end
def column_names
[]
end
end # of class methods
attr_reader :period
def initialize values
values ||= {}
#period = Period.new values[:period] || {}
super values
end
def period_attributes
#period
end
def period_attributes= new_values
#period.attributes = new_values
end
end
In the controller:
def search
#criteria = Criteria.new params[:criteria]
end
In the helper:
def criteria_index_path ct, options = {}
url_for :action => :search
end
In the view:
<%= form_for #criteria do |form| %>
<%= form.fields_for :period do |prf| %>
<%= prf.text_field :beginning_as_text %>
<%= prf.text_field :end_as_text %>
<% end %>
<%= form.submit "Search" %>
<% end %>
Produces the HTML:
<form action="/admin/search" id="new_criteria" method="post">
<input id="criteria_period_attributes_beginning_as_text" name="criteria[period_attributes][beginning_as_text]" type="text">
<input id="criteria_period_attributes_end_as_text" name="criteria[period_attributes][end_as_text]" type="text">
Note: The action attribute provided by the helper and the nested attributes naming format that makes it so simple for the controller to load all the values at once
There is the activerecord-tableless gem. It's a gem to create tableless ActiveRecord models, so it has support for validations, associations, types. It supports Active Record 2.3, 3.0, 3.2
The recommended way to do it in Rails 3.x (using ActiveModel) has no support for associations nor types.

Resources