This is based on an earlier question that was resolved. I need to load sale prices for my ruby-based app in different currencies. I was recently using the gem google_currency to convert the prices based on the Google API. At some point recently it stopped working and I have no idea why. I have tried testing in various ways but can't work out what the problem is.
I am now trying to use the 'exchange' gem which has good documentation however the method I am using is not producing anything in the view files when running.
According to the exchange gem the simple conversion should be something like:
def exchange4
puts 10.in(:eur).to(:usd)
end
However it is not loading anything in the html view. Any suggestions including other working gems welcome!
Currently this code seems like it would pass however now Action Controller is telling me it doesn't know the conversion rates:
def exchange4(goods)
require 'money'
require 'money-rails'
exr = Money.new(1, goods.currency).exchange_to(buyer.currency)
puts exr
end
The error Action Controller is giving is:
No conversion rate known for 'GBP' -> 'EUR'
Very strange..
RubyMoney organization has a very good options to deal with currencies, money and exchange. I use money and it really works. For Rails integration they have money-rails.
Examples of exchange:
Money.us_dollar(100).exchange_to('EUR')
Money.new(100, 'USD').exchange_to('EUR')
You can use eu_central_bank gem (compatible with money) to extract all exchange rates. Example usage (in rails console):
>> bank = EuCentralBank.new
>> bank.update_rates # if bank.last_updated.blank? || bank.last_updated < 1.day.ago
>> Money.default_bank = bank
Then:
>> Money.new(1, 'GBP').exchange_to('EUR')
=> #<Money fractional:1 currency:EUR>
Related
I am trying to use the google-ads-ruby library to allow our ruby on rails application users to connect our app with Google Ads and pull some stats from their account for them.
I installed the gem and managed to authenticate a user and get the refresh_token.
Now I'm trying to start collecting data from Google.
The first thing that fails is their instructions to require the gem in my code with require 'google/ads/google_ads'
I tried adding it to my controller and got cannot load such file -- google/ads/google_ads
Then, according to their instructions, I should be able to run this:
client = Google::Ads::GoogleAds::GoogleAdsClient.new do |config|
config.client_id = Rails.application.secrets.google_oauth_client_id
config.client_secret = Rails.application.secrets.google_oauth_client_secret
config.developer_token = Rails.application.secrets.google_developer_token
config.refresh_token = #user.google_ads.refresh_token
end
accessible_customers = client.service.customer.list_accessible_customers().resource_names
accessible_customers.each do |resource_name|
puts "Customer resource name: #{resource_name}"
end
and then list, for example, the user's accounts, as described here.
However, I am getting uninitialized constant Google::Ads::GoogleAds
Does anyone know what is going on?
Have you tried?
client = ::Google::Ads::GoogleAds::GoogleAdsClient.new do |config|
config.client_id = Rails.application.secrets.google_oauth_client_id
config.client_secret = Rails.application.secrets.google_oauth_client_secret
config.developer_token = Rails.application.secrets.google_developer_token
config.refresh_token = #user.google_ads.refresh_token
end
This is not really an answer to my question. I was unable to find a solution, but doing some more digging, I found the AdsWords on Rails example app Google added to that same gem and the documentation
The app is slightly outdated and you will probably hate getting it to work. Also, it's written in a very cryptic way and includes so many functions just to use their API... but I was able to make it work. To be honest, someone should write a tutorial.
Hope this may give some clues to someone who's lost at some point.
I have a typical Rails REST Api written for a http consumers. However, it turns out they need web socket API because of the integration POS Machines.
The typical API looks like this;
class Api::Pos::V1::TransactionsController < ApplicationController
before_action :authenticate
def index
#transactions = #current_business.business_account.business_deposits.last(5)
render json: {
status: 200,
number: #transactions.count,
transactions: #transactions.as_json(only: [:created_at, :amount, :status, :client_card_number, :client_phone_number])
}
end
private
def request_params
params.permit(:account_number, :api_key)
end
def authenticate
render status: 401, json: {
status: 401,
error: "Authentication Failed."
} unless current_business
end
def current_business
account_number = request_params[:account_number].to_s
api_key = request_params[:api_key].to_s
if account_number and api_key
account = BusinessAccount.find_by(account_number: account_number)
if account && Business.find(account.business_id).business_api_key.token =~ /^(#{api_key})/
#current_business = account.business
else
false
end
end
end
end
How can i serve the same responses using web-sockets?
P.S: Never worked with sockets before
Thank you
ActionCable
I would second Dimitris's reference to ActionCable, as it's expected to become part of Rails 5 and should (hopefully) integrate with Rails quite well.
Since Dimitris suggested SSE, I would recommend against doing so.
SSE (Server Sent Events) use long polling and I would avoid this technology for many reasons which include the issue of SSE connection interruptions and extensibility (websockets allow you to add features that SSE won't support).
I am almost tempted to go into a rant about SSE implementation performance issues, but... even though websocket implementations should be more performant, many of them suffer from similar issues and the performance increase is often only in thanks to the websocket connection's longer lifetime...
Plezi
Plezi* is a real-time web application framework for Ruby. You can either use it on it's own (which is not relevant for you) or together with Rails.
With only minimal changes to your code, you should be able to use websockets to return results from your RESTful API. Plezi's Getting Started Guide has a section about unifying the backend's RESTful and Websocket API's. Implementing it in Rails should be similar.
Here's a bit of Demo code. You can put it in a file called plezi.rb and place it in your application's config/initializers folder...
Just make sure you're not using any specific Servers (thin, puma, etc'), allowing Plezi to override the server and use the Iodine server, and remember to add Plezi to your Gemfile.
class WebsocketDemo
# authenticate
def on_open
return close unless current_business
end
def on_message data
data = JSON.parse(data) rescue nil
return close unless data
case data['msg']
when /\Aget_transactions\z/i
# call the RESTful API method here, if it's accessible. OR:
transactions = #current_business.business_account.business_deposits.last(5)
write {
status: 200,
number: transactions.count,
# the next line has what I think is an design flaw, but I left it in
transactions: transactions.as_json(only: [:created_at, :amount, :status, :client_card_number, :client_phone_number])
# # Consider, instead, to avoid nesting JSON streams:
# transactions: transactions.select(:created_at, :amount, :status, :client_card_number, :client_phone_number)
}.to_json
end
end
# don't disclose inner methods to the router
protected
# better make the original method a class method, letting you reuse it.
def current_business
account_number = params[:account_number].to_s
api_key = params[:api_key].to_s
if account_number && api_key
account = BusinessAccount.find_by(account_number: account_number)
if account && Business.find(account.business_id).business_api_key.token =~ /^(#{api_key})/
return (#current_business = account.business)
end
false
end
end
end
Plezi.route '/(:api_key)/(:account_number)', WebsocketDemo
Now we have a route that looks something like: wss://my.server.com/app_key/account_number
This route can be used to send and receive data in JSON format.
To get the transaction list, the client side application can send:
JSON.stringify({msg: "get_transactions"})
This will result in data being send to the client's websocket.onmessage callback with the last five transactions.
Of course, this is just a short demo, but I think it's a reasonable proof of concept.
* I should point out that I'm biased, as I'm Plezi's author.
P.S.
I would consider moving the authentication into a websocket "authenticate" message, allowing the application key to be sent in a less conspicuous manner.
EDIT
These are answers to the questions in the comments.
Capistrano
I don't use Capistrano, so I'm not sure... but, I think it would work if you add the following line to your Capistrano tasks:
Iodine.protocol = false
This will prevent the server from auto-starting, so your Capistrano tasks flow without interruption.
For example, at the beginning of the config/deploy.rb you can add the line:
Iodine.protocol = false
# than the rest of the file, i.e.:
set :deploy_to, '/var/www/my_app_name'
#...
You should also edit your rakefile and add the same line at the beginning of the rakefile, so your rakefile includes the line:
Iodine.protocol = false
Let me know how this works. Like I said, I don't use Capistrano and I haven't tested it out.
Keeping Passenger using a second app
The Plezi documentation states that:
If you really feel attached to your thin, unicorn, puma or passanger server, you can still integrate Plezi with your existing application, but they won't be able to share the same process and you will need to utilize the Placebo API (a guide is coming soon).
But the guide isn't written yet...
There's some information in the GitHub Readme, but it will be removed after the guide is written.
Basically you include the Plezi application with the Redis URL inside your Rails application (remember to make sure to copy all the gems used in the gemfile). than you add this line:
Plezi.start_placebo
That should be it.
Plezi will ignore the Plezi.start_placebo command if there is no other server defined, so you can put the comment in a file shared with the Rails application as long as Plezi's gem file doesn't have a different server.
You can include some or all of the Rails application code inside the Plezi application. As long as Plezi (Iodine, actually) is the only server in the Plezi GEMFILE, it should work.
The applications will synchronize using Redis and you can use your Plezi code to broadcast websocket events inside your Rails application.
You may want to have a look at https://github.com/rails/actioncable which is the Rails way to deal with WebSockets, but currently in Alpha.
Judging from your code snippet, the client seems to only consume data from your backend. I'm skeptical whether you really need WebSockets. Ιf the client won't push data back to the server, Server Sent Events seem more appropriate.
See relevant walk-through and documentation.
I've tried a handful of captchas for Rails 3 and none tend to play nicely with Mongoid. I don't need anything too fancy just something to do a quick human check.
How do you guys get one working with Mongoid? Are there alternative solutions?
That's outside mongoid scope, but still applicable. Have a look at Negative Captcha:
Negative captchas create a form that has tasks that only bots can perform, but humans cannot. This has the exact same effect, with (anecdotally) a much lower false positive identification rate when compared with positive captchas. All of this comes without making humans go through any extra trouble to submit the form. It really is win-win.
You can use simple-captcha v1rtual's branch with mongo support. Simple and clean setup and usage:
Just add to your Gemfile as:
gem 'wolcanus-simple_captcha', :require => 'simple_captcha', :git => 'git://github.com/v1rtual/simple-captcha.git'
Run generator:
rails generate simple_captcha
For Controller Based, add the following line in the file "app/controllers/application.rb":
ApplicationController < ActionController::Base
include SimpleCaptcha::ControllerHelpers
end
In the view file within the form tags add this code:
<%= show_simple_captcha %>
and in the controller’s action authenticate it as
if simple_captcha_valid?
do this
else
do that
end
See the branch for more options: https://github.com/v1rtual/simple-captcha
I am using the linkedin gem https://github.com/pengwynn/linkedin
I authorize using Omniauth and store the access token and secrets.
I then authorize by access with the client.
I appear to get something useful when I type client.profile -- but it looks like mostly Nokogiri but in a LinkedIn::Profile class.
How do I specifically access fields, and will I be able to use method calls from the View in rails or do I need to do all the parsing in the controller and pass those values to the View from there.
Example of how to access the profile image url, title, name, company that sort of thing once I have established client.profile would be great.
When I use the (:fields =>) I get back something like this:
#<LinkedIn::Profile:0xb682c72c #doc=#<Nokogiri::XML::Document:0x..fdb41630a name="document" children=[#<Nokogiri::XML::Element:0x..fdb415fae name="person" children=[#<Nokogiri::XML::Text:0x..fdb415d88 "\n ">, #<Nokogiri::XML::Element:0x..fdb415d24 name="picture-url" children=[#<Nokogiri::XML::Text:0x..fdb415aae "http://media.linkedis:
I just want the string associated with the node "picture-url"...how do I do that?
From controller:
7 `def show`
8 #user = User.find(params[:id])
9 #client = LinkedIn::Client.new(ENV["LINKEDIN_KEY"], ENV["LINKEDIN_SECRET"])
10 #client.authorize_from_access(#user.atoken, #user.asecret)
11 #client.profile(:id => #user.uid, :fields => ["picture-url", "headline"])
12
13 end
New error:
undefined method `downcase' for nil:NilClass
Here is a related question: "https://stackoverflow.com/questions/5821549/how-do-i-pass-a-a-tag-through-ruby-to-linkedin-using-the-gem"
I did it by adding:
client.profile(:fields => [:positions]).positions
This would then allow me to access specific positions or fields without going into the raw xml, just using the methods in the gem. The gem works nicely once I get the format...
I suggest you get the latest version of linked_in gem from github. It uses Hashie/Mashie syntax which is much simpler than dealing with Nokogiri output and XPath.
If youre using bundler add this to your Gemfile(removing any other linked_in gem reference)
gem 'linkedin', :git => "git://github.com/pengwynn/linkedin.git"
this version of the gem basically sticks the output of your Linked In search into a hash, so you would access your picture-url string as follows: profileHash["picture-url"]
P.S. if you do decide to stick with your version of linked_in gem, get familiarized with XPath syntax, you will need it. Based on the information you provided, the picture url string will be available via profileXML.xpath("//person/picture-url").first.text
I need to parse thousands of feeds and performance is an essential requirement. Do you have any suggestions?
Thanks in advance!
I haven't tried it, but I read about Feedzirra recently (it claims to be built for performance) :-
Feedzirra is a feed library that is
designed to get and update many feeds
as quickly as possible. This includes
using libcurl-multi through the
taf2-curb gem for faster http gets,
and libxml through nokogiri and
sax-machine for faster parsing.
You can use RFeedParser, a Ruby-port of (famous) Python Universal FeedParser. It's based on Hpricot, and it's really fast and easy to use.
http://rfeedparser.rubyforge.org/
An example:
require 'rubygems'
require 'rfeedparser'
require 'open-uri'
feed = FeedParser::parse(open('http://feeds.feedburner.com/engadget'))
feed.entries.each do |entry|
puts entry.title
end
When all you have is a hammer, everything looks like a nail. Consider a solution other than Ruby for this. Though I love Ruby and Rails and would not part with them for web development or perhaps for a domain specific language, I prefer heavy data lifting of the type you describe be performed in Java, or perhaps Python or even C++.
Given that the destination of this parsed data is likely a database it can act as the common point between the Rails portion of your solution and the other language portion. Then you're using the best tool to solve each of your problems and the result is likely easier to work on and truly meets your requirements.
If speed is truly of the essence, why add an additional constraint on there and say, "Oh, it's only of the essence as long as I get to use Ruby."
Not sure about the performance, but a similar question was answered at Parsing Atom & RSS in Ruby/Rails?
You might also look into Hpricot, which parses XML but assumes that it's well-formed and doesn't do any validation.
http://wiki.github.com/why/hpricot
http://wiki.github.com/why/hpricot/hpricot-xml
initially i used nokogiri to do some basic xml parsing, but it was slow and erratic (at times) i switched to feedzirra and not only was there a great performance boost, there were no errors and its as easy as pie.
Example shown below
# fetching a single feed
feed = Feedzirra::Feed.fetch_and_parse("http://feeds.feedburner.com/PaulDixExplainsNothing")
# feed and entries accessors
feed.title # => "Paul Dix Explains Nothing"
feed.url # => "http://www.pauldix.net"
feed.feed_url # => "http://feeds.feedburner.com/PaulDixExplainsNothing"
feed.etag # => "GunxqnEP4NeYhrqq9TyVKTuDnh0"
feed.last_modified # => Sat Jan 31 17:58:16 -0500 2009 # it's a Time object
entry = feed.entries.first
entry.title # => "Ruby Http Client Library Performance"
entry.url # => "http://www.pauldix.net/2009/01/ruby-http-client-library-performance.html"
entry.author # => "Paul Dix"
entry.summary # => "..."
entry.content # => "..."
entry.published # => Thu Jan 29 17:00:19 UTC 2009 # it's a Time object
entry.categories # => ["...", "..."]
if you want to do more with the feeds, for example parsing them, the following will suffice
source = Feedzirra::Feed.fetch_and_parse(http://www.feed-url-you-want-to-play-with.com)
puts "Parsing Downloaded XML....\n\n\n"
source.entries.each do |entry|
begin
puts "#{entry.summary} \n\n"
cleanURL = (entry.url).gsub("+","%2B") #my own sanitization process, ignore
scrapArticleWithURL(cleanURL)
rescue
puts "(****)there has been an error fetching (#{entry.title}) \n\n"
end