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.