uninitialized constant ActiveSupport::Memoizable - ruby-on-rails

Been trying to get fb_graph working so i can get things like someones friendlist and i cannot get rid of this error. The ActiveSupport::Memoizable is included in the facebook class. Trying figure it out from a fb_graph example application here https://github.com/nov/fb_graph_sample
image of error: http://imgur.com/VXSHhJf
facebook model:
class Facebook < ActiveRecord::Base
def profile
#profile ||= FbGraph::User.me(self.access_token).fetch
end
class << self
extend ActiveSupport::Memoizable
def config
#config ||= if ENV['fb_client_id'] && ENV['fb_client_secret'] && ENV['fb_scope']
{
:client_id => ENV['fb_client_id'],
:client_secret => ENV['fb_client_secret'],
:scope => ENV['fb_scope'],
}
else
YAML.load_file("#{Rails.root}/config/facebook.yml")[Rails.env].symbolize_keys
end
rescue Errno::ENOENT => e
raise StandardError.new("config/facebook.yml could not be loaded.")
end
def app
FbGraph::Application.new config[:client_id], :secret => config[:client_secret]
end
def auth(redirect_uri = nil)
FbGraph::Auth.new config[:client_id], config[:client_secret], :redirect_uri => redirect_uri
end
def identify(fb_user)
_fb_user_ = find_or_initialize_by_identifier(fb_user.identifier.try(:to_s))
_fb_user_.access_token = fb_user.access_token.access_token
_fb_user_.save!
_fb_user_
end
end
end
and here is facebooks_controller
require 'rack/oauth2'
class FacebooksController < ApplicationController
before_filter :require_authentication, :only => :destroy
rescue_from Rack:.center.hero-unit
%h1 Welcome to Dropshare
%h2
This is the home page for Dropshare
%p (at least for time being)
= render 'layouts/facebook_signup'
= render 'layouts/drive_signup'
/
<haml:loud> provide(:title, &#39;Home&#39;)</haml:loud>
<h1>Home</h1>
<p>This is the home page (for the time being) for Dropshare</p>
Sign up now!
:OAuth2::Client::Error, :with => :oauth2_error
# handle Facebook Auth Cookie generated by JavaScript SDK
def show
auth = Facebook.auth.from_cookie(cookies)
authenticate Facebook.identify(auth.user)
redirect_to dashboard_url
end
# handle Normal OAuth flow: start
def new
client = Facebook.auth(callback_facebook_url).client
redirect_to client.authorization_uri(
:scope => Facebook.config[:scope]
)
end
# handle Normal OAuth flow: callback
def create
client = Facebook.auth(callback_facebook_url).client
client.authorization_code = params[:code]
access_token = client.access_token! :client_auth_body
user = FbGraph::User.me(access_token).fetch
authenticate Facebook.identify(user)
redirect_to dashboard_url
end
def destroy
unauthenticate
redirect_to root_url
end
private
def oauth2_error(e)
flash[:error] = {
:title => e.response[:error][:type],
:message => e.response[:error][:message]
}
redirect_to root_url
end
end
Solution
replace
ActiveSupport::Memoizable
with memoist and require 'memoist'

I think you may be running into the fact that ActiveSupport::Memoizable was deprecated & removed from Rails.
https://github.com/rails/rails/commit/36253916b0b788d6ded56669d37c96ed05c92c5c
The author of that gem is running this version of Rails in their gemfile, so I would presume it's supported through this:
gem 'rails', '~>3.2.11'
I'm guessing you're running a newer version of Rails.

Related

How to get the permanent token for Shopify (Rails)?

I am trying to authenticate my new Shopify app. First, my authenticate method redirects the shop owner to Shopify's authentication page:
def authenticate
ShopifyAPI::Session.setup({:api_key => "123", :secret => "456"})
session = ShopifyAPI::Session.new("someshop.myshopify.com")
redirect_to session.create_permission_url(["read_orders"], "https://myapp.com/shopify/post_authenticate?user=someshop")
end
Once the shop owner has approved the integration, the redirect uri triggers my post_authenticate method:
def post_authenticate
ShopifyAPI::Session.setup({:api_key => "123", :secret => "456"})
session = ShopifyAPI::Session.new("#{params[:user]}.myshopify.com")
token = session.request_token(:code => params[:code], :signature => params[:signature], :timestamp => params[:timestamp])
end
But the request_token method returns the following error:
#<ShopifyAPI::ValidationException: Invalid Signature: Possible malicious login>
I have read somewhere that you need to be in the same ShopifyAPI session while doing all of this, but it does not say so in the documentation. And the example app takes a very different approach than the documentation.
As per my comment, I utilize the omniauth methodology for authenticating. Here's a gist of the code for reference. https://gist.github.com/agmcleod/7106363317ebd082d3df. Put all the snippets below.
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
helper_method :current_shop, :shopify_session
protected
def current_shop
#current_shop ||= Shop.find(session[:shop_id]) if session[:shop_id].present?
end
def shopify_session
if current_shop.nil?
redirect_to new_login_url
else
begin
session = ShopifyAPI::Session.new(current_shop.url, current_shop.token)
ShopifyAPI::Base.activate_session(session)
yield
ensure
ShopifyAPI::Base.clear_session
end
end
end
end
In my login controller:
def create
omniauth = request.env['omniauth.auth']
if omniauth && omniauth[:provider] && omniauth[:provider] == "shopify"
shop = Shop.find_or_create_by_url(params[:shop].gsub(/https?\:\/\//, ""))
shop.update_attribute(:token, omniauth['credentials'].token)
shopify_session = ShopifyAPI::Session.new(shop.url, shop.token)
session[:shop_id] = shop.to_param
redirect_to root_url
else
flash[:error] = "Something went wrong"
redirect_to root_url
end
end
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :shopify, Settings.api_key, Settings.api_secret,
scope: 'write_products,write_script_tags,read_orders',
setup: lambda { |env| params = Rack::Utils.parse_query(env['QUERY_STRING'])
env['omniauth.strategy'].options[:client_options][:site] = "http://#{params['shop']}" }
end
Then in your routes file, map the create action of your session appropriately:
match '/auth/shopify/callback', :to => 'login#create'
From there i use the shopify_session method as an around filter on the appropriate controllers.

Not receiving posts from Facebook realtime API subscriptions with Rails and Koala

Hope you can help, I'm kind of at my wit's end here....I'm working on a Rails App and running Koala to connect with the Facebook Graph API. I want to maintain an up-to-date list of a user's friends who are using my app so I have been trying to implement the Realtime Updates functionality of the Koala gem. My app is deployed on Heroku and I'm running Resque with Redis-to-Go to manage calls from Facebook... unfortunately, I don't seem to be receiving any even though my test pings to the Facebook server are all returning true. Here's the code I'm working with:
Realtime Controller:
class RealtimeController < ApplicationController
skip_before_filter :logged_in_check
layout nil
VERIFY_TOKEN = "purple-rain"
def create
Friendship.real_time_update!(params)
render :text => 'success'
end
def index
Rails.logger.info("RealTimeController verification")
render :text=>Koala::Facebook::RealtimeUpdates.meet_challenge(params, VERIFY_TOKEN)
end
end
Friendship Controller:
class Friendship < ActiveRecord::Base
attr_accessible :friend_id, :user_id
belongs_to :users, :foreign_key => "user_id"
belongs_to :friends_ids, :class_name => "users", :foreign_key => "friend_id"
def self.get_friends(user)
#facebook ||= Koala::Facebook::API.new(user.oauth_token)
#friends = #facebook.get_connection(user.fbid, "friends")
#friends.each do |friend|
if #friend = User.find_by_fbid(friend["id"])
friendship = Friendship.find_or_create_by_user_id_and_friend_id!(user.id,
#friend.id)
end
end
end
def self.real_time_update!(payload)
RealtimeUpdate.new(payload).enqueue_updates!
end
class RealtimeUpdate < Struct.new(:payload)
def enqueue_updates!
remove_duplicate_ids.each do |entry|
if (user = User.find_by_uid(entry['uid']).try(:user))
Resque.enqueue(Resque::Job::UpdateFacebookFriends, user.id,
:since=>entry['time'])
end
end
end
protected
def remove_duplicate_ids
payload['entry'].each_with_object({}) do |entry, hash|
hash[entry['uid']] ||= [] << entry
end.values.collect { |update_payloads| update_payloads.min { |entry1, entry2|
entry1['time']<=>entry2['time'] } }
end
end
end
Resque Job
class Resque::Job::UpdateFacebookFriends
#queue = "facebook_friends"
def self.perform(uid, opts={})
::Timeout.timeout(1800) do
Friendship.get_friends!(User.find_by_fbid(uid))
end
end
end
Happy to provide any other info I can!!!
Thanks in advance!
Make sure that you have specified read_friendlists permission in the rails configuration:
provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], :scope => 'read_friendlists, friends_location'
And please use function get_connections:
#facebook ||= Koala::Facebook::API.new user.oauth_token
#friends = #facebook.get_connection user.fbid, :friends

Koala Rails Authentication

I have the following code:
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :current_user
def facebook_cookies
#facebook_cookies ||= Koala::Facebook::OAuth.new.get_user_info_from_cookie(cookies).symbolize_keys!
end
def current_user
begin
# allow for ?access_token=[TOKEN] for iOS calls.
#access_token = params[:access_token] || facebook_cookies[:access_token]
#graph = Koala::Facebook::API.new(#access_token)
# TODO: move this to session[:current_user]..
#current_user ||= User.from_graph #graph.get_object('me', { fields: 'id,first_name,last_name,gender,birthday' })
rescue
nil # not logged in
end
end
def authenticate
redirect_to(root_url) if current_user.nil?
end
end
(I have setup Koala as described here https://github.com/arsduo/koala/wiki/Koala-on-Rails)
I don't really want to introduce OmniAuth as what I am trying to do is fairly simple. The above code works, the problem is that it is calling Facebook for every page load = not good. I'm guessing I need to store session[:user_id] and then just call User.find(session[:user_id]) for each subsequent request after the user has authenticated?
Can anyone suggest the most efficient way of solving this so I'm not waiting for Facebook on each page load?
You could try something like this:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :current_user, if: Proc.new{ !current_user? }
def facebook_cookies
#facebook_cookies ||= Koala::Facebook::OAuth.new.get_user_info_from_cookie(cookies).symbolize_keys!
end
def current_user
begin
# allow for ?access_token=[TOKEN] for iOS calls.
#access_token = params[:access_token] || facebook_cookies[:access_token]
#graph = Koala::Facebook::API.new(#access_token)
# TODO: move this to session[:current_user]..
#current_user ||= User.from_graph #graph.get_object('me', { fields: 'id,first_name,last_name,gender,birthday' })
rescue
nil # not logged in
end
end
def authenticate
redirect_to(root_url) if current_user.nil?
end
def current_user?
!!#current_user
end
end
I have an implementation that is use for my facebook authentication and authorization.
The code is seperated in non state changing methods and statechanging methods.
Feel free to use the code.
## checks if we have access to fb_info and it is not expired
## Non stagechanging
def oauth_is_online
return !(session[:fb_cookies].nil? or session[:fb_cookies]['issued_at'].to_i + session[:fb_cookies]['expires'].to_i < Time.now.to_i - 10)
end
## checks if the user is in the database
## Non stats changing
def oauth_is_in_database
return oauth_is_online && 0 < User.where(:fb_id => session[:fb_cookies]['user_id']).count
end
## Returns true if it is the specified user
## Non stagechanging
def oauth_is_user(user)
return oauth_is_online && session[:fb_cookies]['user_id'] == user.fb_id
end
## Requires the user to be online. If not, hell breaks loose.
def oauth_require_online
if !oauth_ensure_online
render :file => "public/401.html", :status => :unauthorized, :layout => false
return false
end
return session[:fb_cookies]
end
## Requires the user to be online and the correct user. If not, hell breaks loose.
def oauth_require_user(user)
c = oauth_require_online
return false unless c
return c unless !oauth_is_user(user)
render :file => "public/403.html", :status => :unauthorized, :layout => false
return false
end
## Ensures that the user is online
def oauth_ensure_online
begin
# Checks if the user can be verified af online
if !oauth_is_in_database
# the user is not online. Now make sure that they becomes online.
logger.info "Creates new FB Oauth cookies"
fb_cookies = Koala::Facebook::OAuth.new.get_user_info_from_cookie(cookies)
# TODO In the future the session should be reset at this point
# reset_session
session[:fb_cookies_reload] = false
session[:fb_cookies] = fb_cookies
logger.info "Updating user in database."
# Tries to load the user
#current_user = User.where(:fb_id => session[:fb_cookies]['user_id']).first
logger.info "User exists? => #{#current_user.nil?}"
# creating if not found
#current_user = User.new(:fb_id => session[:fb_cookies]['user_id']) unless !#current_user.nil?
# Loading graph
#fb_graph = Koala::Facebook::API.new(session[:fb_cookies]['access_token'])
# Loading info from graph
me = #fb_graph.get_object('me')
#current_user.name_first = me['first_name'].to_s
#current_user.name_last = me['last_name'].to_s
#current_user.email = me['email'].to_s
#current_user.fb_access_token = session[:fb_cookies]['access_token'].to_s
# Saving the updated user
#current_user.save!
return oauth_is_online
else
# the user is online. Load variables.
#current_user = User.where(:fb_id => session[:fb_cookies]['user_id']).first
#fb_graph = Koala::Facebook::API.new(#current_user.fb_access_token)
end
return oauth_is_online
rescue Koala::Facebook::OAuthTokenRequestError => oe
## TODO handle the diferent errors
# user is not online on facebook
# user have not authenticatet us
# token is used allready once.
logger.debug "FB koala OAuthTokenRequestError: #{oe}"
return false
end
end

Foursquare API with Rails app?

I've set up authentication with the Foursquare API and my Rails app, and now it's time to add functionality. I am not too proficient with Rails - it is not my first language. I want to allow a merchant to connect with Foursquare (Working) and then direct the merchant to a page where they can see unique visitors to their venue, the number of checkins to the venue, and who the mayor of the venue is. I know what endpoints to use, I'm just not sure how to implement them in rails. (Access Token, etc.)
Thanks!
After Answer
I'm trying to implement Turd Ferguson's answer, but I'm not getting anywhere. I keep getting an error saying the method is undefined. I want to try a simple venue search as soon as the user is authenticated. (Create Action)
Also, I'm using OmniAuth for authentication.
sessions_controller.rb
class SessionsController < ApplicationController
require 'foursquare'
def create
auth_hash = request.env['omniauth.auth']
venues = Foursquare::search_venues("starbucks")
render :text => venues
end
def failure
end
def destroy
session[:user_id] = nil
render :text => "Logged out!"
end
def callback
code = params[:code]
#access_token = foursquare.access_token(code, callback_session_url)
session[:access_token] = #access_token
redirect_to examples_path
end
end
foursquare.rb
class Foursquare
def self.search_venues(text)
client.search_venues(:ll => '36.142064,-86.816086', :query => text)
end
def self.client
#client ||= Foursquare2::Client.new(:client_id => '0YO3F0JNZIPVKG1DE01MNPB132D4JZ0QYRQSOWTZQKHHOPKB', :client_secret => 'GMBOGWUNL2GIKZZXQPSLE4BMFNGB5LDHQREH2UKUCK1TJ1L0')
end
end
Have you looked into using a gem such as foursquare2?
Using the gem you could create a Foursquare class like:
class Foursquare
def self.search_venues(text)
client.search_venues(:ll => '36.142064,-86.816086', :query => text)
end
def self.client
#client ||= Foursquare2::Client.new(:client_id => 'your_client_id', :client_secret => 'your_secret')
end
end
You could then call this anywhere you wanted by doing something like:
venues = Foursquare::search_venues "foobar"

User Registration with Devise and Paypal

I want to integrate Paypal within the Devise user registration process. What I want is to have a standard rails form based on the devise resource, that also has custom fields belonging to the user's model.
When a user fills in those fields and clicks on signup, it will be redirected to Paypal, when he clears from paypal and returns to our site then the user data must be created.
For the scenario where the user fill's out the paypal form but doesn't come back to our site, we have to keep record of user before redirecting to Paypal.
For this we can create a flag in user model and use Paypal IPN and when the user transaction notified, set that flag.
But in the case when the user is redirected to Paypal but doesn't complete the transaction, if the user returns to registration and signup again, our model should not throw error saying that the email entered already exists in the table.
How can we handle all these scenarios, is there any gem or plugin available to work with?
Here i am posting the detail code for performing the whole process.
registration_controller.rb
module Auth
class RegistrationController < Devise::RegistrationsController
include Auth::RegistrationHelper
def create
#user = User.new params[:user]
if #user.valid?
redirect_to get_subscribe_url(#user, request)
else
super
end
end
end
end
registration_helper.rb
module Auth::RegistrationHelper
def get_subscribe_url(user, request)
url = Rails.env == "production" ? "https://www.paypal.com/cgi-bin/webscr/?" : "https://www.sandbox.paypal.com/cgi-bin/webscr/?"
url + {
:ip => request.remote_ip,
:cmd => '_s-xclick',
:hosted_button_id => (Rails.env == "production" ? "ID_FOR_BUTTON" : "ID_FOR_BUTTON"),
:return_url => root_url,
:cancel_return_url => root_url,
:notify_url => payment_notifications_create_url,
:allow_note => true,
:custom => Base64.encode64("#{user.email}|#{user.organization_type_id}|#{user.password}")
}.to_query
end
end
payment_notification_controller.rb
class PaymentNotificationsController < ApplicationController
protect_from_forgery :except => [:create]
layout "single_column", :only => :show
def create
#notification = PaymentNotification.new
#notification.transaction_id = params[:ipn_track_id]
#notification.params = params
#notification.status = "paid"
#custom = Base64.decode64(params[:custom])
#custom = #custom.split("|")
#user = User.new
#user.email = #custom[0]
#user.organization_type_id = #custom[1].to_i
#user.password = #custom[2]
if #user.valid?
#user.save
#notification.user = #user
#notification.save
#user.send_confirmation_instructions
end
render :nothing => true
end
def show
end
end

Resources