I've followed Railscast 360 to setup Omniauth-Facebook authentication for my Rails app. The authentication works well, but i'm driving myself crazy trying to pass the scope request for additional permissions. I know they are available as I can manually typed the scope request into the url. I have tried everything and exhausted all google searches.
As suggested in the Railscast comments I have downgraded my Omniauth-Facebook gem to 1.4.0 which to my understanding means the scope cannot be passed as a hash from the Omniauth initializer but instead via the javascript. Neither work for me, but unlike the comments i'm running coffee script as per the Railscast, i've tried various placements for scope in this but either get errors or incomplete results....i.e. just email, no user_events etc.
I realise there's no code here, but it's exactly as per the railscast.
Can anyone who's also followed the same Railscast offer any advise on either fixing the issue with 1.4.1 so I can pass the scope hash from the initializer OR how to correctly pass it when running 1.4.0.
Massive thanks in advance!
UPDATE:
I'm kind of getting somewhere! But it's not quite right. Any pointers would be really appreciated.
In my Omniauth initializer I have:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, 'app_id', 'secret_id', {:scope => 'user_birthday,user_events,email'}
end
(With real ids inserted!)
I can then seem to make the correct request by placing the word scope into FB.Init within the coffeescript:
jQuery ->
$('body').prepend('<div id="fb-root"></div>')
$.ajax
url: "#{window.location.protocol}//connect.facebook.net/en_US/all.js"
dataType: 'script'
cache: true
window.fbAsyncInit = ->
FB.init(appId: 'app_id', cookie: true, scope)
$('#sign_in').click (e) ->
e.preventDefault()
FB.login (response) ->
window.location = "/auth/facebook/callback" if response.authResponse
$('#sign_out').click (e) ->
FB.getLoginStatus (response) ->
FB.logout() if response.authResponse
true
(Again with real appid inserted above)
However, this stops the popup working so i'm pretty sure i've placed scope incorrectly. The other examples I have seen place it in FB.login but my attempts to place there have either thrown errors or simply do not work.
Help! :)
Managed to solve this. It was the coffeescript that was throwing me. The try coffeescript tool at http://coffeescript.org/ was very helpful.
The correct placement of scope is as follows:
$('#sign_in').click (e) ->
e.preventDefault()
FB.login ((response) ->
window.location = '/auth/facebook/callback' if response.authResponse), scope: "email,user_events,user_location,user_birthday"
Hope this helps some others.
Related
Rails 3.0.10 and activemerchant gem 1.29.3
My app works fine in sandbox, but transactions in production mode are failing with "Security header is not valid", "ErrorCode"=>"10002"
We initiated a support request with paypal, after reviewing all the configuration parameters a million times and they feel we're hitting an incorrect endpoint. They've asked for a full trace for the transaction, including headers, etc, so I'm trying to figure out how to do that. I found this article
which suggested adding this to the config block
ActiveMerchant::Billing::PaypalGateway.wiredump_device = File.new(File.join([Rails.root, "log", "paypal.log"]), "a")
But that just results in an empty log; nothing gets dumped to it.
So, how can I obtain this info from the GATEWAY object, if possible? Here's the production config, the format of which is identical to what's used in staging env.
::GATEWAY = ActiveMerchant::Billing::PaypalGateway(
:login => 'me_api1.blah...',
:password => 'string...',
:signature => 'longer string...'
)
Thanks.
Needed to add the additional line as follows:
ActiveMerchant::Billing::PaypalGateway.wiredump_device.sync = true
Within the same config block in the environment
Somewhere in the class library you're using there should be a function to output this for you (if it's a well built library, that is.)
Even without that, though, you should be able to look in that PaypalGateway function to see where/how it's setting the endpoint. It's either hard-coding the value or it'll be setting different endpoints based on some sandbox option you have configured somewhere else in the class.
It's hard to tell you more than that without getting a look a the actual class library you're using, but I can concur that it must be either incorrect credentials or an incorrect endpoint. I've never once seen that security header error when it wasn't simply invalid credentials, which means either your values are incorrect or you're hitting the wrong endpoint.
If you want to post that whole function (or maybe even the whole library as the endpoint could be getting set from some other function) I can take a look and find the problem for you.
I've put the following code into my config/environments/test.rb file:
config.action_mailer.default_url_options = { :host => "localhost:3000" }
however when I run my tests, all routes use http://test.host. I'm trying to work with an API that won't accept http://test.host as a valid callback URI, so I need to change this to properly receive the API response. Any idea why this isn't working? (I'm using RSpec, Guard, and Spork in my testing suite).
EDIT: Possibly relevant - this is being done inside of a controller spec.
EDIT2: It seems that it changes after a request is made via get, post, etc. Running the following code within the test:
Rails.logger.debug users_url
get 'http://google.com'
Rails.logger.debug users_url
would produce the following output:
http://localhost:3000/users
...get request related response here
http://google.com/users
Nowadays you can just set them in your test.rb like so:
Rails.application.routes.default_url_options[:host]= 'localhost:3000'
Rails.application.routes.default_url_options[:host]= 'localhost:3000'
In the developemnt.rb / test.rb, can be more concise as following:
Rails.application.configure do
# ... other config ...
routes.default_url_options[:host] = 'localhost:3000'
end
From my experience, url_options will not be passed into tests without a bit of hacking.
See e.g.
How to set locale default_url_options for functional tests (Rails)
http://www.ruby-forum.com/topic/3448797
I've frequently encountered this problem when trying to set the locale in tests. I've never used action mailer, though, so there may be a simpler way to do it.
The solution I've found for setting the default locale in url_options is just to patch actiondispatch and force it to use whatever locale I want it to. You could adapt this to your case this way:
class ActionDispatch::Routing::RouteSet
def url_for_with_default_url_options(options)
url_for_without_default_url_options(options.merge(:host => "localhost:3000" ))
end
alias_method_chain :url_for, :default_url_options
end
I put that code in a file in spec/support so it is used in rspec tests and I also require it from my env.rb file so I can use it in cucumber tests as well.
Keep in mind that this will patch it everywhere, in both test code and in actual code running under tests, and it will override any other settings for the :host key that you try to pass in (since the patch merges the fix on top of the options passed into url_for). In your case I believe that shouldn't be a problem.
Monkey patching is not a very elegant solution, though, and I used this after everything else failed. You might find a simpler solution specific to action mailer.
How are you running your tests? Maybe appending RAILS_ENV=test might help.
Working on my first EmberJS app. The entire app requires that a user be logged in. I'm trying to wrap my head around the best way to enforce that a user is logged in now (when the page is initially loaded) and in the future (when user is logged out and there is no refresh).
I have the user authentication hooks handled - right now I have an ember-data model and associated store that connects that handles authorizing a user and creating a user "session" (using sessionStorage).
What I don't know how to do is enforce that a user is authenticated when transitioning across routes, including the initial transition in the root route. Where do I put this logic? If I have an authentication statemanager, how do I hook that in to the routes? Should I have an auth route that is outside of the root routes?
Note: let me know if this question is poorly worded or I need to explain anything better, I will be glad to do so.
Edit:
I ended up doing something that I consider a little more ember-esque, albeit possibly a messy implementation. I have an auth statemanager that stores the current user's authentication key, as well as the current state.
Whenever something needs authentication, it simply asks the authmanager for it and passes a callback function to run with the authentication key. If the user isn't logged in, it pulls up a login form, holding off the callback function until the user logs in.
Here's some select portions of the code I'm using. Needs cleaning up, and I left out some stuff. http://gist.github.com/3741751
If you need to perform a check before initial state transition, there is a special function on the Ember.Application class called deferReadiness(). The comment from the source code:
By default, the router will begin trying to translate the current URL into
application state once the browser emits the DOMContentReady event. If you
need to defer routing, you can call the application's deferReadiness() method.
Once routing can begin, call the advanceReadiness() method.
Note that at the time of writing this function is available only in ember-latest
In terms of rechecking authentication between route transitions, you can add hooks to the enter and exit methods of Ember.Route:
var redirectToLogin = function(router){
// Do your login check here.
if (!App.loggedIn) {
Ember.run.next(this, function(){
if (router.currentState.name != "login") {
router.transitionTo('root.login');
}
})
}
};
// Define the routes.
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
enter: redirectToLogin,
login: Ember.Route.Extend({
route: 'login',
exit: redirectToLogin,
connectOutlets: function(router){
router.get('applicationController').connectOutlet('login');
}
}),
....
})
});
The problem with such a solution is that Ember will actually transition to the new Route (and thus load all data, etc) before then transitioning back to your login route. So that potentially exposes bits of your app you don't want them seeing any longer. However, the reality is that all of that data is still loaded in memory and accessible via the JavaScript console, so I think this is a decent solution.
Also remember that since Ember.Route.extend returns a new object, you can create your own wrapper and then reuse it throughout your app:
App.AuthenticatedRoute = Ember.Route.extend({
enter: redirectToLogin
});
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: App.AuthenticatedRoute.extend({
...
})
})
});
If you use the above solution then you can cherry pick exactly which routes you authenticate. You can also drop the "check if they're transitioning to the login screen" check in redirectToLogin.
I put together a super simple package to manage session and auth called Ember.Session https://github.com/andrewreedy/ember-session
Please also take a look at :
http://www.embercasts.com/
There are two screencasts there about authentication.
Thanks.
I am putting together a basic CRUD system for a project, and we've decided to bundle in Backbone.js & CoffeeScript to abstract more of our JavaScript functionality. The learning curve has been pretty steep for me, since I'm not much of a JS pro.
At the moment, I'm just trying to pull a record. Any record. So I've rigged a dummy route to supply a 'products' record set via JSON, to see how it renders, before I go forward.
window.Product = Backbone.Model.extend
initialize: -> console.log this
window.Products = Backbone.Collection.extend
model: Product
initialize: -> console.log this
url: '/dummy'
So, in the console, I type:
product = new Product()
And it seems to render the product just fine. But when I type:
product.fetch()
It returns:
TypeError: Cannot call method 'ajax' of undefined
I tried the same thing with the Collection.
products = new Products()
products.fetch()
TypeError: Cannot call method 'ajax' of undefined
I've made other parts (view renders, etc.) work just fine, but this ajax error is getting at me repeatedly. I've spent hours looking through different documentation (including the official ones, and all the information I could trail to from the wiki), trying out the code in plain JavaScript as well as CoffeeScript, implementing different scopes (with/without window namespacing), etc. There's nothing on Google.
This must be something ridiculously simple that I should probably just know, but I can't figure it out for the life of me. Or it was the one spot of the documentation that I missed. Can anyone tell me what I'm doing wrong?
#Ironchamber: In order to use the Ajax method of Backbone, you must also supply a library that provides cross-browser Ajax support. Backbone is optimized to use either jQuery or Zepto. It looks to me from your error message that you're missing one of those.
The other solution is to call this at document ready:
Backbone.setDomLibrary(jQuery);
This way the file include order doesn't matter.
I'm using webflows in Grails and I'm currently writing tests for it. Now, inside I've got something that throws an error so I set a message to the flash scope before redirecting:
...
if (some_condition) {
flash.message = "my error message"
return error()
}
...
Now, I know that when I'm going to display this in the GSP page, I access the flash message as
<g:if test="${message}">...
instead of the usual
<g:if test="${flash.message}">...
So anyway, I'm writing my test and I'm wondering how to test the content of the message? Usually, in normal actions in the controllers, I follow what's written in here . However, since this is a webflow, I can't seem to find the message even if I check controller.flash.message / controller.params.message / controller.message . I've also tried looking at the flow scope...
Any ideas on how to see the message then? Thanks a bunch!
Based on your example, you can access your flash.message as controller.request.message in your webflow test. I did a lot of googling for this same exact issue and a lot of webflow documentations talk about it merging all scopes into the "view model". But I also read somewhere that it merges the flash scope into the request scope for redirection. That's what prompted me to try looking in the controller.request in my test case.