How to compare the IDs of edge classes for truthiness with a many-to-many join table - ruby

I am working in Sinatra on a project, and have the following domain:
User-< User_car >-Car
Within the User_cars table I have the foreign key IDs of the User_ID and the Car_ID.
The issue I'm having is:
patch '/cars/:id' do
#cars = Car.find_by(id: params[:id])
if current_user.id == user_cars.user_id
#cars.update
redirect to "/cars"
else
erb :"/cars/index"
end
end
Also there is the helper method for current_user in ApplicationController:
def current_user
# returns the current_user object if there is one, otherwise nil
# checks the session hash and finds a user based on the :user_id key
#current_user ||= User.find_by(id: session[:user_id])
end
I cannot edit as it stands because I don't have a way to evaluate the current_user as the "owner"/creator of the car with the IDs as they will never evaluate to truthy. I am not even getting an error, I just get forwarded to the /cars/index page.

Related

Rails 5 Scheduling App Find all shifts for a user

We are attempting to create an endpoint that allows for a user to view all of their personal shifts across all calendars. Currently I have the following syntax in the shifts controller:
def myschedule
#user = current_user
if #user
#shifts = Shift.where("end_time > ?", Time.current).order("start_time ASC").limit(100)
render "/shifts/index2.json", status: :ok
else
render json: ('You do not have access to these shifts'), status: :unauthorized
end
end
This as expected is returning the first 100 shifts across all calendars, but for all users. What would be the best direction to search for a way to limit the shifts to just the ones for a specified user. I would appreciate some guidance in the right direction. The json rendered is an array of hashes.
As far as relations go on the model level:
a shift has_many users, through usershifts
a user has_many shifts, through usershifts
both user and shift has_many usershifts
and usershift belongs_to both user and shift.
I attempted:
def myschedule
#user = current_user
if #user
#shifts = Shift.where("end_time > ?", Time.current).order("start_time ASC").limit(100).include?(#user)
render "/shifts/index2.json", status: :ok
else
render json: ('You do not have access to these shifts'), status: :unauthorized
end
end
Which returned undefined method map for false: Falseclass in my json view.
Here is the json view as well:
json.shifts #shifts do |shift|
json.shift_id shift.id
json.start_time shift.start_time
json.end_time shift.end_time
json.calendar_name shift.calendar.name
end
I also tried to throw a .joins(#user) to the end of #shifts, that returned an unknown class User for the json.
Also I attempted:
def myschedule
if current_user
#shifts = Shift.where("end_time > ?", Time.current).order("start_time ASC").limit(100).where(:user_id => params[:user_id])
render "/shifts/index2.json", status: :ok
else
render json: ('You do not have access to these shifts'), status: :unauthorized
end
end
which gave the following error in server log
ActionView::Template::Error (PG::UndefinedColumn: ERROR: column
shifts.user_id does not exist
LINE 1: ...ERE (end_time > '2018-10-13 14:52:02.693352') AND "shifts"."
What would be the best direction to search for a way to limit the
shifts to just the ones for a specified user
This should work
#shifts = #user.shifts.where("end_time > ?", Time.current).order("start_time ASC").limit(100)

Strong parameters and Nested Routes - Rails 4.0

I have no idea how this works in rails but I set up routes like this:
resources :users do
resources :api_keys
end
(User has_many: api_keys, api_key belongs_to: user)
So I then (since I only care about API Keys), created the following controller:
class ApiKeysController < ApplicationController
before_action :authenticate_user!
def index
#user = User.find(params[:user_id])
#api_key = User.apikeys
end
def create
#user = User.find(params[:user_id])
#api_key = ApiKey.new(create_new_api_key)
create_api_key(#api_key, #user)
end
def destroy
destroy_api_key
end
private
def create_new_api_key
params.require(:api_key).permit(user_attributes: [:id], :api_key)
end
end
Which states, authenticate user before every action, index fetches all api keys based on a user id. create is suppose to create an api key based on a user id, (note: create_api_key(#api_key, #user) just an abstracted method that states - if we saved, redirect to user_path with a message, if we failed, back to user path with a error message)
And destroy, well that just finds an api key, destroys it and redirects (again with the abstraction).
Whats the issue?
the create_new_api_key method. Its freaking out and saying:
syntax error, unexpected ')', expecting => (SyntaxError)
I thought this is how I pass in the user id ??
You need to change the order of the arguments passed in to permit to fix the syntax error:
def create_new_api_key
params.require(:api_key).permit(:api_key, user_attributes: [:id])
end

Why can't I find an ActiveRecord instance by its auth token?

def current_user
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
I've even tried this:
begin
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
rescue ActiveRecord::RecordNotFound => e
#current_user ||= nil
end
But it is only returning the nil value.
Please help.
Controller:
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
EDIT:
Model:
before_create :generate_token(:auth_token)
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
I think I am having a problem with before_create. Is the way it is written correct?
This has worked for me, for those times when the browser's cookies and those saved to a user model are mis-aligned:
def current_user
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
rescue ActiveRecord::RecordNotFound => e
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id]) # Use find_by_id to get nil instead of an error if user doesn't exist
end
helper_method :current_user
For me the issue would arise when deleting a user that was currently signed in. The above code stops any errors.
It seems that you canno't find that instance, because the cookie doesn't exist anymore in your web browser, there is a conflict. You should therefore clear your browser's datacache, and the problem will disapear.

Generating JSON for Sinatra

I'm having an issue with passing the generated JSON notation of my object to my Sinatra application. The problem I have is twofold:
I have 2 classes that are mapped to a database using the Sequel gem. When they generate JSON it is ok and properly implemented.
I have a custom class called registration that maps one of the classes with an additional field. The goal is to generate JSON out of this and pass that JSON to the application using cucumber (test purpose)
The application code responsible for handling the request has the following function defined:
post '/users' do
begin
hash = JSON.parse(self.request.body.read)
registration = Registration.new.from_json(#request.body.read)
registration.user.country = Database::Alaplaya.get_country_by_iso_code(registration.user.country.iso_code)
return 400 unless(registration.is_valid?)
id = Database::Alaplaya.create_user(registration.user)
# If the registration failed in our system, return a page 400.
return 400 if id < 1
end
problem 1: I cannot use the params hash. It exists but is just an empty hash. Why?
problem 2: I cannot deserialize the JSON generated by the class itself. Why?
The registration class looks like this:
require 'json'
class Registration
attr_accessor :user, :project_id
def to_json(*a)
{
'json_class' => self.class.name,
'data' => [#user.to_json(*a), #project_id]
}.to_json(*a)
end
def self.json_create(o)
new(*o['data'])
end
# Creates a new instance of the class using the information provided in the
# hash. If a field is missing in the hash, nil will be assigned to that field
# instead.
def initialize(params = {})
#user = params[:user]
#project_id = params[:project_id]
end
# Returns a string representing the entire Registration.
def inspect
"#{#user.inspect} - #{#user.country.inspect} - #{#project_id}"
end
# Returns a boolean valid representing whether the Registration instance is
# considered valid for the API or not. True if the instance is considered
# valid; otherwise false.
def is_valid?
return false if #user.nil? || #project_id.nil?
return false if !#user.is_a?(User) || !#project_id.is_a?(Fixnum)
return false if !#user.is_valid?
true
end
end
I had to implement the methods to generate the JSON output correctly. When I run this in console I get the following output generated:
irb(main):004:0> r = Registration.new(:user => u, :project_id => 1)
=> new_login - nil - 1
irb(main):005:0> r.to_json
=> "{\"json_class\":\"Registration\",\"data\":[\"{\\\"json_class\\\":\\\"User\\\
",\\\"login\\\":\\\"new_login\\\"}\",1]}"
Which looks like valid JSON to me. However when I POST this to the application server and try to parse this, JSON complains that at least 2 octets are needed and refuses to deserialize the object.
If you're using Sequel as your ORM, try something like this:
In your model:
class Registration < Sequel::Model
many_to_one :user
many_to_one :project
plugin :json_serializer
end
The server:
before do
#data = JSON.parse(request.body.read) rescue {}
end
post '/users' do
#registration = Registration.new #data
if #registration.valid?
#registration.save
#registration.to_json #return a JSON representation of the resource
else
status 422 #proper status code for invalid input
#registration.errors.to_json
end
end
I think you may be overcomplicating your registration process. If the HTTP action is POST /users then why not create a user? Seems like creating a registration is overly complex. Unless your user already exists, in which case POST /users would be incorrect. If what you're really intending to do is add a user to to a project, then you should PUT /projects/:project_id/users/:user_id and the action would look something like this:
class User < Sequel::Model
many_to_many :projects
end
class Project < Sequel::Model
many_to_many :users
end
#make sure your db schema has a table called users_projects or projects_users
put '/projects/:project_id/users/:user_id' do
#find the project
#project = Project.find params[:project_id]
raise Sinatra::NotFound unless #project
#find the user
#user = Project.find params[:project_id]
raise Sinatra::NotFound unless #user
#add user to project's users collection
#project.add_user #user
#send a new representation of the parent resource back to the client
#i like to include the child resources as well
#json might look something like this
#{ 'name' : 'a project name', 'users' : ['/users/:user_id', '/users/:another_user_id'] }
#project.to_json
end

How do I work with Rails 3 cookies and helpers?

I created a user and stored the id in a permanent cookie:
def save_user_id_cookie
cookies.permanent.signed[:user_id] = #user_id
end
Here is a link.
and then try to access it:
helper_method :current_user
private
def current_user
#current_user = #current_user || User.find(cookies.signed[:user_id])
end
Here is a link.
I see the cookie on my machine but when I try to load the homepage I get:
Couldn't find User without an ID
app/controllers/application_controller.rb:8:in `current_user'
The controller is here.
Believe this line
#current_user = #current_user || User.find(cookies.signed[:user_id])
should be
#current_user = #current_user || User.find(cookies[:user_id])
*side note: for little less code you can try assigning like
#current_user ||= User.find(cookies[:user_id])
In your save_user_id_cookie:
def save_user_id_cookie
cookies.permanent.signed[:user_id] = #user_id # may be #user.id?
puts 'saved cookie'
end
#user_id is nil. I think you should use #user.id instead.
Try this:
#current_user = #current_user || User.find(*cookies.signed[:user_id])
Notice the * before the cookies.
and yes, as #nash pointed out, that user_id should be actually user.id.
I didn't bother to look there for errors, as you said that you could see the cookie on your machine.

Resources