I have this background job that run once once per day via resque-scheduler
#user = User.all
#user.each do |u|
current_user = u.id #this does not doe the job
twt = Tweet.where(user_id: u.uid).where(status_id: 0).order(:created_at, :id).first
if twt
twt.status_id = 1
twt.save
$client.update(twt.text)
end
Currently this code dies all the tweet updates $client.update(twt.text) to the first ever logged in user. What I want it to do is to set the twitter oauths current user to the currently selected user in the #user.each do |u| each loop and post the tweet to its specific account. How can I change the current_user attributes while the user is not actively logged in?
Update
The current_user is determined by these methods in user.rb
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_secret = auth.credentials.secret
user.save!
end
end
then the current_user is set in the sessions_controller
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
if Subscription.where(user_id: current_user.uid).present?
redirect_to root_path
else
redirect_to new_subscription_path
end
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
def session_params
params.require(:user_id).permit!
end
end
Related
I've got a class method called authenticate, which works on the User class.
def self.authenticate(email:, password:)
result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")
User.new(result[0]['id'], result[0]['email'])
end
I have an Rspec test;
feature 'authentication' do
it 'a user can sign in' do
User.create(email: 'test#example.com', password: 'password123')
visit 'sessions/new'
fill_in(:email, with: 'test#example.com')
fill_in(:password, with: 'password123')
click_button 'Sign In'
expect(page).to have_content 'Welcome, test#example.com'
end
end
When running Rspec, I get the following error;
1) authentication a user can sign in
Failure/Error:
def initialize(id:, email:)
#id = id
#email = email
end
ArgumentError:
wrong number of arguments (given 2, expected 0)
# ./lib/user.rb:15:in `initialize'
# ./lib/user.rb:23:in `new'
# ./lib/user.rb:23:in `authenticate'
# ./app.rb:84:in `block in <class:BookmarkManager>'
Below is my Sinatra app;
require 'sinatra/base'
require './lib/bookmark'
require './lib/user'
require './database_connection_setup.rb'
require 'uri'
require 'sinatra/flash'
require_relative './lib/tag'
require_relative './lib/bookmark_tag'
class BookmarkManager < Sinatra::Base
enable :sessions, :method_override
register Sinatra::Flash
get '/' do
"Bookmark Manager"
end
get '/bookmarks' do
#user = User.find(session[:user_id])
#bookmarks = Bookmark.all
erb :'bookmarks/index'
end
post '/bookmarks' do
flash[:notice] = "You must submit a valid URL" unless Bookmark.create(url: params[:url], title: params[:title])
redirect '/bookmarks'
end
get '/bookmarks/new' do
erb :'bookmarks/new'
end
delete '/bookmarks/:id' do
Bookmark.delete(id: params[:id])
redirect '/bookmarks'
end
patch '/bookmarks/:id' do
Bookmark.update(id: params[:id], title: params[:title], url: params[:url])
redirect('/bookmarks')
end
get '/bookmarks/:id/edit' do
#bookmark = Bookmark.find(id: params[:id])
erb :'bookmarks/edit'
end
get '/bookmarks/:id/comments/new' do
#bookmark_id = params[:id]
erb :'comments/new'
end
post '/bookmarks/:id/comments' do
Comment.create(text: params[:comment], bookmark_id: params[:id])
redirect '/bookmarks'
end
get '/bookmarks/:id/tags/new' do
#bookmark_id = params[:id]
erb :'/tags/new'
end
post '/bookmarks:id/tags' do
tag = Tag.create(content: params[:tag])
BookmarkTag.create(bookmark_id: params[:id], tag_id: tag.id)
redirect '/bookmarks'
end
get '/users/new' do
erb :'users/new'
end
post '/users' do
user = User.create(email: params[:email], password: params[:password])
session[:user_id] = user.id
redirect '/bookmarks'
end
get '/sessions/new' do
erb :'sessions/new'
end
post '/sessions' do
user = User.authenticate(email: params[:email], password: params[:password])
if user
session[:user_id] = user.id
redirect('/bookmarks')
else
flash[:notice] = 'Please check your email or password.'
redirect('/sessions/new')
end
end
run! if app_file == $0
end
Below is the full User class
require_relative './database_connection'
require 'bcrypt'
class User
def self.create(email:, password:)
encypted_password = BCrypt::Password.create(password
)
result = DatabaseConnection.query("INSERT INTO users (email, password) VALUES('#{email}', '#{encypted_password}') RETURNING id, email;")
User.new(id: result[0]['id'], email: result[0]['email'])
end
attr_reader :id, :email
def initialize(id:, email:)
#id = id
#email = email
end
def self.authenticate(email:, password:)
result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")
User.new(result[0]['id'], result[0]['email'])
end
def self.find(id)
return nil unless id
result = DatabaseConnection.query("SELECT * FROM users WHERE id = #{id}")
User.new(
id: result[0]['id'],
email: result[0]['email'])
end
end
What I don't understand is, why is Rspec saying it was expecting 0 arguments, when the initialize method clearly requires two arguments (id, and, email)?
I need to take the id and email method from authenticate and deliver it to initialize.
I thought that's what I was doing, but both Rspec and sinatra are saying otherwise.
Thanks, in advance.
Here you are passing id as sequential args (in the authenticate method).
User.new(result[0]['id'], result[0]['email'])
However your User.new expects keyword args:
def initialize(id:, email:)
Simply pass them this way:
User.new(id: result[0]['id'], email: result[0]['email'])
Also, just something I noticed, if your DatabaseConnection.query returns no results your authenticate will raise an error from result[0]['id'] (it will say "Undefined method [] for Nil:NilClass". Maybe you should fix this and add a test case for it, for example:
def self.authenticate(email:, password:)
result = DatabaseConnection.query(
"SELECT * FROM users WHERE email = '#{email}'"
)
record = result[0]
if record
User.new(id: result[0]['id'], email: result[0]['email'])
end
end
This way the method will return nil if there's no matching user, and your if user inside post '/sessions' will work properly.
I'm working on a Rails 5 app using the omniauth-bnet gem, not devise, have a Single Sign On through that gem, and have a few User types, using Single Table Inheritance. For whatever reason, the admin type can login fine, but the average User cannot create a session. Here's some of the relevant code.
items_controller.rb:
before_action :check_authorization, except: [:show]
before_action :check_for_email, except: [:show]
...
private
def check_authorization
unless current_user
redirect_to root_path
end
end
def check_for_email
unless current_user.email
redirect_to signup_add_email_url
end
end
sessions_controller.rb:
class SessionsController < ApplicationController
def create
begin
#user = User.from_omniauth(request.env['omniauth.auth'])
session[:user_id] = #user.id
flash[:success] = "Well met, #{#user.name}!"
rescue
flash[:warning] = "There was an error while trying to create your
account..."
end
redirect_to items_path
end
...
admin_user.rb:
class AdminUser < User
end
normal_user.rb:
class NormalUser < User
end
user.rb:
class User < ApplicationRecord
...
class << self
def from_omniauth(auth_hash)
user = find_or_create_by(name: auth_hash['info']['battletag'], uid:
auth_hash['uid'], provider: auth_hash['provider'])
user.name = auth_hash['info']['battletag']
user.uid = auth_hash['uid']
user.token = auth_hash['credentials']['token']
user.save!
user
end
end
routes.rb:
...
# Auth
get '/auth/:provider/callback', to: 'sessions#create'
...
The logs show that my NormalUser type session never gets created. Yet the AdminUser type doesn't have any problem logging in...
Any ideas? I've tried everything I can google or think of.
Basically I'm trying to port the code as seen here to Sinatra and Sequel: How to use bcrypt() in your Rails application
As a matter of fact, I am trying to write simple signup and login methods in a Sequel User model, which currently looks like this:
require 'sequel'
require 'bcrypt'
USERNAME_REGEXP = /^(\w){1,32}$/
# This file is called user.rb and it contains the User class, adding custom
# behavior to 'users' dataset by following its business logic.
class User < Sequel::Model(:users)
include BCrypt
one_to_many :items
one_to_many :reactions
plugin :validation_helpers
def validate
super
validates_unique(:username, :email)
validates_presence([:username, :password, :email])
validates_format(USERNAME_REGEXP, :username)
end
def password
#password ||= Password.new(password_hash)
end
def password=(new_password)
#password = Password.create(new_password)
self.password_hash = #password
end
def signup(params = {})
#user = User.new(username: params[:username], email: params[:email])
#user.password = params[:password]
#user.save
end
def login(params = {})
#user = User.where(username: params[:username], delete: false).first
if #user.password == params[:password]
session[:user_id] = #user.id
redirect to("/#{#user.username}")
else
redirect to('/login')
end
end
end
Then my Sinatra app.rb is requiring the Sequel User model - so my question is: can I access params and session hash this way, without requiring Sinatra in the model?
Thank you very much in advance for your help!
So I`m using the google-api-ruby-client to make a google analytics app, and I wanted to log in every time with a specific user instead of having to be redirected to oauth everytime.
My question is: is there any way to insert the login/password of that client into the code so when I use the app I don't have to authorize anything?
Here is the code that makes the autentication:
class TokenPair
attr_accessor :id
attr_accessor :refresh_token
attr_accessor :access_token
attr_accessor :issued_at
def initialize
##id ||= 1
self.id = ##id
##id += 1
end
def self.get(id)
##els ||= {}
tp = ##els.fetch(id, TokenPair.new)
##els[tp.id] = tp
end
def update_token!(object)
self.refresh_token = object.refresh_token
self.access_token = object.access_token
#self.expires_in = object.expires_in
self.issued_at = object.issued_at
end
def to_hash
{
refresh_token: refresh_token,
access_token: access_token,
# expires_in: expires_in,
issued_at: issued_at ? Time.at(issued_at) : ''
}
end
end
def logout
reset_session
redirect_to root_url
end
def logged_in?
if session["token_id"]
redirect_to profile_path
end
end
def login
logged_in?
end
def self.params
##params
end
def update_token
#client = Google::APIClient.new
#client.authorization.client_id = '209273986197.apps.googleusercontent.com'
#client.authorization.client_secret = '6sCG5ynCiz9Ej07pwIm653TU'
#client.authorization.scope = 'https://www.googleapis.com/auth/analytics.readonly'
#client.authorization.redirect_uri = callback_url
#client.authorization.code = params[:code] if params[:code]
logger.debug session.inspect
if session[:token_id]
# Load the access token here if it's available
token_pair = TokenPair.get(session[:token_id])
#client.authorization.update_token!(token_pair.to_hash)
end
if #client.authorization.refresh_token && #client.authorization.expired?
#client.authorization.fetch_access_token!
end
#analytics = #client.discovered_api('analytics', 'v3')
unless #client.authorization.access_token || request.path_info =~ /^\/oauth2/
redirect_to authorize_path
end
end
def authorize
redirect_to #client.authorization.authorization_uri.to_s, :status => 303
end
def callback
begin
#client.authorization.fetch_access_token!
# Persist the token here
token_pair = TokenPair.get(session[:token_id])
token_pair.update_token!(#client.authorization)
session[:token_id] = token_pair.id
redirect_to profile_url
rescue ArgumentError
redirect_to root_url
end
end
def get_web_properties
result = #client.execute(
api_method: #analytics.management.profiles.list,
parameters: {accountId: "~all", webPropertyId: "~all"}
#parameters: {accountId: "582717"}
)
result.data
end
Even if your app is always acting as the same user, OAuth is still the preferred mechanism for various reasons -- easier to revoke access, limited access in case of compromise, client login auth mechanism is deprecated, etc.
By default the client will request offline access, which allows you to keep refreshing the access token indefinitely without having to go through the full oauth flow each time. You can simply authorize the app once, save the refresh token, and when it expires, just call fetch_access_token! again. If you're using the latest version of the library, the client will automatically attempt refreshing the token if it expired, so all you need to take care of is the initial authorization & storage of the refresh token.
Problem localhost:3000/users/ won't display
I enter humbly as I am trying to make it through the rails tutorial for the first time. I am in chapter 10 and I have been trouble shooting this for 5 hours. When I attempt to visit localhost:3000/users/ I get an error (I believe this has something to do with factory_girl) that explain that the #users variable is empty and that I forgot to pass a collection object for will_paginate.
I'm currently at chapter 10, section 10.23 and each time I run:
$ bundle exec rake db:reset $ bundle exec rake db:populate
$ bundle exec rake db:test:prepare
I get an error explaining that
rake aborted!
Factory already registered: micropost
This is my second time trying this chapter as I encountered problems the first time and started from chapter 9. Please help and be clear and detailed when providing directions. I am happy to post whatever files that will be helpful.
Here is my index.html.erb - I save these as HTML, should they be saved as ruby files instead?
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<%= render #users %>
</ul>
<%= will_paginate %>
Here is my users controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
end
def new
#user = User.new
end
def index
#title = "All users"
#users = User.paginate(:page => params[:page])
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Do more of the things you love!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_url
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
In your Users controller, make sure you have #users and if you are using will_paginate, make sure you call .paginate(page: params[:page], per_page: 20] and in your view, have <%= will_paginate #users %>.
/users should point to UsersController#index. Make sure you are assigning the collection #users.
For instance it could look like this at the most basic level:
def index
#users = User.all # not paginated
#users = User.paginate(page: params[:page]) # paginated
end
As far as the test database error, I'm guessing that's because you define a :micropost factory more than once.
Instead of #user = User.find(params[:id]) this you should use
#users = User.paginate(page: params[:page])