`send_tweet': undefined method `update' for nil:NilClass (NoMethodError) - ruby

I've been looking for the answer to my problem forever. For some reason I get this error: send_tweet': undefined methodupdate' for nil:NilClass (NoMethodError)'
whenever I try to run my ruby script. I don't know how to fix this.
Here's the code:
class TwitterConnect
def intialize
#client = Twitter::REST::Client.new do |config|
config.consumer_key = "CONSUMER KEY"
config.consumer_secret ="CONSUMER SECRET"
config.access_token = "ACCESS TOKEN"
config.access_token_secret = "ACCESS TOKEN SECRET"
end
#client.middleware.insert_after Twitter::Response::RaiseError, CustomMiddleware
end
def send_tweet (twitterMessage = "Hello world!")
#client.update("New TwitterConnect object intialized")
puts twitterMessage
end
end

If this is all the code you have, your send_tweet method isn't working because #client is never defined. You'll need to fix a couple things to make it work.
First, to have any access, you'll need to create a new instance of the class.
tc = TwitterConnect.new
Then, you'll be able to access your client instance variable within your newly created TwitterConnect object.
tc.send_tweet
If, alternatively, you are already doing this step and still getting the error, the problem is likely in the authentication of your config variables within the initialize method.
Hope that helps!

Related

getting a Twitter::Cursor object with the Twitter gem

I'm playing around with the Ruby Twitter gem and wish to use the methods that are available on the Cursor object. For example, using the Twitter::Cursor I'm supposed to be able to get a an array of all friends by doing
client.friends.to_a
or get a most recent follower with
client.friends.first
However, in my attempt below, when tried to do client.friends.first for kanyewest, I got an error which showed that I'm using the Twitter::User object, not the Twitter::Cursor
undefined methodfriends' for #
How can I use the gem to get a cursor object that will allow me to query Kanye's friends.
client.friends.to_a
Note, I read the documentation for creating a new cursor object but I found it a little abstract. I'm not sure if you're supposed to call the constructor directly? If so, please show me how I'd do that
- (Twitter::Cursor) initialize(attrs, key, klass, request)
My Failing code
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
client = Twitter::REST::Client.new do |config|
config.consumer_key = "8nwa....."
config.consumer_secret = "Wj20r....."
config.access_token = "363......"
config.access_token_secret = "7eydU2n....."
end
kanyewest = client.user("kanyewest")
puts kanyewest.friends.first
client.friends("kanyewest").first should work. friends is a method on client not on Twitter::User

Can't access current_user inside .new do block in the ApplicationController

I'm using devise and the bitbucket api gem and I have a method in my ApplicationController which creates an instance so I can make API calls. To do that, it tries to read the token and secret from the current_user.
This works fine with hardcoded token and secret strings, I'm also able to do puts current_user.inspect before the do block, and that all works fine. I'm also sure that bb_token and bb_secret exist (I'm able to call puts on them individually).
But once I try to create my bitbucket instance, it can't read current_user anymore. Any ideas?
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
def bitbucket
puts "token----------"
puts current_user
#bitbucket = BitBucket.new do |config|
config.oauth_token = current_user.bb_token # replaceing this with hardcoded string works
config.oauth_secret = current_user.bb_secret # replaceing this with hardcoded string works
config.client_id = 'xx'
config.client_secret = 'yy'
config.adapter = :net_http
end
end
end
And the error:
NameError (undefined local variable or method `current_user' for #<BitBucket::Client:0x007fbebc92f540>):
app/controllers/application_controller.rb:12:in `block in bitbucket'
app/controllers/application_controller.rb:11:in `bitbucket'
It seems block passed to BitBucket.new is executed in context of new BitBucket::Client instance (BitBucket.new is really BitBucket::Client.new, according to this).
A glance to the source confirms this supposition.
If you want to pass current_user, you can recall that the blocks are closures, so they keep the context in which they are defined. So you can do something like this:
def bitbucket
# (...)
user = current_user # local variable assignment
#bitbucket = BitBucket.new do |config|
config.oauth_token = user.bb_token # it works because user is local variable and the block is closure
# (...)
end
end
Inside BitBucket.new do..end block,self is set to config. But current_user is not a instance method of BitBucket class. Thus a valid error is thrown.

uninitialized constant Couch::Couchbase (NameError)

I have this problem:
uninitialized constant Couch::Couchbase (NameError)
./features/step_definitions/lib/couchbase.rb:6:in `get'
./features/step_definitions/StepsLib.rb:130:in `/^I get couch$/'
features/test.feature:4:in `Then I get couch
The code is:
require 'rubygems'
require 'couchbase'
class Couch
def get
client = Couchbase.connect(:bucket => "user", :hostname => "192.168.1.50")
user = client.get("COMMENT-FO-1103")
return user
client.disconnect
end
end
I've been loocking all over, and no clue, I'm no ruby expert.
Thanks.
Try connecting through IRB and see if you get the same error.
Open up an IRB instance and type:
> require 'Couchbase'
You'll get a statement back saying: => true
Then connect as follows:
> c = Couchbase.new("http://localhost:8091/pools/default/buckets/MyBucket")
This should connect you directly to the bucket you wish to operate on.
Then try:
> c.set("mykey", "Some Value")
And you should get a confirmation that the object has been set in the Bucket.
Then use:
> c.get("mykey")
And you should print the value of the object you just set.
Regarding your code above, I'm not sure why exactly you're trying to wrap this call up in a Class? What is your Use case?
I notice on the github page that methods like get aren't run on client itself, but instead are used in a block argument to run like:
client.run { |conn| conn.get("COMMENT-FO-1103") }
That's really all I can think of there. Hope it helps.
I do notice that return user will prevent the line client.disconnect from ever running, as return kicks you out of the method entirely.

ruby variable scoping across classes

RuNubie here. I've got a class Login that logs into gmail using the net/IMAP library. What is happening is that I create a new instance of that class, such as:
a = Login.new("username", "gmail.com", "passw")
Then, I'm working on other classes that will do some "stuff" with the mailbox. The problem is that the #imap variable I've defined in Login seems to have disappeared (due to scoping I assume).
This is how #imap is declared in Login class:
#imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)
So this:
#today = Date.today
#received_today = imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
...returns an error. These are the two errors I've gotten while playing around with this. The first one is when I use imap, the second one is when I try #imap:
NameError: undefined local variable or method `imap' for #<Object:0x10718d2a8>
NoMethodError: undefined method `search' for nil:NilClass
What are the best practices for dealing with a situation like this? Is the only solution to define my methods that do "stuff" in the same class where I'm creating the new instance of Net::IMAP? Is declaring #imap as a global variable $imap a bad practice? So confused, I bet the answer is very simple and obvious too, but I'm just not seeing it. Thanks!
This:
#received_today = imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
won't work because, well, there is no imap in scope at that point and so you get a NameError. When you try it like this:
#received_today = #imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
You get a NoMethodError because instance variables, such as #imap, are automatically created at first use and initialized as nil. Your real #imap is in another object so you can't refer to it as #imap anywhere else.
I think you want a structure more like this:
class User
def imap
if(!#imap)
#imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false)
# and presumably an #imap.authenticate too...
end
#imap
end
end
class OtherOne
def some_method(user)
#today = Date.today
#received_today = user.imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
end
end
Keep your Net::IMAP localized inside your User and let other objects use it by providing a simple accessor method.
Oh and that global $imap idea, I'll just pretend I didn't see that as globals are almost always a really bad idea.
a shorter way to define the imap variable in the User class, which is pretty much the same as what mu posted:
class User
def imap
#imap ||= Net::IMAP.new...
end
end

What is the best way to mock a 3rd party object in ruby?

I'm writing a test app using the twitter gem and I'd like to write an integration test but I can't figure out how to mock the objects in the Twitter namespace. Here's the function that I want to test:
def build_twitter(omniauth)
Twitter.configure do |config|
config.consumer_key = TWITTER_KEY
config.consumer_secret = TWITTER_SECRET
config.oauth_token = omniauth['credentials']['token']
config.oauth_token_secret = omniauth['credentials']['secret']
end
client = Twitter::Client.new
user = client.current_user
self.name = user.name
end
and here's the rspec test that I'm trying to write:
feature 'testing oauth' do
before(:each) do
#twitter = double("Twitter")
#twitter.stub!(:configure).and_return true
#client = double("Twitter::Client")
#client.stub!(:current_user).and_return(#user)
#user = double("Twitter::User")
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
But, I'm getting this error:
1) testing oauth twitter
Failure/Error: login_with_oauth
Twitter::Error::Unauthorized:
GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
# ./app/models/user.rb:40:in `build_twitter'
# ./app/models/user.rb:16:in `build_authentication'
# ./app/controllers/authentications_controller.rb:47:in `create'
# ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
# ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'
The mocks above are using rspec but I'm open to trying mocha too. Any help would be greatly appreciated.
OK, I managed to figure this out thanks to everyone's help. Here's the final test:
feature 'testing oauth' do
before(:each) do
#client = double("Twitter::Client")
#user = double("Twitter::User")
Twitter.stub!(:configure).and_return true
Twitter::Client.stub!(:new).and_return(#client)
#client.stub!(:current_user).and_return(#user)
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
The trick was figuring out that I needed to stub :configure and :new on the real objects and stub :current_user and :name on a dobuled object instance.
I think the problem is just the way you are using the mock, you created the mock #twitter, but you never actually use it. I think you may be under the impression that any calls to Twitter will use the stubbed methods you specified, but that's not how it works, only calls made to #twitter are stubbed.
I use double ruby, not rspec mocks, but i believe you want to do something like this instead:
Twitter.stub!(:configure).and_return true
...
Twitter::Client.stub!(:current_user).and_return #user
This ensures that anytime the methods you stubbed on Twitter, Twitter::Client are called, they respond how you want.
Also, it seems strange that this is tested as part of a view, should really be part of a controller test instead unless i'm missing something.
You can try using something like http://jondot.github.com/moxy/ . Mock Web Requests

Resources