How to configure a dynamodb in rails? - ruby-on-rails

In rails 5, I need to configure the dynamodb feature. I have referred some blogs and tried to implement it. First in localhost it was running without any issue, but when I move to other new system or a server then it is showing an error like,
/home/NICHEPRO/shruthir/.rvm/gems/ruby-2.4.0/gems/aws-sdk-core-2.10.19/lib/aws-sdk-core/plugins/regional_endpoint.rb:34:in `after_initialize': missing region; use :region option or export region name to ENV['AWS_REGION'] (Aws::Errors::MissingRegionError)
from /home/NICHEPRO/shruthir/.rvm/gems/ruby-2.4.0/gems/aws-sdk-core-2.10.19/lib/seahorse/client/base.rb:84:in `block in after_initialize'
AWS gem is,
aws-sdk (2.10.19)
aws-sdk-core (2.10.19)
aws-sdk-resources (2.10.19)
Referred From:
https://assist-software.net/snippets/how-save-data-amazon-dynamodb-using-ruby-on-rails
Also I have tried to fix this by referring other blogs but I will get below error too,
Failed to open TCP connection to localhost:8080 (Connection refused - connect(2) for "localhost" port 8080)
How to solve this issue?

Hope you are using Dynamoid gem. In app/config/initializer add a new config file and add below code.
Dynamoid.configure do |config|
config.adapter = 'aws_sdk_v2' # This adapter establishes a connection to the DynamoDB servers using Amazon's own AWS gem.
config.access_key = (ENV['AWS_ACCESS_KEY_ID'] || APP_CONFIG[:aws_access_key_id])
config.secret_key = (ENV['AWS_SECRET_ACCESS_KEY'] || APP_CONFIG[:aws_secret_access_key])
config.region = (ENV['AWS_REGION'] || 'us-east-1')
config.namespace = nil # To namespace tables created by Dynamoid from other tables you might have. Set to nil to avoid namespacing.
config.warn_on_scan = true # Output a warning to the logger when you perform a scan rather than a query on a table.
config.read_capacity = 100 # Read capacity for your tables
config.write_capacity = 200 # Write capacity for your tables
config.endpoint = (ENV['DYNAMO_ENDPOINT'] || APP_CONFIG[:dynamo_endpoint]) # [Optional]. If provided, it communicates with the DB listening at the endpoint. This is useful for testing with [Amazon Local DB] (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html).
end
Make sure you update your ENV variables. Or if you connect directly to AWS instead of Dynamoid gem just follow...
def client
#client ||= Aws::DynamoDB::Client.new(
access_key_id: (ENV['AWS_ACCESS_KEY_ID'] || APP_CONFIG[:aws_access_key_id]),
secret_access_key: (ENV['AWS_SECRET_ACCESS_KEY'] || APP_CONFIG[:aws_secret_access_key]),
region: (ENV['AWS_REGION'] || 'us-east-1'),
endpoint: (ENV['DYNAMO_ENDPOINT'] || APP_CONFIG[:dynamo_endpoint])
)
end
and do a query like this
client.query(
table_name: table_name,
select: 'COUNT',
expression_attribute_values: {
':v1' => index
},
key_condition_expression: 'user_id = :v1'
).count
For more info http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/DynamoDB.html

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

Write adapter for microsoft azure in sitemap_generator

I am using sitemap_generator for generating sitemaps in my RoR project.Everything is working fine till now.I am hosting my project on Heroku, which doesn't allow writing to the local filesystem.I still require some write access, because the sitemap files need to be written out before uploading. But I have to use microsoft azure to store my sitemap.The adapters listed in sitemap_generator does not include azure.Could someone point me in the right direction for writing an adapter for azure.
Refering to "Configure carrierwave" in this article I have made a few changes in my code.
But I am not sure only editing the initialiazer file is going to help.In the above article Carrierwave points to the WaveAdapter here which uses CarrierWave::Uploader::Base to upload to any service supported by CarrierWave
config/initializers/azure.rb
Azure.configure do |config|
config.cache_dir = "#{Rails.root}/tmp/"
config.storage = :microsoft_azure
config.permissions = 0666
config.microsoft_azure_credentials = {
:provider => 'azure',
:storage_account_name => 'your account name',
:storage_access_key => 'your key',
}
config.azure_directory = 'container name'
end
Please help!
I copied my setup from the S3 adapter and from Azure's ruby example
Add the azure blob gem to your Gemfile:
gem 'azure-storage-blob'
create config/initializers/sitemap_generator/azure_adapter.rb:
require 'azure/storage/blob'
module SitemapGenerator
# Class for uploading sitemaps to Azure blobs using azure-storage-blob gem.
class AzureAdapter
#
# #option :storage_account_name [String] Your Azure access key id
# #option :storage_access_key [String] Your Azure secret access key
# #option :container [String]
def initialize
#storage_account_name = 'your account name'
#storage_access_key = 'your key'
#container = 'your container name (created already in Azure)'
end
# Call with a SitemapLocation and string data
def write(location, raw_data)
SitemapGenerator::FileAdapter.new.write(location, raw_data)
credentials = {
storage_account_name: #storage_account_name,
storage_access_key: #storage_access_key
}
client = Azure::Storage::Blob::BlobService.create(credentials)
container = #container
content = ::File.open(location.path, 'rb') { |file| file.read }
client.create_block_blob(container, location.filename, content)
end
end
end
Make sure the container you create in Azure is a 'blob' container so the container is not public but the blobs within are.
and then in config/sitemaps.rb:
SitemapGenerator::Sitemap.sitemaps_host = 'https://[your-azure-address].blob.core.windows.net/'
SitemapGenerator::Sitemap.sitemaps_path = '[your-container-name]/'
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AzureAdapter.new
That should do it!

Aws::S3::Presigner undefined method credentials for nil:NilClass in Ruby

i have use aws-sdk-core gem i am getting error during getting url form aws
following is my code
def initialize(bucket:, region:)
#bucket = bucket
client = Aws::S3::Client.new(region: region)
#signer = Aws::S3::Presigner.new(client: client)
end
def sign(key, expires_in: 3600)
#signer.presigned_url(:get_object, bucket: #bucket, key: key, expires_in: expires_in)
end
i am getting error
NoMethodError - undefined method `credentials' for nil:NilClass:
aws-sdk-core (2.1.15) lib/aws-sdk-core/signers/v4.rb:24:in `initialize'
aws-sdk-core (2.1.15) lib/aws-sdk-core/s3/presigner.rb:88:in `block in sign_but_dont_send'
If anyone known how get presigned url please lets us known
Thanks
The unhelpful error message indicates that you have not configured AWS credentials. These are need to generate the signature. If you had used the client to send a request you would have gotten a more helpful error message indicating that credentials were required.
def initialize(bucket:, region:)
#bucket = bucket
creds = Aws::Credentials.new('ACCESS_KEY', 'SECRET_ACCESS_KEY')
client = Aws::S3::Client.new(region: region, credentials, creds)
#signer = Aws::S3::Presigner.new(client: client)
end
def sign(key, expires_in: 3600)
#signer.presigned_url(:get_object, bucket: #bucket, key: key, expires_in: expires_in)
end
Not related to your problem, but you can use the resource interface for S3 which cleans up the code a bit.
def initialize(bucket:, region:)
#bucket = Aws::S3::Bucket.new(bucket, {
region: region,
credentials: Aws::Credentials.new('ACCESS_KEY', 'SECRET_ACCESS_KEY'),
})
end
def sign(key, expires_in: 3600)
#bucket.object(key).presigned_url(:get, expires_in: expires_in)
end
While I showed how to configure credentials in code, I strongly recommend against this. You should export credentials to ENV before launching your applications or put them in the shared credentials file.
$ export AWS_ACCESS_KEY_ID=...
$ export AWS_SECRET_ACCESS_KEY=...
Or put the following in ~/.aws/credentials
[default]
aws_access_key_id=...
aws_secret_access_key=...
If you use the ENV or shared credentials file, then you no longer need to configure them in code. The SDK will attempt to source these locations when they are not given to the client constructor.

undefined method: connect_timeout

Browser error:
NoMethodError
undefined method `connect_timeout=' for #<Mysql2::Client:0x47f7570>
On my browser, an error comes up that connect_timeout is undefined. I'm pretty sure it has something to do with the client.rb file. I'll show you the file. I had to edit some of it to actually get Webrick up and running. When I started the server, an error always appeared on my command line unless I made the changes. I've commented on what I have edited. Sometimes edited random things and some of them worked but they produced different errors on my browser. I am using a windows 8 machine. Thank you for helping.
module Mysql2
class Client
attr_reader :query_options, :read_timeout
##default_query_options = {
:as => :hash, # the type of object you want each row back as; also supports :array (an array of values)
:async => false, # don't wait for a result after sending the query, you'll have to monitor the socket yourself then eventually call Mysql2::Client#async_result
:cast_booleans => false, # cast tinyint(1) fields as true/false in ruby
:symbolize_keys => false, # return field names as symbols instead of strings
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
:cache_rows => true, # tells Mysql2 to use it's internal row cache for results
#:connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION,
#I had to delete the line above because for some reason the command prompt said that each of the constants were undefined were not used in the right place or something
:cast => true,
:default_file => nil,
:default_group => nil
}
def initialize (opts = {})
opts = Mysql2::Util.key_hash_as_symbols( opts )
#read_timeout = nil
#query_options = ##default_query_options.dup
#query_options.merge! opts
#initialize_ext
# the chrome page said that the above variable is undefined :P
# Set default connect_timeout to avoid unlimited retries from signal interruption
opts[:connect_timeout] = 120 unless opts.key?(:connect_timeout)
[:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout, :default_file, :default_group, :secure_auth, :init_command].each do |key|
next unless opts.key?(key)
case key
when :reconnect, :local_infile, :secure_auth
send(:"#{key}=", !!opts[key])
when :connect_timeout, :read_timeout, :write_timeout
send(:"#{key}=", opts[key].to_i)
else
send(:"#{key}=", opts[key])
end
end
# force the encoding to utf8
self.charset_name = opts[:encoding] || 'utf8'
ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
ssl_set(*ssl_options) if ssl_options.any?
if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| #query_options.has_key?(k) }
warn "============= WARNING FROM mysql2 ============="
warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future."
warn "Instead, please use :username, :password, :host, :port, :database, :socket, :flags for the options."
warn "============= END WARNING FROM mysql2 ========="
end
user = opts[:username] || opts[:user]
pass = opts[:password] || opts[:pass]
host = opts[:host] || opts[:hostname]
port = opts[:port]
database = opts[:database] || opts[:dbname] || opts[:db]
socket = opts[:socket] || opts[:sock]
flags = opts[:flags] ? opts[:flags] | #query_options[:connect_flags] : #query_options[:connect_flags]
# Correct the data types before passing these values down to the C level
user = user.to_s unless user.nil?
pass = pass.to_s unless pass.nil?
host = host.to_s unless host.nil?
port = port.to_i unless port.nil?
database = database.to_s unless database.nil?
socket = socket.to_s unless socket.nil?
connect user, pass, host, port, database, socket, flags
end
def self.default_query_options
##default_query_options
end
def query_info
info = query_info_string
return {} unless info
info_hash = {}
info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
info_hash
end
private
def self.local_offset
::Time.local(2010).utc_offset.to_r / 86400
end
end
end
Mysql2::Client#initialize called connect_timeout= but there isn't such attr_writer in the client.
when :connect_timeout, :read_timeout, :write_timeout
send(:"#{key}=", opts[key].to_i)
else
If this client is written by yourself, add attr_accessor :connect_timeout in Mysql2::Client's definition and make proper use of the attribute. If it is from other library, check your load path. You may have missed some files that opened Mysql2::Client and monkey patched it.

Select when devise send the confirmation mail or not

i need to select when devise send the confirmation mail. I overwrite the send_confirmation_instructions and add a date field named invited on my user model. If the invited field is null send the mail, otherwise not sent.
Here's my code:
def send_confirmation_instructions
unless invited.nil?
self.confirmation_token = nil if reconfirmation_required?
#reconfirmation_required = false
generate_confirmation_token! if self.confirmation_token.blank?
else
self.confirmation_token = nil if reconfirmation_required?
#reconfirmation_required = false
generate_confirmation_token! if self.confirmation_token.blank?
self.devise_mailer.confirmation_instructions(self).deliver
end
end
The output of my console its:
Loading development environment (Rails 3.0.10)
1.9.3-p0 :001 > User.create!(:email => "hello#test.com") NoMethodError: undefined method `reconfirmation_required?' for
I have rewrite many other devise method without problems. Any idea ?
Thanks in advance.
The best solution was to connect manually to the database and add the fields to the users table.
# read configuration from database.yml
config = Rails.application.config.database_configuration[Rails.env]
host = config["host"]
database = config["database"]
username = config["username"]
password = config["password"]
# stablish db connection
mysql = Mysql2::Client.new(:host => host, :username => username, :database => database, :password => password)
# generate devise confirmation token
token = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")
# made the sql
sql = "INSERT INTO users (email, confirmation_token, confirmation_sent_at) VALUES ('email#test.com', '#{token}', '#{Time.now.to_s}')"
# execute query
mysql.query(sql)
# close mysql connection
mysql.close
I hope this will be useful.

Resources