Ahoy visits not created with after_validation :geocode uncommented - ruby-on-rails

I have integrated Ahoy into our platform and it works great for tracking events etc. I am now trying to extend the functionality with enabling geocoding. The issue I am running into is as soon as I uncomment the
after_validation :geocode
line, visits stop recording in the database.
What am I doing wrong here?
visit.rb
class Ahoy::Visit < ActiveRecord::Base
self.table_name = "ahoy_visits"
# ahoy_visit
geocoded_by :ip
# after_validation :geocode
has_many :events, class_name: "Ahoy::Event"
belongs_to :user
end
ahoy.rb (note the short visit duration for testing):
class Ahoy::Store < Ahoy::DatabaseStore
end
# set to true for JavaScript tracking
Ahoy.api = true
# better user agent parsing
Ahoy.user_agent_parser = :device_detector
Ahoy.geocode = true
# Ahoy.server_side_visits = :when_needed
Ahoy.visit_duration = 10.seconds
# Ahoy.visit_duration = Rails.application.secrets.visit_duration
Ahoy.quiet = false
geocoder.rb
Geocoder.configure(
# Geocoding options
timeout: 15, # geocoding service timeout (secs)
lookup: :google, # name of geocoding service (symbol)
:ip_lookup => :maxmind, # IP address geocoding service (see below for supported options):
language: :en, # ISO-639 language code
use_https: true, # use HTTPS for lookup requests? (if supported)
# http_proxy: nil, # HTTP proxy server (user:pass#host:port)
# https_proxy: nil, # HTTPS proxy server (user:pass#host:port)
api_key: Rails.application.secrets.google_server_api_key, # API key for geocoding service
# cache: nil, # cache object (must respond to #[], #[]=, and #keys)
# cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
# Exceptions that should not be rescued by default
# (if you want to implement custom error handling);
# supports SocketError and Timeout::Error
# always_raise: [],
# Calculation options
units: :km, # :km for kilometers or :mi for miles
# distances: :linear # :spherical or :linear
)
To re-iterate, when I comment out the geocoding line visits are recorded properly and ahoy works as expected.
Thanks.
EDIT
I am certain there is an exception being thrown but it is not bubbling up in the logs and I have debug logging enabled. Ahoy just states that "[ahoy] Event excluded since visit not created:" yet on the UI we can see that a visit is being started via these log statements from ahoy:
Visit started
ahoy.self-01ef77de70801670c1f7f2f12fea979d59ba70488a77db75270b57ec5b1a2f8e.js?body=1:175
{visit_token: "4c7e0bcb-7afb-48cd-91ed-1bdf0d614767", visitor_token:
"374bf981-d843-45c3-953d-0f0b8fd5a6a7", platform: "Web", landing_page:
"http://localhost:3000/", screen_width: 1680, …}
ahoy.self-01ef77de70801670c1f7f2f12fea979d59ba70488a77db75270b57ec5b1a2f8e.js?body=1:175
{name: "$click", properties: {…}, time: 1533656941.084, id:
"c967b67f-96f7-4f18-a9a8-df3735fdc1c2", js: true}

Related

Can't connect to clustered Azure Redis Cache with redis-rb gem and public access

We've provisioned an Azure Redis Cache server using the Premium tier. The server is clustered, with 2 shards, and the server is configured to allow public access over the public internet through a firewall--allow-listing a set of known IPs.
Deploys of our Rails application two any of these known IPs fail with the error:
Redis::CannotConnectError: Redis client could not connect to any cluster nodes
Here is our Rails config:
# application.rb
if Rails.env.test?
config.cache_store = :redis_cache_store, {
url: config.nines[:redis_url],
expires_in: 90.minutes,
namespace: ENV['TEST_ENV_NUMBER'],
}
else
config.cache_store = :redis_store, {
namespace:ENV['TEST_ENV_NUMBER'],
cluster: [ Rails.application.config.nines[:redis_url] ],
replica: true, # allow reads from replicas
compress: true,
compress_threshold: 1024,
expires_in: 90.minutes
}
end
The config.nines[:redis_url] is set like this: rediss://:<pw>#<cache-name>.redis.cache.windows.net:6380/0
Then, we initialize the Redis connection in code like this:
if Rails.env.test?
::Redis.new :url => redis_url, :db => ENV['REDIS_DB']
else
::Redis.new(cluster: [ "#{redis_url}" ], db: ENV['REDIS_DB'])
end
We're using the redis-rb gem and redis-rails gem.
If anyone can point out what we're doing wrong, please do share!
Thank you User Peter Pan - Stack Overflow. Posting your suggestion as answer to help other community members.
You can try below code:
# Import the redis library for Ruby
require "redis"
# Create a redis client instance for connecting Azure Redis Cache
# At here, for enabling SSL, set the `:ssl` symbol with the
# symbol value `:true`, see https://github.com/redis/redis-rb#ssltls-support
redis = Redis.new(
:host => '<azure redis cache name>.redis.cache.windows.net',
:port => 6380,
:db => <the db index you selected like 10>,
:password => "<access key>",
:ssl => :true)
# Then, set key `foo` with value `bar` and return `OK`
status = redis.set('foo', 'bar')
puts status # => OK
# Get the value of key `foo`
foo = redis.get('foo')
puts foo # => bar
Reference: How to setup Azure Redis cache with Rails - Stack Overflow

Existence of ActiveModel::SecurePassword authenticate method (Rails 6)

The "authenticate" method can only be found here: https://apidock.com/rails/ActiveModel/SecurePassword/InstanceMethodsOnActivation/authenticate
, with version 6.0.0 being grayed out. So this seems to be outdated.
I have searched the Rails 6 documentation for the authenticate method, and found no record of it under https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html.
Yet in the code snippet on the same page
# Schema: User(name:string, password_digest:string, recovery_password_digest:string)
class User < ActiveRecord::Base
has_secure_password
has_secure_password :recovery_password, validations: false
end
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save # => true
user.recovery_password = "42password"
user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
user.save # => true
user.authenticate('notright') # => false
user.authenticate('mUc3m00RsqyRe') # => user
user.authenticate_recovery_password('42password') # => user
User.find_by(name: 'david')&.authenticate('notright') # => false
User.find_by(name: 'david')&.authenticate('mUc3m00RsqyRe') # => user
The authenticate method is still used (user.authenticate). Where does this method come from if I can't find it in the latest documentation?
Edit:
A related question regarding differences in documentation: I am able to find ActionDispatch::Request::Session on rubydocs but not on api.rubyonrails.
https://www.rubydoc.info/docs/rails/ActionDispatch/Request/Session
https://api.rubyonrails.org/classes/ActionDispatch/Request.html
Now I am not certain where I should be looking when searching for methods. Is api.rubyonrails not the "definitive" place to look for documentation?
It looks like they forgot to mention it in the documentation for has_secure_password. If you look into source code of ActiveModel::SecurePassword. You will find
# Returns +self+ if the password is correct, otherwise +false+.
#
# class User < ActiveRecord::Base
# has_secure_password validations: false
# end
#
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
# user.save
# user.authenticate_password('notright') # => false
# user.authenticate_password('mUc3m00RsqyRe') # => user
define_method("authenticate_#{attribute}") do |unencrypted_password|
attribute_digest = public_send("#{attribute}_digest")
BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
end
alias_method :authenticate, :authenticate_password if attribute == :password
You can se it is now defined as dynamic method based on the parametr name provided to has_secure_password method. So they implemented it in more general way. And to be more friendly with backwards compatibility the implemented the alias authenticate for authenticate_password which was the original implementation.
Unfortunately these dynamic methods are not very well documented in the rails API docs.

Ruby Geocoder connection refused

When I search for an IP address, I get the following error:
pry(main)> Geocoder.search("130.132.173.68")
Geocoding API connection refused.
=> []
If I search for anything else eg.
pry(main)> Geocoder.search("new haven")
I get the correct results.
Is there a problem with the freegeoip service?
Make sure you have an initializer setup for Geocoder with all of the config settings. This was the problem for me. Something along the lines like this:
# config/initializers/geocoder.rb
Geocoder.configure(
# geocoding options
:timeout => 7, # geocoding service timeout (secs)
:lookup => :google, # name of geocoding service (symbol)
:language => :en, # ISO-639 language code
:use_https => true, # use HTTPS for lookup requests? (if supported)
:http_proxy => '', # HTTP proxy server (user:pass#host:port)
:https_proxy => '', # HTTPS proxy server (user:pass#host:port)
:api_key => nil, # API key for geocoding service
:cache => nil, # cache object (must respond to #[], #[]=, and #keys)
:cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
# IP address geocoding service (see below for supported options):
#:ip_lookup => :maxmind,
# to use an API key:
#:api_key => "...",
# exceptions that should not be rescued by default
# (if you want to implement custom error handling);
# supports SocketError and TimeoutError
# :always_raise => [],
# calculation options
# :units => :mi, # :km for kilometers or :mi for miles
# :distances => :linear # :spherical or :linear
)

spree_chimpy:merge_vars:sync rake aborted

I am installing the gem spree_chimpy from https://github.com/watg/spree_chimpy in my Ruby on Rails application with spree. After doing mailchimp setup I am notifying mailchimp about merge_vars which seem to cause the error. When I run the command
rake spree_chimpy:merge_vars:sync --trace
I get the error "tag" must be 10 bytes and may only contain "A-Z 0-9 _. I don't understand the error, I have nowhere added any tag variable in the configuration. For reference, my config/initializers/spree_chimpy.rb is pasted here:
Spree::Chimpy.config do |config|
# your API key as provided by MailChimp
config.key = '<#my-api-hash-key>'
# extra api options for the Mailchimp gem
# config.api_options = { throws_exceptions: false, timeout: 3600 }
# name of your list, defaults to "Members"
config.list_name = 'test'
# Allow users to be subscribed by default. Defaults to false
# If you enable this option, it's strongly advised that your enable
# double_opt_in as well. Abusing this may cause Mailchimp to suspend your account.
# config.subscribed_by_default = false
# When double-opt is enabled, the user will receive an email
# asking to confirm their subscription. Defaults to false
config.double_opt_in = false
# id of your store. max 10 letters. defaults to "spree"
# config.store_id = 'acme'
# define a list of merge vars:
# - key: a unique name that mail chimp uses. 10 letters max
# - value: the name of any method on the user class.
# default is {'EMAIL' => :email}
config.merge_vars = {
'EMAIL' => :email,
'FNAME' => :fname,
'LNAME' => :lname,
'ORDERNUMBER' => :onumber
}
end
That error is being thrown is from somewhere around here:
https://github.com/watg/spree_chimpy/blob/7ba5d855112050e1b61c2d0a3369bc08f254842d/lib/spree_chimpy.rb#L59-L62
The actual error is within the mailchimp API client. You're getting the error because ORDERNUMBER has 11 characters in it. If you trim it down to 10 characters, you should be okay.

How to "crawl" only the root URL with Anemone?

In the example below I would like anemone to only execute on the root URL (example.com). I am unsure if I should apply the on_page_like method and if so what pattern I would need.
require 'anemone'
Anemone.crawl("http://www.example.com/") do |anemone|
anemone.on_pages_like(???) do |page|
# some code to execute
end
end
require 'anemone'
Anemone.crawl("http://www.example.com/", :depth_limit => 1) do |anemone|
# some code to execute
end
You can also specify the following in the options hash, below are the defaults:
# run 4 Tentacle threads to fetch pages
:threads => 4,
# disable verbose output
:verbose => false,
# don't throw away the page response body after scanning it for links
:discard_page_bodies => false,
# identify self as Anemone/VERSION
:user_agent => "Anemone/#{Anemone::VERSION}",
# no delay between requests
:delay => 0,
# don't obey the robots exclusion protocol
:obey_robots_txt => false,
# by default, don't limit the depth of the crawl
:depth_limit => false,
# number of times HTTP redirects will be followed
:redirect_limit => 5,
# storage engine defaults to Hash in +process_options+ if none specified
:storage => nil,
# Hash of cookie name => value to send with HTTP requests
:cookies => nil,
# accept cookies from the server and send them back?
:accept_cookies => false,
# skip any link with a query string? e.g. http://foo.com/?u=user
:skip_query_strings => false,
# proxy server hostname
:proxy_host => nil,
# proxy server port number
:proxy_port => false,
# HTTP read timeout in seconds
:read_timeout => nil
My personal experience is that Anemone was not very fast and had a lot of corner cases. The docs are lacking (as you have experienced) and the author doesn't seem to be maintaining the project. YMMV. I tried Nutch shortly but didn't play aroud as much but it seemed faster. No benchmarks, sorry.

Resources