Rails class gives NoMethodError undefined method `each' - ruby-on-rails

I'm working with redmine and I've installed a plugin for managing mails.
When I try to send a mail I obtain the following error
[ActiveJob] [ActionMailer::DeliveryJob] [uuid] Error performing ActionMailer::DeliveryJob (Job ID: uuid) from Async(mailers) in 41.81ms: NoMethodError (undefined method `each' for #<User:id>):
This is the file that gives me the error
module EncryptMails
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :mail_without_relocation, :mail
alias_method :mail, :mail_with_relocation
end
end
module InstanceMethods
# action names to be processed by this plugin
def actions
[
'attachments_added',
'document_added',
'issue_add',
'issue_edit',
'message_posted',
'news_added',
'news_comment_added',
'wiki_content_added',
'wiki_content_updated'
]
end
# dispatched mail method
def mail_with_relocation(headers={}, &block)
# pass unchanged, if action does not match or plugin is inactive
act = Setting.plugin_openpgp['activation']
return mail_without_relocation(headers, &block) if
act == 'none' or not actions.include? #_action_name or
(act == 'project' and not project.try('module_enabled?', 'openpgp'))
# relocate recipients
recipients = relocate_recipients(headers)
header = #_message.header.to_s
# render and deliver encrypted mail
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:encrypted], encrypt = true, sign = true
) do |format|
format.text
end
m.deliver
# render and deliver filtered mail
reset(header)
tpl = #_action_name + '.filtered'
m = mail_without_relocation prepare_headers(
headers, recipients[:filtered], encrypt = false, sign = true
) do |format|
format.text { render tpl }
format.html { render tpl } unless Setting.plain_text_mail?
end
m.deliver
# render unchanged mail (deliverd by calling method)
reset(header)
m = mail_without_relocation prepare_headers(
headers, recipients[:unchanged], encrypt = false, sign = false
) do |format|
format.text
format.html unless Setting.plain_text_mail?
end
m
end
# get project dependent on action and object
def project
case #_action_name
when 'attachments_added'
#attachments.first.project
when 'document_added'
#document.project
when 'issue_add', 'issue_edit'
#issue.project
when 'message_posted'
#message.project
when 'news_added', 'news_comment_added'
#news.project
when 'wiki_content_added', 'wiki_content_updated'
#wiki_content.project
else
nil
end
end
# relocates reciepients (to, cc) of message
def relocate_recipients(headers)
# hash to be returned
recipients = {
:encrypted => {:to => [], :cc => []},
:blocked => {:to => [], :cc => []},
:filtered => {:to => [], :cc => []},
:unchanged => {:to => [], :cc => []},
:lost => {:to => [], :cc => []}
}
# relocation of reciepients
[:to, :cc].each do |field|
headers[field].each do |user|
# encrypted
unless Pgpkey.find_by(user_id: user.id).nil?
recipients[:encrypted][field].push user and next
end
# unencrypted
case Setting.plugin_openpgp['unencrypted_mails']
when 'blocked'
recipients[:blocked][field].push user
when 'filtered'
recipients[:filtered][field].push user
when 'unchanged'
recipients[:unchanged][field].push user
else
recipients[:lost][field].push user
end
end unless headers[field].blank?
end
recipients
end
# resets the mail for sending mails multiple times
def reset(header)
#_mail_was_called = false
#_message = Mail.new
#_message.header header
end
# prepares the headers for different configurations
def prepare_headers(headers, recipients, encrypt, sign)
h = headers.deep_dup
# headers for recipients
h[:to] = recipients[:to]
h[:cc] = recipients[:cc]
# headers for gpg
h[:gpg] = {
encrypt: false,
sign: false
}
# headers for encryption
if encrypt
h[:gpg][:encrypt] = true
# add pgp keys for emails
h[:gpg][:keys] = {}
[:to, :cc].each do |field|
h[field].each do |user|
user_key = Pgpkey.find_by user_id: user.id
unless user_key.nil?
h[:gpg][:keys][user.mail] = user_key.fpr
end
end unless h[field].blank?
end
end
# headers for signature
if sign
server_key = Pgpkey.find_by(:user_id => 0)
unless server_key.nil?
h[:gpg][:sign] = true
h[:gpg][:sign_as] = Setting['mail_from']
h[:gpg][:password] = server_key.secret
end
end
h
end
end
end
The stack of the log tells me that the error is in row 109
# relocation of reciepients
[:to, :cc].each do |field|
I'm not an expert of ruby and rails but I've seen that each is a method of a Ruby array, not a custom one, so I don't understand why I obtain the error.
What I am doing wrong and how can I fix this error?

Are you sure the problem isn't on this line?
h[field].each do |user|
The field there would be :to or :cc so h[field] could be a User instance.
If you want to allow h[:to] or h[:cc] to be a single User or an array of Users, then wrap it in Array():
# relocation of reciepients
[:to, :cc].each do |field|
Array(headers[field]).each do |user|
#^^^^
I'd also move that trailing unless so it doesn't get missed, maybe something like this:
%i[to cc].select { |field| headers[field].present? }.each do |field|
Array(headers[filed]).each do |user|
#...
end
end

Related

AuthenticationFailed: While fetching file stored to azure storage using Ruby on Rails

I am using ruby-2.7.0 and Rails 6.0.3.3. I uploaded the file to azure storage successfully and got the URL for it. While accessing the URL, I am getting the following error.
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization
header is formed correctly including the signature. RequestId:c87f3e57-a01e-000a-748b-
8aa65d000000 Time:2020-09-14T11:38:20.3226191Z</Message>
<AuthenticationErrorDetail>Signature fields not well formed.</AuthenticationErrorDetail>
</Error>
My code to upload the file.
When using s3 service, made this URL publicly available by adding acl: 'public-read' but I need to use azure storage service. So couldn't make the URL publicly available.
file name: app/lib/active_storage/service/azure_storage_service.rb
require "active_support/core_ext/numeric/bytes"
require "azure/storage"
require "azure/storage/core/auth/shared_access_signature"
module ActiveStorage
class Service::AzureStorageService < Service
attr_reader :client, :blobs, :container, :signer, :public
def initialize(storage_account_name:, storage_access_key:, public: true, container:, **options)
#client = Azure::Storage::Client.create(storage_account_name: storage_account_name, storage_access_key: storage_access_key, **options)
#signer = Azure::Storage::Core::Auth::SharedAccessSignature.new(storage_account_name, storage_access_key)
#blobs = client.blob_client
#container = container
#public = public
end
def upload(key, io, checksum: nil, **)
instrument :upload, key: key, checksum: checksum do
handle_errors do
blobs.create_block_blob(container, key, IO.try_convert(io) || io, content_md5: checksum)
end
end
end
def download(key, &block)
if block_given?
instrument :streaming_download, key: key do
stream(key, &block)
end
else
instrument :download, key: key do
handle_errors do
_, io = blobs.get_blob(container, key)
io.force_encoding(Encoding::BINARY)
end
end
end
end
def download_chunk(key, range)
instrument :download_chunk, key: key, range: range do
handle_errors do
_, io = blobs.get_blob(container, key, start_range: range.begin, end_range: range.exclude_end? ? range.end - 1 : range.end)
io.force_encoding(Encoding::BINARY)
end
end
end
def delete(key)
instrument :delete, key: key do
blobs.delete_blob(container, key)
rescue Azure::Core::Http::HTTPError => e
raise unless e.type == "BlobNotFound"
# Ignore files already deleted
end
end
def delete_prefixed(prefix)
instrument :delete_prefixed, prefix: prefix do
marker = nil
loop do
results = blobs.list_blobs(container, prefix: prefix, marker: marker)
results.each do |blob|
blobs.delete_blob(container, blob.name)
end
break unless marker = results.continuation_token.presence
end
end
end
def exist?(key)
instrument :exist, key: key do |payload|
answer = blob_for(key).present?
payload[:exist] = answer
answer
end
end
def url(key, expires_in:, filename:, disposition:, content_type:)
instrument :url, key: key do |payload|
binding.pry
generated_url = signer.signed_uri(
uri_for(key), true,
service: 'My azure storage',
permissions: 'rw',
).to_s
payload[:url] = generated_url
generated_url
end
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
instrument :url, key: key do |payload|
generated_url = signer.signed_uri(
uri_for(key), false,
service: 'My azure storage,
permissions: 'rw',
expiry: format_expiry(5.days)
).to_s
payload[:url] = generated_url
generated_url
end
end
def headers_for_direct_upload(key, content_type:, checksum:, **)
{ "Content-Type" => content_type, "Content-MD5" => checksum, "x-ms-blob-type" => "BlockBlob" }
end
private
def uri_for(key)
blobs.generate_uri("#{container}/#{key}")
end
def blob_for(key)
blobs.get_blob_properties(container, key)
rescue Azure::Core::Http::HTTPError
false
end
def format_expiry(expires_in)
expires_in ? Time.now.utc.advance(seconds: expires_in).iso8601 : nil
end
# Reads the object for the given key in chunks, yielding each to the block.
def stream(key)
blob = blob_for(key)
chunk_size = 5.megabytes
offset = 0
raise ActiveStorage::FileNotFoundError unless blob.present?
while offset < blob.properties[:content_length]
_, chunk = blobs.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
yield chunk.force_encoding(Encoding::BINARY)
offset += chunk_size
end
end
def handle_errors
yield
rescue Azure::Core::Http::HTTPError => e
case e.type
when "BlobNotFound"
raise ActiveStorage::FileNotFoundError
when "Md5Mismatch"
raise ActiveStorage::IntegrityError
else
raise
end
end
end
end
What is the correct way to make the image URL publicly available?

Getting Filter chain halted for callback_phase in cutom omniauth strategy

I am trying to implement custom strategy for linking account here is my code
require 'omniauth-oauth2'
require 'multi_json'
module OmniAuth
module Strategies
class MyStrategy < OmniAuth::Strategies::OAuth2
option :name, 'my_strategy'
args [:consumer_key, :consumer_secret]
option :consumer_key, nil
option :consumer_secret, nil
option :client_options, {
site: SITE_URL,
header: { ACCEPT_HEADERS },
request_token_url: request_token_uri,
access_token_url: access_token_uri,
authorize_url: authorizerequest_token_uri
}
option :provider_ignores_state, true
def consumer
consumer = ::OAuth::Consumer.new(options.consumer_key, options.consumer_secret, options.client_options)
end
def request_phase
binding.pry
request_token = consumer.get_request_token({:oauth_callback => callback_url}, options.request_params)
session["oauth"] ||= {}
session["oauth"][name.to_s] = {"callback_confirmed" => request_token.callback_confirmed?, "request_token" => request_token.token, "request_secret" => request_token.secret}
if request_token.callback_confirmed?
redirect request_token.authorize_url(options[:authorize_params])
else
redirect request_token.authorize_url(options[:authorize_params].merge(:oauth_callback => callback_url))
end
rescue ::Timeout::Error => e
fail!(:timeout, e)
rescue ::Net::HTTPFatalError, ::OpenSSL::SSL::SSLError => e
fail!(:service_unavailable, e)
end
def callback_phase
binding.pry
end
def build_access_token
binding.pry
token_params = {
:redirect_uri => callback_url.split('?').first,
:client_id => client.id,
:client_secret => client.secret
}
verifier = request.params['code']
client.auth_code.get_token(verifier, token_params)
end
credentials do
{ "token" => access_token.token, "secret" => access_token.secret }
end
extra do
{ "access_token" => access_token }
end
def raw_info
binding.pry
#raw_info ||= access_token
end
end
end
end
But I am getting following warning to the request phase
Filter chain halted as :require_no_authentication rendered or redirected
Because of this it going into the infinite loop (i.e. it continuously executing the callback_phase).
Can any one help tell why this is happening and how can I fix this issue.
I am using rails 4.
Thanks

Active Merchant paypal recurring payments

I am using Active Merchant gem to handle payments through the site. But now i want to make these payments recurring, on a monthly basis. Is there a way using active merchant or?
subscription_controller.rb
class SubscriptionsController < ApplicationController
def new
#home_page = true
#white = true
#subscription = Subscription.new(token: params[:token])
if !logged_in?
redirect_to signup_url
end
end
def create
#subscription = Subscription.new(subscription_params)
#subscription.remote_ip = request.remote_ip
#subscription.user_id = current_user.id
if #subscription.save
if #subscription.purchase
#subscription.send_thank_you_email
redirect_to thankyou_path
else
raise ActiveRecord::Rollback
flash[:notice] = "It seems something went wrong with the paypal transaction. Please check that your credit card is valid and has credit in it and try again."
redirect_to :back
end
else
flash[:notice] = "Something went wrong with marking your purchase as complete. Please contact support to check it out."
redirect_to :back
end
end
def purchase
response = GATEWAY.setup_purchase(999,
ip: request.remote_ip,
return_url: new_subscription_url,
cancel_return_url: root_url,
currency: "USD",
items: [{name: "Order", description: "Recurring payment for ******", quantity: "1", amount: 999}]
)
redirect_to GATEWAY.redirect_url_for(response.token)
end
def thank_you
#home_page = true
#white = true
end
private
def subscription_params
params.require(:subscription).permit(:token)
end
end
subscription.rb model
def purchase
response = GATEWAY.purchase(999, express_purchase_options)
response.success?
end
def token=(token)
self[:token] = token
if new_record? && !token.blank?
# you can dump details var if you need more info from buyer
details = GATEWAY.details_for(token)
puts details.params["PayerInfo"]["PayerName"].inspect
self.payer_id = details.payer_id
self.first_name = details.params["PayerInfo"]["PayerName"]["FirstName"]
self.last_name = details.params["PayerInfo"]["PayerName"]["LastName"]
end
end
# send thank you email
def send_thank_you_email
UserMailer.thank_you(self).deliver_now
end
private
def express_purchase_options
{
:ip => remote_ip,
:token => token,
:payer_id => payer_id
}
end
production.rb environment
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :production
::GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(
:login => ENV['PAYPAL_LOGIN'],
:password => ENV['PAYPAL_PASSWORD'],
:signature => ENV['PAYPAL_SIGNATURE']
)
end
I think ActiveMerchant used to have something like this:
subscription = PAYPAL_EXPRESS_GATEWAY.recurring(#subscription.price_in_cents, nil,
:description => 'blah',
:start_date => Date.tomorrow,
:period => 'Year',
:frequency => 1,
:amount => price,
:currency => 'USD'
)
See this answer Does ActiveMerchant support Subscription Based transaction
Also see this: https://github.com/activemerchant/active_merchant/blob/master/lib/active_merchant/billing/gateways/paypal_express.rb
https://github.com/activemerchant/active_merchant/blob/master/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb

How to send email to user after payment is done with paypal

I want to sent email to user after transcation done. now paypal is working fine for me, but user is not getting mail notification after transcation done? how to get email notification for user .
Here is my code
This is my controller code
This is my paypal function
def pay
if #order.update order_params
#order.update_attributes(:invoice_id => rand.to_s[2..11])
if current_user.billing_address.blank?
current_user.create_billing_address(#order.billing_address.dup.attributes)
end
if current_user.shipping_address.blank?
current_user.create_shipping_address(#order.shipping_address.dup.attributes)
end
# #cart.calculate_shipping
if #order.total == 0
return redirect_to checkout_thank_you_path
end
# if !params['payment'].present?
# return redirect_to :back, notice: 'Select Payment Gateway!'
# end
# if params['payment']=='paypal'
#order.order_statuses.create(status_type: 1)
item_details=[]
#order.line_items.each do |item|
item_details << {:name => item.title, :quantity => item.quantity, :amount => item.amount.fractional}
end
logger.info item_details.inspect
response = EXPRESS_GATEWAY.setup_purchase(#cart.total.fractional,
:ip => request.remote_ip,
:currency =>"USD",
:items => item_details,
:order_id => #order.invoice_id,
:return_url => checkout_thank_you_url,
:cancel_return_url => cart_url
)
return redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
# else
# return redirect_to 'https://www.payumoney.com/'
# end
else
flash[:alert] = 'Billing and shipping address fields are required!'
render :addresses
end
end
This is my thank function for paypal
def thank_you
#order = Order.find(session[:order_id])
details = EXPRESS_GATEWAY.details_for(params[:token])
response = EXPRESS_GATEWAY.purchase(#cart.total.fractional, {
ip: request.remote_ip,
token: params[:token],
payer_id: details.payer_id,
items: #order.line_items.map{|l| {name: l.title, quantity: l.quantity, amount: l.amount.fractional}}
})
if response.success?
# logger.info payment_params.inspect
payment_params = {gateway: 'PayPal Express Checkout', transaction_id: response.params['token'], ip: request.remote_ip, amount: response.params['gross_amount']}
#cart.order.created_at = DateTime.now
#cart.order.status = 'Paid'
#cart.order.save
session.delete :order_id
# OrderMailer.order_confirmation(#order).deliver
# OrderMailer.admin_receipt(#order).deliver
else
redirect_to :cart_checkout, alert: 'Something went wrong. Please try again. If the problem persists, please contact us.'
end
#cart = Cart.new current_or_null_user.id, session[:order_id], session[:currency] # Start a new cart
end
Any help is appreciatable

Podio Ruby Rails shows "nomethoderror"

I'm having problems with the Podio_rails_sample. I've included my leadsController and leads.rb files. The line that gets hung up is field['config']['settings']['allowed_values'].
Line 25 is the problematic one:
NoMethodError in LeadsController#new
undefined method `[]' for nil:NilClass
Extracted source (around line #25):
23 app = Podio::Application.find(APP_ID)
24 field = app.fields.find { |field| field['external_id'] == 'status' }
25 field['config']['settings']['allowed_values']
26 end
27
28 def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
-----------------------------------
class LeadsController < ApplicationController
before_filter :load_collections, :only => [:new, :edit]
def index
#leads = Lead.all
end
def new
#lead = Lead.new
end
def create
Lead.create_from_params(params['lead'])
redirect_to leads_path, :notice => 'Lead created'
end
def edit
#lead = Lead.find_basic(params[:id])
end
def update
Lead.update_from_params(params[:id], params['lead'])
redirect_to leads_path, :notice => 'Lead updated'
end
def destroy
Lead.delete(params[:id])
redirect_to leads_path, :notice => 'Lead deleted'
end
#protected
def load_collections
#lead_contacts = Lead.space_contacts
#sales_contacts = Lead.users
#statuses = Lead.statuses
end
end
-------------------------------------
- leads.rb file
class Lead < Podio::Item
APP_ID =12328033
SPACE_ID =3204114
# Find all items in the Leads app
def self.all
collection = self.find_all(APP_ID)
collection[:all]
end
# Find valid lead contacts in the space
def self.space_contacts
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'space,connection', :exclude_self => false) rescue []
end
# Find valid sales contacts in the space
def self.users
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'user', :exclude_self => false) rescue []
end
# Find valid statuses
def self.statuses
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
# raise fields.inspect
self.create(APP_ID, { :fields => fields_from_params(params) })
end
def self.update_from_params(id, params)
self.update(id, { :fields => fields_from_params(params) })
end
#
# Map the field values return by the Podio API to simple getters
#
def organization
field_values_by_external_id('company-or-organisation', :simple => true)
end
def lead_contact
field_values_by_external_id('contacts', :simple => true).try(:[], 'name')
end
def sales_contact
field_values_by_external_id('sales-contact', :simple => true).try(:[], 'name')
end
def potential_revenue_value
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'value').to_i
end
def potential_revenue_currency
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'currency')
end
def probability
field_values_by_external_id('probability-of-sale', :simple => true)
end
def status
field_values_by_external_id('status', :simple => true)
end
def followup_at
field_values_by_external_id('next-follow-up').try(:first).try(:[], 'start').try(:to_datetime)
end
protected
def field_values_by_external_id(external_id, options = {})
if self.fields.present?
field = self.fields.find { |field| field['external_id'] == external_id }
if field
values = field['values']
if options[:simple]
values.first['value']
else
values
end
else
nil
end
else
nil
end
end
def self.fields_from_params(params)
{
'company-or-organisation' => params[:organization],
'contacts' => (params[:lead_contact].present? ? params[:lead_contact].to_i : nil),
'sales-contact' => (params[:sales_contact].present? ? params[:sales_contact].to_i : nil),
'potential-revenue' => { :value => params['potential_revenue_value'], :currency => params['potential_revenue_currency'] },
'probability-of-sale' => params[:probability].to_i,
'status' => params[:status],
'next-follow-up' => DateTime.new(params['followup_at(1i)'].to_i, params['followup_at(2i)'].to_i, params['followup_at(3i)'].to_i).to_s(:db)
}.delete_if { |k, v| v.nil? }
end
end

Resources