Use two gems in same namespace in Rails - ruby-on-rails

I have an app that uses the LinkedIn gem but I need to move towards using the LinkedIn OAuth2 implementation which comes in a different gem.
I need to support the requests on oAuth1 in the initial gem for existing users, but I need to support OAuth2 for new users going forwards.
The problem is, both of these gems use the LinkedIn namespace for their module names, and depending on what order I include them in my Gemfile, one clobbers the other.
I tried adding require: false to the gemfile like so:
gem 'linkedin', require: false
gem 'linkedin-oauth2', require: false
But weirdly enough when I go to my console, the first one is still being required, where as the second one is not:
irb(main):001:0> require 'linkedin'
=> false
irb(main):002:0> require 'linkedin-oauth2'
=> true
Is this something to do with how require works? Is it possible to load just one of these gems each in separate lib files without clobbering each other?
EDIT
I figured out that I was requiring the linkedin in one of my spec files, which was causing it to be autoloaded, but that did not still fix the issue of things being clobbered.
When I have both gems installed and I run:
irb(main):001:0> require 'linkedin'
=> true
irb(main):002:0> ::LinkedIn::Client.new
NameError: uninitialized constant Api::QueryHelpers
from /Users/me/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/linkedin-1.1.0/lib/linked_in/client.rb:8:in `<class:Client>'
irb(main):004:0> require 'linkedin-oauth2'
=> true
But if I uninstall linkedin-oauth2 from my gemfile it works just fine:
irb(main):002:0> require 'linkedin'
=> true
irb(main):004:0> ::LinkedIn::Client.new
=> #<LinkedIn::Client:0x007f9eef6d72a8 #consumer_token=nil, #consumer_secret=nil, #consumer_options={}>
Why is that, especially since linkedin-oauth2 is not being required in the first example, yet the error occurs. Could it be because of how they require supporting files in the linkedin gem? Seems still like it shouldn't affect it.

I wouldn't recommend doing this, since it could have some weird side effects such as if linkedin-oauth2 references itself with ::LinkedIn, but a method to redefine a ruby constant is shown in this answer.
I would change it a little bit to prevent renaming a constant warning... Object.send(:remove_const, :Stripe) instead of the Stripe = Module.new as shown in the answer. So, an example (not tested) would be:
require 'linkedin-oauth2'
LinkedInOauth2 = LinkedIn
Object.send(:remove_const, :LinkedIn)
require 'linkedin'

Related

Uninitialized constant Google::Cloud raised by Google::Cloud::Translate.new in production environment

I have a GoogleTranslate service that translates text in my app. The feature works on localhost but in production it raises
uninitialized constant Google::Cloud in my app/helpers/google_translations_helper.rb:4:in `initialize'...
Here is the Gemfile related part :
# use of google API
gem 'google-api-client', '~> 0.11', :require =>
'google/apis/analyticsreporting_v4'
gem 'omniauth-google-oauth2'
gem "google-cloud-translate"
And here is the helper/service initializer:
module GoogleTranslationsHelper
class GoogleTranslate
def initialize
#translation_service = Google::Cloud::Translate.new
end
def translate(text)
#translation_service.translate text.to_s, from: "fr", to: "en"
end
end
end
I wonder if I'm not missing something about gem version or something like that..
Does someone had the problem already?
I assume you are running Rails. Make sure you include:
require "google/cloud/translate"
somewhere reasonable, either at the top of the file that creates the client object (app/helpers/google_translations_helper.rb in your case), or in a global initialization file such as config/application.rb. (The google-cloud-translate library, like most libraries, needs you to require it before you can use it. See the snippets in the documentation for examples.)
It's not completely clear to me why this is working differently between your development and production environments, but there are usually a lot of differences in the initialization procedure between the two environments so it's not too surprising. Just make sure you're in the habit of requiring any library before using it.
As a side note, I would also recommend updating your Gemfile to call for more recent versions of the Google client libraries. Or at least make sure you've done a recent bundle update. As of this writing, google-api-client 0.11 is more than 2 years old; the newest is 0.30.8. And google-cloud-translate is at 1.3.0. It is always possible there are issues if you're on old versions.

Using "require 'my_module'" in ruby on rails

Still learning RoR, sometimes I'll see an example use of a library in plain Ruby that has require 'my_library'.
When we're in Ruby on Rails, are we able to do require? Or does everything have to be included in the gemfile (which I guess both installs and requires the library).
In particular I'm trying to call a API:
class MyModel < ActiveRecord::Base
has_many :other_models
def get_score
require 'rest_client'
response = RestClient.post 'https://sender.blockspring.com/api/blocks/da289f59df228ac4e89cebdfc9aa41fd?api_key=fe5cf0d86af27c086ab5cd4d0eab6641', { items_as_json_string: '[{"time_since_post_in_hours": 5, "upvote_count": 22}, {"time_since_post_in_hours": 3, "upvote_count": 502}]' }
end
end
You absolutely can require things, but you generally don't need to when they are declared in the Gemfile. One particular case where you'd need to require them is if you told it so, such as (in your Gemfile):
gem 'something_very_specific', require: false
Now, you'll need to require it in the "very specific" place you intended to use it.
require is part of Ruby and not unique to Rails. You can require stuff in Rails and it is normally done at the top of the Class and not inside of methods. require simply runs the file to make sure the functionality you are trying to use is loaded.

Rails: Using ruby-gmail gem causes problems

I have the simple following code, which is working in a ruby (not rails) app:
require 'gmail'
Gmail.new('my_account', 'my_password') do |gmail|
end
I am able to get a connection to the Gmail account and do some stuff in there.
However, I want to use this Gem in a Rails app, and therefore I have tried adding the following into the Gemfile:
gem "ruby-gmail", "0.2.1"
gem "mime", "0.1"
However, when I try to use this in a rake task, like this:
task :scrap_receipts_gmail => :environment do
Gmail.new('my_account', 'my_password') do |gmail|
puts gmail.inspect
end
end
I get the following error:
uninitialized constant Object::Gmail
This is solved if I add require 'gmail'. My question is:
Why would I have to require gmail, if I have already specified that in the Gemfile?
The module/class namespace has to match the directory structure. For example, in lib/foo/bar.rb, if and only if the namespace is Foo::Bar can it be auto loaded by Rails, otherwise you have to require it explicitly.
In this case, Gmail is defined as a class, which doesn't match the directory structure. If Gmail was defined as a module (namespace ::Gmail matchs directory structure), then you'll never need to explicitly require "gmail".

Using Datamapper with existing rails application

I have an existing Rails 3 application using ActiveRecord, and I want to switch to Datamapper. The instructions given in the dm-rails page only talk about creating a new application. Does anyone know how to throw away all activerecord dependancies and migrate to datamapper?
Thanks!
It's realtively straightforward, but there are a couple of things you need to do.
In your Gemfile, remove "rails" and instead require the following.
gem 'activesupport', RAILS_VERSION, :require => 'active_support'
gem 'actionpack', RAILS_VERSION, :require => 'action_pack'
gem 'actionmailer', RAILS_VERSION, :require => 'action_mailer'
gem 'railties', RAILS_VERSION, :require => 'rails'
Where RAILS_VERSION is the version of Rails you want to use (e.g. ~> 3.1). This is basically all of rails except ActiveRecord.
At the top of config/application.rb, remove the require for rails (I forget what the original require looks like) and replace it with specific requires for the railties you need.
require "action_controller/railtie"
require "action_mailer/railtie"
I think the only other one is a Test::Unit railtie, but we're not using Test::Unit, so we don't include it.
Finally, if you want to use the identity map (I suggest you do, but it's not needed), place in your ApplicationController's class body:
use Rails::DataMapper::Middleware::IdentityMap
That should be everything; the rest is just configuring your database.yml according to the README (it's pretty much cross-compatible with a standard rails one anyway).
For reference, take a look at what the generators does:
-zsh$ curl http://datamapper.org/templates/rails.rb
apply 'http://datamapper.org/templates/rails/gemfile.rb'
apply 'http://datamapper.org/templates/rails/application.rb'
If you look at the contents of those two files you'll see the extra stuff you'd get if you had used the generator.

Authlogic_OAuth fails with error "uninitialized constant UserSession::OAuth" in Rails 3

I've gotten my application to work (i.e. sign_in and sign_up) with Authlogic and I'm now trying to add support for OAuth through the Authlogic_OAuth gem. I've gotten all of the basics set up (I think) and I've added a "Login with Twitter" button to my landing page. The problem is that when I click the button I get this error:
uninitialized constant UserSession::OAuth
with the application trace:
app/models/user_session.rb:17:in `oauth_consumer'
app/controllers/user_sessions_controller.rb:23:in `create'
The function that is failing is in my user_session model:
# authlogic_oauth hacks
# Twitter example
def self.oauth_consumer
OAuth::Consumer.new("TOKEN", "SECRET",
{ :site => "http://twitter.com",
:authorize_url => "http://twitter.com/oauth/authenticate"})
end
I'm pretty new to rails and ruby so I don't quite understand where this namespace collision is coming from or how to solve it. Any help would be greatly appreciated.
OK, I figured it out. The problem is that OAuth::Consumer is not defined withing authlogic_oauth. It's actually defined in the oauth gem. so I updated my Gemfile to:
gem 'authlogic', '2.1.6'
# set up oauth capabilities. Note: :lib is replaced with :require in rails 3
gem 'authlogic-oauth', '1.0.8', :require => 'authlogic_oauth'
gem 'oauth', '0.4.4'
then run:
bundle install
and, don't forget to restart the rails server so that it reloads the gems from the Gemfile.
Try to change OAuth to ::OAuth. The colons mean that you want to access OAuth from outside your class. It was searching from your class.

Resources