Updating Rails 5 Initializer with Devise User Parameters - ruby-on-rails

I thought I was getting closer to wrapping my head around Rails until this challenge. I have an initializer agilecrm.rb - content show below. I am using AgileCRM Ruby code to try and connect my app with AgileCRM system. When using the code below, with the test Create Contact array at the bottom, it successfully creates a contact in my AgileCRM account, so I know at least this part works. What I need to do is create a new AgileCRM user every time I create a new Devise user. I have a feeling that I am looking at this the wrong way and probably need a controller for this, but this is not completely foreign to me, but I still can't figure out when way to go. Thank you.
config/initializers/agilecrm.rb
require 'net/http'
require 'uri'
require 'json'
class AgileCRM
class << self
def api_key=(key)
##api_key = key
end
def domain=(d)
##domain = d
end
def email=(email)
##email = email
end
def api_key
##api_key
end
def domain
##domain
end
def email
##email
end
def request(method, subject, data = {})
path = "/dev/api/#{subject}"
case method
when :get
request = Net::HTTP::Get.new(path)
when :post
request = Net::HTTP::Post.new(path)
request.body = data.to_json
when :put
request = Net::HTTP::Put.new(path)
request.body = data.to_json
when :delete
request = Net::HTTP::Delete.new(path)
else
raise "Unknown method: #{method}"
end
uri = URI.parse("https://#{domain}.agilecrm.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request['Content-Type'] = 'application/json'
request['Accept'] = 'application/json'
request.basic_auth AgileCRM.email, AgileCRM.api_key
response = http.request(request)
response.body
end
end
end
AgileCRM.api_key = '*******'
AgileCRM.domain = '*******'
AgileCRM.email = '*******'
# ======================Create Contact====================================
contact_data = '{
"star_value": "4",
"lead_score": "92",
"tags": [
"Lead",
"Likely Buyer"
],
"properties": [
{
"type": "SYSTEM",
"name": "first_name",
"value": "John"
}
]
}'
parsed_contact_data = JSON.parse(contact_data)
print(AgileCRM.request :post, 'contacts', parsed_contact_data)

You might want to move this logic into your User model, and have a after_save hook to push data to agilecrm. Assuming that the Devise user model is called User :
class User < ApplicationRecord
...
after_save :sync_to_agilecrm
def sync_to_agilecrm
# your agilecrm api calls go here
...
end
end
The above should do what you are trying to achieve.

Related

Rails display only published episodes from Simplecast api

I'm running a rails application that calls Simplecasts API to display my podcast episodes. I followed a tutorial to setup the API services using Faraday. My question is how to only display published episodes on my index page? Normally, I would add a .where(:status => "live") in my controller, IE #podcasts = Episodes.where(:status => "published") but this doesn't seem to work.
Simplecast's API for the podcast returns a collection that contains all the available episodes, each has a status node.
Any help would be appreciated as I'm new to working with external APIs in Rails
Sample API response
"collection": [
{
"updated_at": "2020-03-25T17:57:00.000000-04:00",
"type": "full",
"token": "lgjOmFwr",
"title": "Test",
"status": "draft",
Episode.rb
module Simplecast
class Episodes < Base
attr_accessor :count,
:slug,
:title,
:status
MAX_LIMIT = 10
def self.episodes(query = {})
response = Request.where('/podcasts/3fec0e0e-faaa-461f-850d-14d0b3787980/episodes', query.merge({ number: MAX_LIMIT }))
episodes = response.fetch('collection', []).map { |episode| Episode.new(episode) }
[ episodes, response[:errors] ]
end
def self.find(id)
response = Request.get("episodes/#{id}")
Episode.new(response)
end
def initialize(args = {})
super(args)
self.collection = parse_collection(args)
end
def parse_collection(args = {})
args.fetch("collection", []).map { |episode| Episode.new(episode) }
end
end
end
Controller
class PodcastsController < ApplicationController
layout "default"
def index
#podcasts, #errors = Simplecast::Episodes.episodes(query)
#podcast, #errors = Simplecast::Podcast.podcast(query)
render 'index'
end
# GET /posts/1
# GET /posts/1.json
def show
#podcast = Simplecast::Episodes.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
private
def query
params.permit(:query, {}).to_h
end
end
Looks like collection is just an array of hashes so rails ActivrRelations methods aka .where are not supported. However It is an array so you can just filter this array:
published_episodes = collection.filter { |episode| episode[:status] == “ published” }
Also look through their API - may be the do support optional filtering params so you would get only published episodes in the first place.
BTW: second thought is to save external API request data in your own DB and then fetch require episodes with standard .where flow.

uninitialized constant "controllername::modulename" TableauServer

Im trying to test the tableau_trusted.rb example for trusted authentication for tableau server in Ruby on rails but I keep getting the error "uninitialized constantTableauTrustedsController::TableauTrustedInterface", this is my code:
tableautrusteds_controller.rb
class TableauTrustedsController < ApplicationController
include TableauTrustedInterface
def index
tabserver = 'xxxxx'
tabuser = 'test'
tabpath = 'views/Tableau_DW1/General?:iid=1'
tabparams = ':embed=yes&:toolbar=no'
ticket = tableau_get_trusted_ticket(tabserver, tabuser, request.remote_ip)
if ticket != "-1"
url = "http://#{tabserver}/trusted/#{ticket}/#{tabpath}?#{tabparams}"
redirect_to url
return
end
render :status => 403, :text => "Error with request"
end
end
module TableauTrustedInterface
require 'net/http'
require 'uri'
# the client_ip parameter isn't necessary to send in the POST unless you have
# wgserver.extended_trusted_ip_checking enabled (it's disabled by default)
def tableau_get_trusted_ticket(tabserver, tabuser, client_ip)
post_data = {
"username" => tabuser,
"client_ip" => client_ip
}
response = Net::HTTP.post_form(URI.parse("http://#{tabserver}/trusted"), post_data)
case response
when Net::HTTPSuccess
return response.body.to_s
else
return "-1"
end
end
end
I have changed the line "include TableauTrustedInterface" to "extend TableauTrustedInterface" but it didn't work.
Also, The URL I put in the browser is
http://localhost:3000/tableautrusteds/index, I use get 'tableautrusteds/index' in routes.rb.
I don't really know if that is important but some people ask me for this.
I am little bit new in rails so any help will be very appreciated.
I fixed my problem, if anybody was having a similar issue here is my code
module TableauTrustedInterfaces
require 'net/http'
require 'uri'
# the client_ip parameter isn't necessary to send in the POST unless you have
# wgserver.extended_trusted_ip_checking enabled (it's disabled by default)
def tableau_get_trusted_ticket(tabserver, tabuser, client_ip)
post_data = {
"username" => tabuser,
"client_ip" => client_ip
}
response = Net::HTTP.post_form(URI.parse("http://#{tabserver}/trusted"), post_data)
case response
when Net::HTTPSuccess
return response.body.to_s
else
return "-1"
end
end
end
class TableauTrustedController < ApplicationController
include TableauTrustedInterfaces
def index
tabserver = 'xxxxx'
tabuser = 'test'
tabpath = 'views/Tableau_DW1/General?:iid=1'
tabparams = ':embed=yes&:toolbar=no'
ticket = tableau_get_trusted_ticket(tabserver, tabuser, request.remote_ip)
if ticket != "-1"
url = "http://#{tabserver}/trusted/#{ticket}/#{tabpath}?#{tabparams}"
redirect_to url
return
end
render json: {}, status: :forbidden
end
end
In order to use the module it needs to be declared before the class. Also, and very important I changed the name of the file to tableau_trusted_controler.rb because the snake case that rails uses.

Cache api (json) request to avoid repeating the request

So I created this request which gives me a response as json.
require 'dotenv/load'
require 'faraday'
class OverviewController < ApplicationController
def api_key
ENV["API_KEY"]
end
def url
"https://example.com"+api_key
end
def index
conn = Faraday.new(url, request: {open_timeout: 1, timeout: 1}) do |c|
c.response :json, :content_type => /\bjson$/
c.adapter Faraday.default_adapter
end
response = conn.get url
#hash = response.body['data']
end
end
Response:
{
"type": "products",
"version": "x.x.x",
"data": {
"Product 1": {
"title": "xxx",
"attributes": {
"x"=1
},
"id": 22,
"name": "Product 1"
},
"Product 2": {
"title": "xXx",
"attributes": {
"x"=2
},
"id": 25,
"name": "Product 2"
},
...
This works great so far. But since the data in this json changes really rarely and there is a policy to not request the api as much I would like to cache my result.
I tried different solutions with "faraday-http-cache" but I can't get it to work. But I like to not use another lib.
I read the "rails - Guides - caching" segment and I think I need low level caching Rails.cache.fetch
I would be really glad if someone could help me :-)
EDIT(after Panic's comment):
I tried this, but I need some more help
require 'dotenv/load'
require 'faraday'
class StatsClient
def api_key
ENV["API_KEY"]
end
def url
"https://example.com"+api_key
end
def index
conn = Faraday.new(url, request: {open_timeout: 1, timeout: 1}) do |c|
c.response :json, :content_type => /\bjson$/
c.adapter Faraday.default_adapter
end
response = conn.get url
#hash = response.body['data']
end
end
class OverviewController < ApplicationController
def index
#hash = Rails.cache.fetch('something', expires_in: 15.minutes) do
StatsClient.products
end
end
end
Like this? What has to go actually as 'something'. Also I get the error that "StatsClient.products is not recognised.
Move the code from your controller into a separate class (or module) StatsClient. Then in your controller:
def index
#hash = Rails.cache.fetch('something', expires_in: 15.minutes) do
StatsClient.products
end
end

Define a params in a variable

I would know how define a params in a variable to use it in another method
In my controller i have result page and contact page, i want store the search params from result page in variables and get them in my contact page method to not duplicate form fields
My result page
def result
if params[:room_type].present? && params[:location].present? && params[:nb_piece].present?
#biens = Bien.near(params[:location], 1, units: :km).where(room_type: params[:room_type], nb_piece: params[:nb_piece])
end
#users = User.where(id: #biens.reorder(:user_id).pluck(:user_id), payer: true) || User.where(id: #biens.reorder(:user_id).pluck(:user_id), subscribed: true)
end
I want store this params in my other method,like that i will need to ask only email and phone in my form
def contact
wufoo(params[:location], params[:room_type], params[:nb_piece], params[:email], params[:phone])
end
My wufoo
def wufoo(adresse, type, pieces, email, phone)
require "net/http"
require "uri"
require "json"
base_url = 'https://wako94.wufoo.com/api/v3/'
username = 'N5WI-FJ6V-WWCG-STQJ'
password = 'footastic'
uri = URI.parse(base_url+"forms/m1gs60wo1q24qsh/entries.json")
request = Net::HTTP::Post.new(uri.request_uri)
request.basic_auth(username, password)
request.set_form_data(
'Field7' => adresse,
'Field9' => type,
'Field12' => email,
'Field11' => phone,
'Field8' => pieces
)
response = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme =='https'){
|http|http.request(request)
}
puts JSON.pretty_generate(JSON[response.body])
end
It depends on how a user goes from search to contact. I assume that the contact form is linked off the search, and that they want to contact you regarding the information in the last search.
A simple method here would be to store the last search within the session, and just reference that.
def search
store_params_in_session
# .. your search logic here
end
def contact
last_search = session[:last_search]
if last_search.blank?
# .. some error handling if no search is available
return
end
wufoo(last_search[:location], #.. you get the idea
end
private
def store_params_in_session
session[:last_search] = {
location: params[:location],
# .. more params here
}

Unfuddle API get accounts info

I'm trying to get the account info from Unfuddle API using ActiveResource
The url is http://mydomain.unfuddle.com/api/v1/account
this is my ActiveResource class
class Account < ActiveResource::Base
self.collection_name = "account"
self.site = "https://mydomain.unfuddle.com/api/v1"
self.user = "me"
self.password = "pass"
end
if I try getting my account info with Account.all I'll get an empty array but if I try this
require 'net/https'
UNFUDDLE_SETTINGS = {
:subdomain => 'mydomain',
:username => 'me',
:password => 'pass',
:ssl => true
}
http = Net::HTTP.new("#{UNFUDDLE_SETTINGS[:subdomain]}.unfuddle.com",UNFUDDLE_SETTINGS[:ssl] ? 443 : 80)
if UNFUDDLE_SETTINGS[:ssl]
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
begin
request = Net::HTTP::Get.new('/api/v1/account')
request.basic_auth UNFUDDLE_SETTINGS[:username], UNFUDDLE_SETTINGS[:password]
response = http.request(request)
if response.code == "200"
puts response.body
else
puts "HTTP Status Code: #{response.code}."
end
rescue => e
puts e.message
end
I get my account information , any ideas why the ActiveResource approach isn't working ?
**UPDATE
I forgot to specify that I had this issue https://github.com/rails/rails/issues/2318 and I use erikkallens hack .
It seems to be this issue https://github.com/rails/rails/issues/2318 , I tried vaskas solution but it didn't work by default I had to modify it.
class Account < ActiveResource::Base
self.collection_name = "account"
self.site = "https://mydomain.unfuddle.com/api/v1"
self.user = "me"
self.password = "pass"
self.format = AccountXMLFormatter.new
end
class AccountXMLFormatter
include ActiveResource::Formats::XmlFormat
def decode(xml)
[account: ActiveResource::Formats::XmlFormat.decode(xml)]
end
end

Resources