have a transaction model similar to RailsCasts ActiveMerchant tutorial.
How can I create a fake response?
Tried something like the following but no luck.
response = #success=true, #params = {"ref" => "123"}, #authorization = "54321", ...
models/order_transaction.rb
class OrderTransaction < ActiveRecord::Base
belongs_to :order
serialize :params
def response=(response)
self.success = response.success?
self.authorization = response.authorization
self.message = response.message
self.params = response.params
rescue ActiveMerchant::ActiveMerchantError => e
self.success = false
self.authorization = nil
self.message = e.message
self.params = {}
end
end
you can do something like
a = OpenStruct.new
def a.success?
true
end
Related
so im trying to do web scraping with rails and kimurai, the problem i ran in to was that for some reason i get a single big object instead of one for each of the products im scraping, here is my code:
class ProductsSpider < Kimurai::Base
#name = "products_spider"
#engine = :mechanize
def self.process(url)
#start_urls = [url]
self.crawl!
end
def parse(response, url:, data: {})
response.xpath("//div[#class='andes-card andes-card--flat andes-card--default ui-search-result ui-search-result--core andes-card--padding-default andes-card--animated']").each do |product|
item = {}
item[:product_name] = product.xpath("//h2[#class='ui-search-item__title ui-search-item__group__element']")&.text&.squish
item[:price] = product.xpath("//span[#class='price-tag-fraction']")&.text&.squish&.delete('^0-9')to_i
item[:shipping] = product.xpath("//p[#class='ui-search-item__shipping ui-search-item__shipping--free']")&.text&.squish
Product.where(item).first_or_create
end
end
end
and here is the function on the controller:
def scrape
url = "https://computacion.mercadolibre.com.ar/componentes-pc-placas-video/msi/cordoba/placa-de-video_NoIndex_True#applied_filter_id%3Dstate%26applied_filter_name%3DUbicaci%C3%B3n%26applied_filter_order%3D13%26applied_value_id%3DTUxBUENPUmFkZGIw%26applied_value_name%3DC%C3%B3rdoba%26applied_value_order%3D11%26applied_value_results%3D120%26is_custom%3Dfalse%26view_more_flag%3Dtrue"
response = ProductsSpider.process(url)
if response[:status] == :completed && response[:error].nil?
flash.now[:notice] = "Successfully scraped url"
else
flash.now[:alert] = response[:error]
end
rescue StandardError => e
flash.now[:alert] = "Error: #{e}"
end
Im building a basic rails web scraper and im running into this error. Here is my scraper method and my scraper model too.
https://gyazo.com/d866cd8def5ac107ea8c13515faac989
class RestaurantsScraper < Kimurai::Base
#name = 'restaurants_scraper'
#engine = :mechanize
def self.process(url)
url = 'tripadvisor.com/Restaurants-g31892-Rogers_Arkansas.html'
#start_url = [url]
self.crawl!
end
def parse(response, url:, data: {})
response.xpath("//div[#class=_1llCuDZj]").each do |t|
item = {}
item[:title] = t.css('a._15_ydu6b')&.text&.squish&.gsub('[^0-9].', '')
item[:type] = t.css('span._1p0FLy4t')&.text&.squish
item[:reviews] = t.css('span.w726Ki5B').text&.squish
item[:top_reviews] = t.css('a._2uEVo25r _3mPt7dFq').text&.squish
Restaurant.where(item).first_or_create
end
end
end
def scrape
url = 'https://www.tripadvisor.com/Restaurants-g31892-Rogers_Arkansas.html'
response = RestaurantsScraper.process(url)
if response[:status] == :completed && response[:error].nil?
flash.now[:notice] = "Successfully scraped url"
else
flash.now[:alert] = response[:error]
end
rescue StandardError => e
flash.now[:alert] = "Error: #{e}"
end
I'm new to rails and programming and I keep getting the above error when I try to view the user with id "2". I'm using the twitter-omniauth and twitter gems to view a users tweets. I have no clue whats wrong, any help would be really appreciated.
class UsersController < ApplicationController
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(params[:id])
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
def indexed
#providers = Providers.for(#user)
end
These are my models.
user.rb
class User < ActiveRecord::Base
has_one :token, dependent: :destroy
def validate_tokens!
tokens.each(&:validate_token!)
end
feed.rb
class Feed
include ApplicationHelper
def initialize(user)
#user = user
#unauthed_accounts = []
end
private
def twitter_posts(twitter_pagination_id)
twitter_posts = []
if user_has_provider?('twitter', #user)
twitter_timeline = Twitter::Timeline.new(user)
begin
twitter_posts = twitter_timeline.posts(twitter_pagination_id).map { |post| Twitter::Post.from(post) }
#twitter_pagination_id = twitter_timeline.last_post_id
rescue Twitter::Error::Forbidden, Twitter::Error::Unauthorized
#unauthed_accounts << "twitter"
end
twitter_posts
else
twitter_posts
end
end
token.rb
class Token < ActiveRecord::Base
validates :provider, presence: true
validates :uid, presence: true
belongs_to :user
def self.by_name(name)
where(provider: name)
end
def self.update_or_create_with_twitter_omniauth(id, auth)
token = where(provider: auth["provider"], uid: auth["uid"]).first_or_initialize
token.provider = auth["provider"]
token.uid = auth["uid"]
token.access_token = auth["extra"]["access_token"].token
token.access_token_secret = auth["extra"]["access_token"].secret
token.user_id = id
token.save!
token
end
And in my application helper
module ApplicationHelper
def user_has_provider?(provider, user)
#user.token.by_name(provider).any?
end
end
Error:
app/helpers/application_helper.rb:14:in `user_has_provider?'
app/models/feed.rb:27:in `twitter_posts'
app/models/feed.rb:18:in `posts'
app/controllers/users_controller.rb:62:in `feed'
Issue is on line: feed = Feed.new(params[:id])
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(params[:id]) # HERE AT THIS LINE!!
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
It should be:
def feed
#title = "Feed"
#providers = Providers.for(#user)
#user = User.find(params[:id])
feed = Feed.new(#user) # Should be #user!!
#timeline = feed.posts(params[:twitter_pagination])
#unauthed_accounts = feed.unauthed_accounts
#poster_recipient_profile_hash = feed.poster_recipient_profile_hash
#commenter_profile_hash = feed.commenter_profile_hash
#load_more_url = feed_content_path(
:twitter_pagination => feed.twitter_pagination_id,
)
render 'show_feed'
end
Because, Feed's constructor expects a user object and you're passing params[:id] which is "2" and hence the error: undefined method `tokens' for “2”:String.
I am using resque to process a file in the background. It's a CSV file however I get the following error: uninitialized constant ImportFileHelper::CSV
I have tried to require 'csv' and also include CSV neither will work.
require 'csv'
module ImportFileHelper
HOST = ""
USER_NAME = ""
PASSWORD = ""
def self.process_file(file_data, file_name)
init
#file_name = file_name
begin
csv = CSV.parse(file_data, :headers => true)
csv.each do |row|
#first_name = row["FirstName"]
#last_name = row["LastName"]
#email = row["Email"]
#password = "ch#ngeM3!"
#user_group_name = row["GroupName"].split(",")
#store_name = row["StoreName"]
#external_id = row["ExternalID"]
add_user unless #first_name.nil? || #last_name.nil? || #email.nil? || #password.nil? || #first_name.empty? || #last_name.empty? || #email.empty?
end
rescue NoMethodError => no_method_error
log_error_to_db no_method_error
rescue IOError => error
log_error_to_db error
#errors << error.to_s
rescue Exception => ex
log_error_to_db ex
end
prep_soap_responses_for_output
end
def self.init
HTTPI.log = false
#body = { username: USER_NAME, password: PASSWORD }
#errors = []
#existing_users = []
configure_savon
get_all_groups
get_all_stores
end
def self.prep_soap_responses_for_output
[#existing_users, #errors]
end
def self.log_error_to_db(error)
error.backtrace ||= "Not Available"
if error.message.length > 250
error_message = "There was an error"
else
error_message = error.message
end
ErrorLog.create(message: error_message, trace: error.backtrace, file_name: #file_name)
end
def self.get_store_id
#store_id = #stores[#store_name.to_sym]
end
def self.get_all_stores
#stores = { }
client = Savon::Client.new(HOST + "Storews.asmx?wsdl")
body_data = { mall_id: 1, is_return_offline_store: :false }
#body.merge! body_data
begin
response = client.request :get_store_list, body: #body
if response
hash_response = response.to_hash
stores = hash_response[:get_store_list_response][:get_store_list_result][:store]
stores.each do |s|
store = { s[:name].to_sym => s[:store_id] }
#stores.merge! store
end
end
rescue Savon::Error => ex
log_error_to_db error
#errors << error.to_s
end
end
def self.create_adbuilder_user_object
AdbuilderUser.new(#first_name, #last_name, #email, #user_id, #store_id, #store_name, #user_group_name, #group_id, #external_id)
end
def self.configure_savon
Savon.configure do |configure|
configure.log = false
end
end
def self.add_user
body_data = { first_name: #first_name, last_name: #last_name, user_password: #password, email: #email, external_id: #external_id }
#body.merge! body_data
begin
client = Savon::Client.new(HOST + "UserWS.asmx?wsdl")
response = client.request :add_user, body: #body
if response
#user_id = response.body[:add_user_response][:add_user_result]
if #user_group_name
get_group_id
end
if #store_name
#store_id = get_store_id
unless #store_id.to_s =~ /^0$/
adbuilder_user = create_adbuilder_user_object
UserMailer.create_password(adbuilder_user).deliver if adbuilder_user
end
end
end
rescue Savon::Error => error
log_error_to_db error
if error.message == "(soap:Client) 3: A user with the same email login already exists. Please choose a different login."
#existing_users << #email
else
#errors << error.to_s
end
rescue Exception => error
log_error_to_db error
#errors << error.message.to_s
end
end
def self.get_group_id
begin
#user_group_name.each do |group_name|
user_group_id = #groups_info[group_name.downcase.to_sym]
add_user_to_group user_group_id if user_group_id
end
rescue Exception => error
log_error_to_db error
#errors << error.message.to_s
end
end
def self.get_all_groups
#groups_info = {}
begin
client = Savon::Client.new(HOST + "Usergroupws.asmx?wsdl")
response = client.request :get_user_group_list, body: #body
if response
group = response.to_hash
groups = group[:get_user_group_list_response][:get_user_group_list_result][:user_group]
groups.each do |g|
new_hash = { g[:name].gsub(/\s/, "_").downcase.to_sym => g[:user_group_id] }
#groups_info.merge! new_hash
end
end
rescue Savon::Error => error
log_error_to_db
#errors << error.to_s
end
end
def self.add_user_to_group(group_id)
body_data = { user_id: #user_id, user_group_id: group_id }
#body.merge! body_data
begin
client = Savon::Client.new(HOST + "Usergroupws.asmx?wsdl")
response = client.request :add_user_to_group, body: #body
rescue Savon::Error => error
log_error_to_db error
#errors << error.to_s
end
end
end
So as a work around for this I am doing the csv parsing in the resque job file. This is now allowing it to run. Not sure if this is the best way to do it though.
class ProcessFile
#queue = :rts_file_parser
def self.perform(file_data, file_name)
csv = CSV.parse(file_data, :headers => true)
csv.each do |row|
row_data = { first_name: row["FirstName"], last_name: row["LastName"], email: row["Email"], password: "ch#ngeM3!", user_group_name: row["GroupName"].split(","), store_name: row["StoreName"], external_id: row["ExternalID"] }
ImportFileHelper.process_file file_name, row_data
end
end
end
Mind if I claim the answer (via my comment)?
It looks like it might be a scope resolution issue.
Try ::CSV instead of CSV.
Try adding the gem to the gemfile.
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