How to choose object in file.yml and update only this object - ruby

I have this structure in file.yml
- !ruby/object:Account
name: Anton
login: Anton1231
password: Antonqwe
age: '37'
card: []
When i sign_in in account, i can add some card. Question - How can i find object from file where login and password == login, password account in which i sign_in and update only card

require 'yaml'
# assume your class looks something like this
class Account
attr_reader :name, :login, :password, :age
attr_accessor :card
end
def read_accounts
File.open('file.yml') { |f| YAML.load_stream(f) }
end
def write_accounts(accounts)
File.open('file.yml', 'r+') do |f|
accounts.each { |a| f.write YAML.dump(a) }
end
end
def update_card(account, card)
account.card << card
end
def find_account(accounts, login, password)
accounts.each do |acct|
return acct if acct.login == login && acct.password == password
end
nil
end
# assume these are set somewhere
#login = 'Anton1231'
#password = 'Antonqwe'
#card = 'a card'
accounts = read_accounts
account = find_account(accounts.first, #login, #password) # accounts.first as accounts is a 2d array
update_card(account, #card) if account
write_accounts accounts
Inspiration from this answer: How to read ruby object in YAML

Related

When Running Rspec and Sinatra, I keep getting ArgumentError: wrong number of arguments (given 2, expected 0)

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.

How to change current_user twitter oauth for running background jobs

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

How to access Sinatra params hash and set Sinatra session hash from Sequel model?

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!

Ruby BCrypt password comparisons return incorrect evaluation

In order to store my user's passwords securely, I'm attempting to use BCrypt in my Sinatra/Ruby application.
The following code is of my User model.
require 'mongo_mapper'
require 'bcrypt'
# User model
class User
include MongoMapper::Document
include BCrypt
key :email, String, length: 6..50, unique: true
key :password, String
key :password_hash, String
def password
#password ||= Password.new(password_hash)
end
def password=(new_password)
#password = Password.create(new_password)
self.password_hash = #password
end
def self.authenticate(requested_email, requested_password)
u = self.find_by_email(requested_email)
u if u && u.password_hash == requested_password
end
end
# Test user account
if User.count == 0
user = User.new(email: "bar#foo.com")
user.password = "admin"
user.save
end
When I call the authenticate method like so: User.authenticate("bar#foo.com", "admin"), the code returns false. I am certain the user exists.
EDIT:
u.password == requested_password returns false as well
Why does this happen, even when the values being passed to the method are valid and correct?
create a key called secret, delete password and password_hash.
Change your code to:
def password=(password)
self.secret = BCrypt::Password.create(password)
end
def password
return BCrypt::Password.new(secret) if self.secret
nil
end

Best way to Map data?

I wanna map some data from facebook into my User class. I read now some articles about inheritance, extending, including and so on. But maybe I understand something wrong.
Is this the right approach for DataMapping in Ruby?
class User
attr_accessible :name, :address
def map_facebook
FacebookUserMapper.new(facebook_object, self)
end
end
class FacebookUserMapper
def initialize(facebook_user, user)
#facebook_user = facebook_user
#user = user
mapit
end
def self.map_it()
username
address
return #user
end
def username
#user.username = #facebook_user.name
end
def address
#user.address = #facebook_user.address
end
end
I would do like this:
def mapFacebook
FacebookUserMapper.new(facebook_object, self).call
end
class FacebookUserMapper
def initialize(facebook_user, user)
#facebook_user = facebook_user
#user = user
end
def call
username
address
self
end
# ...
end
FYI: Don't add () around methods in Ruby
The better way to map the facebook object on to your user model would be this
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
auth is the facebook object here.
tap just allows you do do something with an object inside of a block, and always have that block return the object itself.
This is a code snippet from a Railscasts episode from which you could get even more help for your facebook related app.

Resources