pass a variable from observer to controller - ruby-on-rails

i have a controller (User controller), this is used to create update and delete a user from db. Within the UserObserver class after_save is been defined as a method in UserObserver after each save in db i have to call another application through http with user_details(in hash format)
class UserObserver < ActiveRecord::Observer
def after_save user_details
begin
http Net::HTTP.new("localhost", "8000")
request = Net::HTTP::Post.new("/verification")
request.add_field('Content-Type', 'application/json')
request.body = user_details.to_json
response = http.request(request)
#http_error = false if response.code == 200
rescue Exception => error
#http_error = true
end
end
end
i need to access #http_error variable in user_controller to know status of http request been made so that furthur action can be taken according to it.

Related

Rails 5: Saving external API call to DB

I'm currently trying to save filled out forms from my Typeform. Everything works just fine, except when I try to save the form to the db.
My model Order.rb
class Order < ApplicationRecord
belongs_to :user
include HTTParty
base_uri 'api.typeform.com'
def initialize
token = '############################'
#auth = 'Bearer ' + token
end
def get_orders
response = self.class.get("/forms/######/responses?page_size=25", headers: { "Authorization" => #auth})
end
def save_orders
if response.code.to_i == 200
orders = response.parsed_response
order = response["items"]
order.each do |data|
create!(
email: data["hidden"]["email"]
)
end
else
raise "Error fetching data from Typeform API"
end
end
end

NoMethodError: undefined method `submission' for HTTParty

I'm currently working on a Rails application where I am trying to submit a form to the FormStack API. The request look as follows.
This is what the requests looks like:
POST /api/v2/form/12345/submission.json HTTP/1.1
Host: www.formstack.com
Authorization: Bearer YOUR_APP_OAUTH_TOKEN
Accept: application/json
Content-Type: application/json
field_12345=Example&field_12346=Answer
I'm trying to implement that using Httparty on the library I created to make the requests to this API service.
module FormStack
class Form
include HTTParty
attr_reader :form_id
base_uri "https://www.formstack.com/api/v2"
def initialize
#access_token = ENV.fetch('FORMSTACK_ACCESS_TOKEN')
#form_id = ENV.fetch('FORMSTACK_FORM_ID')
end
def create_form
self.class.get(relative_uri, headers: headers)
end
def submission
self.class.post(create_submission_uri, headers: headers, query: query)
end
private
def relative_uri
"/form/#{#form_id}/field.json"
end
def create_submission_uri
"form/#{#form_id}/submission.json"
end
def headers
{
"Accept" => "application/json",
"Content-Type" => "application/json",
"Authorization" => "Bearer #{#access_token}"
}
end
def query
{
"field_66563890" => "blah",
"field_66563757" => "something"
}
end
end
end
controller
class FormsController < ApplicationController
def display_form
#form = FormStack::Form.new().create_form
end
def create
#form.submission
redirect_to 'localhost:3000'
end
end
This are the routes
get '/forms/display_form', to: 'forms#display_form'
post '/forms/submit', to: "forms#create"
First of all, I've got a couple general ruby things for you:
When you call FormStack::Form.new().create_form you actually don't need the () after .new -- ruby knows to call the method with no arguments even if you exclude the parens.
I'm not quite sure how you're calling FormsController::display_form from FormsController::create, but for now I'll just assume that you're using magic.
Anyways, on to my answer. As your error message states, the error is related to you calling submission on something which does not have a submission method. With that knowledge, we can look at what Object you're calling submission on in this line:
#form.submission
It looks like you're calling submission on #form. Well, let's go and look at where you declare #form:
#form = FormStack::Form.new().create_form
Let's break that declaration down into its parts. First, with FormStack::Form.new(), you're creating a new instance of FormStack::Form. So far so good. FormStack::Form has a submission method defined on it. But then, you call create_form on it. So, let's look at what create_form does:
def create_form
self.class.get(relative_uri, headers: headers)
end
create_form calls a method provided by HTTParty, get. The get method returns a HTTParty::Response Object. So, let's parse through the line where you set #form again. Broken down, what you're doing is this:
#form = FormStack::Form # This line sets the variable to a constant
#form = #form.new # This line sets the variable to be an instance of FormStack::Form
#form = #form.create_form # This line sets #form to be an instance of HTTParty::Reponse
As you can see, at the end we've set #form to an instance of HTTParty::Reponse instead of FormStack::Form, and since there's not submission method for HTTParty::Response that's why you get the error.
Based on this exploration, we can see that the fix would be to set #form to a FormStack::Form object instead, which we can do by changing the display_form action to be:
def display_form
#form = FormStack::Form.new
#form.create_form
end

WebMock model's function when called via controller

I have existing functionality, where specs calls HTTP PUT method of a controller, which in-turn calls model's method to get some JSON data via. API.
class SomeModel
def GetData()
uri = URI.parse('http://api.mydomain.com/getmydata/123/ohmyurl')
Net::HTTP.start(uri.host, uri.port, :read_timeout => 200) do |http|
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
unless response.body == "null"
return JSON.parse(response.body)
end
#......
end
end
end
class SomeController < ApplicationController
def update
#...
#model.GetData()
#...
end
end
#......specs............
put :update
I need to mock the API in SomeModel. So far I have tried:
#......specs............
before do
stub_request(:get, /api.mydomain.com/)
.with(headers: {'Accept'=>'application/json' })
.to_return(status: 200, body: {id: 1, secondParam: '324'}.to_json, headers: {})
end
#.......
put :update
result = JSON.load response.body
expect(result['secondParam']).to eq("324")
Which is not able to mock the API call and actual API is called.
kindly ignore syntax errors

Rails - Send Twilio messages for custom actions

In rails 4.2.4, I am using gem 'twilio-ruby' to send SMS. Right now I am calling this twilio method for particular action, eg: send otp message & it is working fine. But the issue is same message will send when I am calling other actions.
In development.rb
config.middleware.use Rack::TwilioWebhookAuthentication, Rails.application.secrets.twilio_auth_token, '/voice'
In user model,
def send_otp_notification
begin
client = Twilio::REST::Client.new Rails.application.secrets.twilio_account_sid, Rails.application.secrets.twilio_auth_token
message = client.messages.create :from=> '+12015598867', :to=>"+#{self.mobile_number}", :body=> "Verify your otp: #{self.otp}"
rescue Twilio::REST::RequestError => e
puts "e = #{e}".red
end
end
In mobile/api/user.rb,
user = User.new(params[:user])
user.save
user.send_otp_notification
Here, send_otp_notification method will call only once when user registers, right now when a user creates any other object(eg: create 'posts' table entry) then also otp message will send, how can I avoid this?
Using Active Record new_record
user = User.new(params[:user])
user.save
tmp = true
user.send_otp_notification if tmp.present?
Active Record Persistence new_record
hope this solve your issue!!!
ActiveRecord has two callback method after_save or after_create.You can use any one or both to call your function dynamically.You need to set those method in your model.No need to set condition or call at anywhere.
after_save :send_otp_notification
after_create :send_otp_notification
You can modify your model to contain a boolean field that tells if a notification has already been sent for this user
class AddOtpSentToUsers < ActiveRecord::Migration
def up
add_column :users, :otp_sent, :boolean, default: false
end
def down
remove_column :users, :otp_sent
end
end
And modify your function to be flexible in sending otp if it is requested to be sent again or for the first time
def send_otp_notification send_again = false
if !self.otp_sent || send_again
begin
client = Twilio::REST::Client.new Rails.application.secrets.twilio_account_sid, Rails.application.secrets.twilio_auth_token
message = client.messages.create :from=> '+12015598867', :to=>"+#{self.mobile_number}", :body=> "Verify your otp: #{self.otp}"
rescue Twilio::REST::RequestError => e
puts "e = #{e}".red
end
end
end

net/http hanging requests causing failure - RoR

I have a bit of code that checks the response code of a list of URL's and presents them back - I am having trouble with a few of URL's that are hanging which causes the application not load at all. How can I make the request to give up after 30 seconds and check the next URL marking the skipped URL as failure.
below is my current code;
(Model/status.rb)
require "net/http"
require "uri"
class Status
def initialize(url)
#url = url
end
def get_status
response.code
end
def active?
["200","203","302"].include?(get_status) ? true : false
end
private
def lookup
URI.parse(#url)
end
def http
Net::HTTP.new(lookup.host, lookup.port)
end
def request
Net::HTTP::Get.new(lookup.request_uri)
end
def response
http.request(request)
end
end
(controllers/welcome_controller.rb)
class WelcomeController < ApplicationController
def index
#syndication = [
["http://v1.syndication.u01.example.uk/organisations?apikey=bbccdd", "U.INT 01"],
["http://v1.syndication.u02.example.uk/organisations?apikey=bbccdd", "U.INT 02"],
].collect { |url| logger.info("Boom #{url[0]}"); ["#{url[1]} (#{url[0]})", Status.new(url[0]).active?] }
end
end
Got the answer..
adding the following to my "def get_status"
def get_status
begin
response.code
rescue Exception => e
Rails.logger.info("Error #{e}")
end
end
This logged the error and the went to the next URL

Resources