How to access flickr user id from username search API call - ruby-on-rails

I am working on a small app to access the flickr api and serve up photos. I am using the flickr gem for auth. It is working for recent photos, which are displayed if nothing is entered in the form yet. It is working for search by tags. It was working by user_id, but I am trying to change it to accept username, and then use the flickr.people.findByUsername method to get the user id and then use that to pull up the photos. It's easy to find peoples usernames on the flickr website, but hard to find ID's so I think this will be more user friendly. Here's the current version of the app before I branched it to attempt this. https://flickr-photo-feed.herokuapp.com/ It's a very basic app with no model and no database. There is only the index controller action and a very basic form partial and another partial to render the returned photos.
I changed the form to accept username
<div class="form">
<%= form_with url: :root, method: :get do |form| %>
<%= form.text_field :username, placeholder: "Username", class: "form-field" %>
<%= form.text_field :tags, placeholder: "tags", class: "form-field" %>
<%= form.submit 'submit', class: "submit-btn" %>
<% end %>
</div>
Here is the controller:
class StaticPagesController < ApplicationController
require "flickr"
def index
#flickr = Flickr.new
if params[:username].present?
user_id = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id
elsif params[:tags].present?
#photos = #flickr.photos.search tags: params[:tags], safesearch: 1
else
#photos = #flickr.photos.getRecent
end
end
end
If I enter a username, I get this error:
undefined method `delete' for {"id"=>"132822455#N05","nsid"=>"132822455#N05",
"username"=>"images#twiston"}:Flickr::Response Extracted source
(around line #8): 6 7 8 9 10 11
if params[:username].present?
user_id = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id
elsif params[:tags].present?
#photos = #flickr.photos.search tags: params[:tags], safesearch: 1
else
with this error in the rails server:
oauth_args = args.delete(:oauth) || {}
As you can see, I'm getting a response with the nsid in it. I don't quite understand the no method error for delete, but I gather that it is coming from the flickr gem. So, I figure that I need pull the nsid out of the hash and pass it to my api call. So, I change one line to be:
#photos = #flickr.people.getPhotos user_id["nsid"]
which generates this error:
no implicit conversion of Symbol into String
So, I try this:
#photos = #flickr.people.getPhotos user_id[:nsid]
which gives me this error:
undefined method `delete' for nil:NilClass
I even tried this:
#photos = #flickr.people.getPhotos user_id.nsid
which gets me this error:
no implicit conversion of Symbol into String
I have tried a few other things as well, but the result is always one of those error messages. can anyone point out where I'm going wrong? Thank you.
Edit: I've been able to verify that I can puts the user_id["nsid"] and the correct nsid is output to the rails server. However, I still get the "no implicit conversion of symbol to string" error. So, I tried saving it to a variable and explicitly calling .to_str on it before passing it to the #flickr.people.getPhotos method. I have verified with p (not puts) that it does get output as a string. The ""show up around it. However, that particular error persists.
Edit to add the initializers/flickr.rb file:
require "dotenv/load"
require "flickr"
flickr_api_key = ENV["FLICKR_API_KEY"]
flickr_shared_secret = ENV["FLICKR_SHARED_SECRET"]
flickr = Flickr.new flickr_api_key, flickr_shared_secret
# This is the URL Flickr will redirect your users to once they agree to access
#callback_url = "http://localhost:3000/auth_controller/callback"
# Users should hit this method to get the link which sends them to flickr
def auth
flickr = Flickr.new API_KEY, SHARED_SECRET
token = flickr.get_request_token(oauth_callback: URI.escape(#callback_url))
# You'll need to store the token somewhere for when the user is returned to the callback method
# I stick mine in memcache with their session key as the cache key
#auth_url = flickr.get_authorize_url(token["oauth_token"], perms: "delete")
# Stick #auth_url in your template for users to click
end
# Your users browser will be redirected here from Flickr (see #callback_url above)
def callback
flickr = Flickr.new
request_token = # Retrieve from cache or session etc - see above
oauth_token = params[:oauth_token]
oauth_verifier = params[:oauth_verifier]
raw_token =
flickr.get_access_token(
request_token["oauth_token"],
request_token["oauth_token_secret"],
oauth_verifier
)
# raw_token is a hash like this {"user_nsid"=>"92023420%40N00", "oauth_token_secret"=>"XXXXXX", "username"=>"boncey", "fullname"=>"Darren%20Greaves", "oauth_token"=>"XXXXXX"}
# Use URI.unescape on the nsid and name parameters
oauth_token = raw_token["oauth_token"]
oauth_token_secret = raw_token["oauth_token_secret"]
# Store the oauth_token and oauth_token_secret in session or database
# and attach to a Flickr instance before calling any methods requiring authentication
# Attach the tokens to your flickr instance - you can now make authenticated calls with the flickr object
flickr.access_token = oauth_token
flickr.access_secret = oauth_token_secret
end

The documentation is not great, but it looks like it should be:
flickr = Flickr.new "api key", "api secret"
#user = flickr.people.findByUsername username: 'images#twiston'
#=> {"id"=>"132822455#N05", "nsid"=>"132822455#N05", "username"=>"images#twiston"}
Which give you:
#user['nsid']
#=> "132822455#N05"
#user['id']
#=> "132822455#N05"
So your code should be something like:
#user = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id: #user['id']
The findByUsername method returns that hash and you were treating it as if it returns just the :id.
The docs say:
Alternatively, if the API key and Shared Secret are not provided, Flickr will attempt to read them from environment variables:
ENV['FLICKR_API_KEY']
ENV['FLICKR_SHARED_SECRET']
You could use the console to do a manual authentication with the key and secret per my example to make sure it's working right.

response = #flickr.people.findByUsername username: params[:username]
#photos = #flickr.people.getPhotos user_id: response["nsid"]
Beartech was correct. This worked right away.

Related

How to hidden query-string in Rails

I wanna pass to a resource in a request for example
# Go to payment link
<%= link_to 'Payment', checkout_path(pricing: amount.id) %>
When I go to payment link the url path is the next:
http://localhost:3000/checkout?pricing=amount_2aHUHuhdn23jnSJd
I'd like to hidden the query-string "pricing=amount_2aHUHuhdn23jnSJd" without have to used any gem
UPDATE QUESTION 31/12
This request is of type Get since I need to show the different prices to the user, that's why the parameter pass (pricing: amount.id)
<%= link_to 'Payment', checkout_path(pricing: amount.id) %>
get 'checkout', to: 'subscriptions#checkout'
I'd appreciate your time and your grain of sand
You could store it in the Session.
Store it when the user enters the page, clear it when user clicks a link.
# SomeController#before_payment
session[:pricing] = amount.id
#then..
# CheckoutController#index
pricing = session[:pricing]
session[:pricing] = nil
Be careful because it will only live within the session. It will be stored as a cookie, and have a 4kb limit for data.
When the value is sensitive then hiding the value doesn't really fix the problem. Instead, I would suggest encrypting the value in the URL or to use another non-sensitive value instead.
Value encryption
You could use Rails MessageEncryptor to encrypt the value before passing it to the URL and decrypt it later in the controller again.
# in app/models/url_encrypter.rb
module URLEncrypter
ENCRYPTER = ActiveRecord::MessageEncryptor.new(
Rails.application.secrets.secret_key_base.first(32)
)
def encrypt(value)
ENCRYPTOR.encrypt_and_sign(value, purpose: :url)
end
def decrypt(value)
ENCRYPTOR.decrypt_and_verify(value, purpose: :url)
end
end
# when building the URL
<%= link_to 'Payment', checkout_path(pricing: URLEncrypter.encyrpt(amount.id)) %>
# when reading the param in the controller
pricing = URLEncrypter.decyrpt(params[:pricing])
amount = Amount.find(pricing)
Have a second non-sensitive, unique identifier
Here you add a second unique identifier to your database table, for example, a column named uuid which you could populate automatically in a before_save callback with self.uuid = SecureRandom.uuid
You can then use its value instead of the id like this:
# when building the URL
<%= link_to 'Payment', checkout_path(pricing: amount.uuid) %>
# when reading the param in the controller
amount = Amount.find_by(uuid: params[:pricing])
I'm not quite sure what you mean without seeing your routes.rb file. As mentioned by #Deepak Kumar to hide query from your url you should use POST request. Have a look at this guide. You can add below
post 'payment', to: 'checkout#payment'
In your routes.rb. This will call Payment action from your CheckoutsController

Stripe connect doesn't giver error but doesn't create accounts

I am currently working on integrating stripe connect to my app but it isn't working. I don't get any errors when I run it and it asks me to create an account and redirects back to the website but when I check my stripe dashboard, it doesn't show any added accounts. Any help would be appreciated! I looked over their documentation and copied that but I got the same results.
Here is some of my code:
class StripeController < ApplicationController
def connect
response = HTTParty.post("https://connect.stripe.com/oauth/token",
query: {
client_secret: ENV["STRIPE_SECRET_KEY"],
code: params[:code],
grant_type: "authorization_code"
}
)
if response.parsed_response.key?("error")
redirect_to welcome_path,
notice: response.parsed_response["error_description"]
else
stripe_user_id = response.stripe_user_id
current_user.stripe_user_id = stripe_user_id
redirect_to mypage_path,
notice: 'User successfully connected with Stripe!'
end
end
end
module UsersHelper
def stripe_button_link
stripe_url = "https://connect.stripe.com/express/oauth/authorize"
redirect_uri = stripe_connect_url
client_id = ENV["STRIPE_CLIENT_ID"]
"#{stripe_url}?response_type=code&redirect_uri=#{redirect_uri}&client_id=#{client_id}&scope=read_write"
end
end
<% if current_user.stripe_user_id %>
<%= link_to "Go to Stripe Dashboard", stripe_dashboard_path(current_user.id) %>
<% else %>
<%= link_to image_tag("ConnectwithStripe.png", width:"120px", height:"40px"), stripe_button_link %>
<% end %>
Before I dive in to your specific code and question I wanted to flag that using OAuth with Express accounts is no longer recommended by Stripe. You should be creating Express accounts using the /v1/accounts API and using Account Links instead.
With that out of the way, I believe the main issue with your code is that you're using HTTParty.post instead of HTTParty.get. When the user is redirected from the OAuth flow back to your website it will be a regular GET request, not a POST.
Once the user is redirected back to your site you need to use the authorization code in the URL to complete the connection process. It's not clear if the code for this is missing or was omitted from your question, but you need to do something like this somewhere:
response = Stripe::OAuth.token({
grant_type: 'authorization_code',
code: 'AUTHORIZAION_CODE_FROM_URL_HERE',
})
# Store the response.stripe_user_id (the Stripe account ID) in your database for use in the Stripe-Account header when making Connect requests
stripe_account_id = response.stripe_user_id

Instance variables are purged when user fails his authentication

I have trouble getting instances variables while overriding Devise::SessionsController.
When an unauthenticated user add an item to its cart, I want to redirect him to the sign in page and apply the addition after he's authenticated.
1 . I pass the item_id as a URL parameters:
localhost:3000/user_accounts/sign_in?item_id=42
I get back in a hidden field in the form, I can have it through the session creation form:
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.hidden_field :item_id, value: params[:item_id] || #item_id %>
...
<% end %>
When Rails starts his form flow, the URL parameters are removed:
Before:
localhost:3000/user_accounts/sign_in?item_id=42
After:
localhost:3000/user_accounts/sign_in
I don't want to loose the item_id when the user fails his authentication, so I ensure #item_id is exposed as an instance variable, so I can inject it back to the form.
However, on failure, Rails(?) / Devise(?) / Warden(?) seems to purge the instance variables (for security reasons?). As a result, #item_id is nil.
Note that works well when the user successfully authenticate (through URL parameters). Also, I use this very same technique in the registration process and it works in both success (URL parameters) and failure (instances variables) case.
Here is my implementation of SessionsController:
class MySessionsController < Devise::SessionsController
def create
#item_id = parse_id(params[:user_account][:item])
super do |account|
add_to_cart(account, #item_id) if #item_id
end
flash.delete(:notice)
end
end
Do you know how I can fix this ?
I am open to alternatives as well.
I was wrong. Rails, Devise and Warden aren't doing shady things to my instance variables. I found out that a redirection was made, explaining why the context was lost.
In the end, I used cookies to fix the problem as #nattfodd suggested it. This was trivial I don't know why I didn't think of it.
class MySessionsController < Devise::SessionsController
def create
item_id = parse_id(cookies.encrypted[:item])
super do |account|
add_to_cart(account, item_id) if item_id
cookies.encrypted[:item] = ""
end
flash.delete(:notice)
end
end
Cleaner, no hack. Good.

Passing attributes in test url - Rspec / Addressable gem

From a View file I pass attributes in a url:
%= link_to piece_path(#current_piece, file: file, rank: rank), method: :patch do %>
this gives urls like http://localhost:3030/pieces/%23?file=8&rank=8
I need to extract the value of file and rank from this url, to update the database fields (coordinates of a chess piece after a move).
In Controller I'm trying to use the Addressable gem:
def update
(some code)
current_piece.update_attributes(piece_params)
(more code)
end
private
def piece_params
uri = Addressable::URI.parse(request.original_url)
file = uri.query_values.first ## I don't know if "first"
rank = uri.query_values.last ## and "last" methods will work
params.require(:piece).permit({:file => file, :rank => rank})
end
When I inspect uri I get: #<Addressable::URI:0x3fa7f21cc01c URI:http://test.host/pieces/2>
There is no hash of attributes trailing the url. Thus uri.query_values returns nil. I don't know how to mirror such thing in the test.
The error message:
1) PiecesController pieces#update should update the file and rank of the chess piece when moved
Failure/Error: file = uri.query_values.first
NoMethodError:
undefined method `first' for nil:NilClass
In Controller_spec:
describe "pieces#update" do
it "should update the file and rank of the chess piece when moved" do
piece = FactoryGirl.create(:piece)
sign_in piece.user
patch :update, params: { id: piece.id, piece: { file: 3, rank: 3}}
piece.reload
expect(piece.file).to eq 3
expect(piece.rank).to eq 3
end
I can't check if the logic works from the localhost browser (I don't have pieces objects at the moment so I run into errors). Also working on that.
My question regards the test; however if there are suggestions to extract the attributes from the url in different ways I'm all ears!
You don't need to manually parse the request URI to get query params in Rails.
Rails is built on top of the Rack CGI interface which parses the request URI and request body and provides the parameters as the params hash.
For example if you have:
resources :things
class ThingsController < ApplicationController
def index
puts params.inspect
end
end
Requesting /things?foo=1&bar=2 would output something like:
{
foo: 1,
bar: 2,
action: "index",
controller: "things"
}
link_to method: :patch uses JQuery UJS to let you use a <a> element to send requests with other methods than GET. It does this by attaching a javascript handler that creates a form and sends it to the URI in the HREF attribute.
However unlike "normal forms" in rails the params are not nested:
<%= link_to piece_path(#current_piece, file: file, rank: rank), method: :patch do %>
Will give the following params hash:
{
file: 1,
rank: 2
}
Not
{
piece: {
file: 1,
rank: 2
}
}
If you want nested keys you would have to provide the params as:
<%= link_to piece_path(#current_piece, "piece[file]" => file, "piece[rank]" => rank), method: :patch do %>
If your URL is http://localhost:3030/pieces/%23?file=8&rank=8 you should be able to do:
def piece_params
params.require(:piece).permit(:rank, :file)
end
and then access them in your action via params[:rank] and params[:file]
I usually use params[:file].present? to make sure that the params are there before I try to assign the value. Something like this should work:
p = {}
if params[:rank].present?
p[:rank] = params[:rank]
end
if params[:file].present?
p[:file] = params[:file]
end
current_piece.update_attributes(p)
FWIW, you probably shouldn't use the URL string to pass params to a PATCH/PUT request. You might consider passing them via a form or something.
button_to with nested attributes works; in the view file:
<%= button_to piece_path(#current_piece), method: :patch, params: {piece: {file: file, rank: rank}} do %>
And keep it simple in the controller:
def piece_params
params.require(:piece).permit(:rank, :file)
end

parsing # in rails uris

i am getting the following url information and need to parse it within rails. i already checked request and params but it is not there.
the "#" character seems to f*ck up things.
here's the url:
http://foo.bar.me/whoo#access_token=131268096888809%7C2.5BRBl_qt4xJ08n88ycbpZg__.3600.1276880400-100001151606930%7C0kJ1K-qoGBbDoGbLx6s4z5UEaxM.
thanks for any pointers.
You won't be able to access the part after the '#' character as the browser doesn't send it to the server. You can use it on the client side with javascript though.
It seems that you're trying to use the javascript based authentication which is not what you really want.
I didn't have any problems using this oauth2 library. Then you only need to check for params[:code] within your callback action.
UPDATE:
This is a simplified version of the code I used in my experiments with the new facebook graph API:
# Accessible as facebook_url:
# routes.rb: map.facebook '/facebook', :controller => 'facebook', :action => 'index'
def index
oauth2 = OAuth2::Client.new(FB_API_KEY, FB_API_SECRET, :site => 'https://graph.facebook.com')
if current_user.facebook_token
# The user is already authenticated
fb = OAuth2::AccessToken.new(oauth2, current_user.facebook_sid)
result = JSON.parse(fb.get('/me'))
elsif params[:code]
# Here we get the access token from facebook
fb = oauth2.web_server.get_access_token(params[:code], :redirect_uri => facebook_url)
result = JSON.parse(fb.get('/me'))
current_user.facebook_id = result["id"]
current_user.facebook_token = fb.token.to_s
current_user.save
else
# The user is visiting this page for the first time. We redirect him to facebook
redirect_to oauth2.web_server.authorize_url(:redirect_uri => facebook_url, :scope => 'read_stream,publish_stream,offline_access')
end
end
You don't really need anything else for it to work.

Resources