I am trying to create User objects in a rails PostgreSQL database using JWT authentication. When I fire the create user method from my React frontend the user is not created in the backend and I suspect this has something to do with how my controllers are set up.
Here is my User controller in my Rails backend:
class Api::V1::UsersController < ApplicationController
before_action :find_user, only: [:show]
skip_before_action :authorized, only: [:index, :create]
def index
#users = User.all
render json: #users
end
def show
render json: #user
end
def create
#user = User.create(user_params)
if #user.valid?
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
end
private
def user_params
params.permit(:username, :password)
end
def find_user
#user = User.find(params[:id])
end
Here is my 'auth' controller for JWT:
class Api::V1::AuthController < ApplicationController
skip_before_action :authorized, only: [:create]
def create # POST /api/v1/login
#user = User.find_by(username: user_login_params[:username])
if #user && #user.authenticate(user_login_params[:password])
#token = encode_token({ user_id: #user.id })
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :accepted
else
render json: { message: 'Invalid username or password' }, status: :unauthorized
end
end
private
def user_login_params
params.require(:user).permit(:username, :password)
end
end
And my application controller (I suspect the issue is here and has to do with the way in which I am encoding and decoding the tokens):
class ApplicationController < ActionController::API
before_action :authorized
def encode_token(payload)
JWT.encode(payload, ENV["jwt_secret"])
end
def auth_header
request.headers['Authorization']
end
def decoded_token
if auth_header()
token = auth_header.split(' ')[1]
begin
JWT.decode(token, ENV["jwt_secret"], true, algorithm: 'HS256')
rescue JWT::DecodeError
nil
end
end
end
def current_user
if decoded_token()
user_id = decoded_token[0]['user_id']
#user = User.find_by(id: user_id)
else
nil
end
end
def logged_in?
!!current_user
end
def authorized
render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?
end
end
From my front-end I am using a fetch method to POST to the /users/ endpoint like so:
export const signupUser = (username, password) => {
return(dispatch) => {
const data = {user: {username, password} }
fetch('http://localhost:3000/api/v1/users',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify(data)
})
.then(r=>r.json())
.then(r=>{
localStorage.setItem('jwt', r.jwt)
dispatch({
type: SET_CURRENT_USER,
payload: r.user
})
})
}
}
Apologies that this is long-winded. I wanted to include all the code necessary to figure this out. Any assistance would be appreciated.
I noticed you are not saving your user object when you using a function to create user. Please check app/controllers/api/v1/users_controller.rb and modify following with valid to save method
def create
#user = User.create(user_params)
if #user.valid?
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
Change the line #user.valid? to #user.save
def create
#user = User.create(user_params)
if #user.save
#token = encode_token(user_id: #user.id)
render json: { user: UserSerializer.new(#user), jwt: #token }, status: :created
else
render json: {error: "Could not create user"}, status: :unprocessible_entity
end
end
Please note .valid? is used to validate and check if any error, and .save is used to save it. You are just checking validation and not actually saving, validation happen automatically so there is no need for this method here.
Related
I've my Sessions controller set up as below. I'm looking for a way to grab the auth_token from command.result in the authenticate method and make it available in my headers when the user logs in so I can access it inside react to authenticate users on each request.
When I make a request to the authenticate action, I get the right response with the auth_token but can't figure out how to send this response to the header and use it there.
class Api::V1::SessionsController < ApplicationController
skip_before_action :authenticate_request
include CurrentUserConcern
def authenticate
command = AuthenticateUser.call(params[:email], params[:password])
if command.success?
render json: { auth_token: command.result, message: 'Login successful' }
else
render json: { error: command.errors }, status: :unauthorized
end
end
def create
user = User.find_by(email: params[:email])
.try(:authenticate, params[:password])
if user
session[:user_id] = user.id
render json: {
status: :created,
logged_in: true,
user: user,
}
else
render json: {
status: 400,
}, status: 400
end
end
def logged_in
if #current_user
render json: {
logged_in: true,
user: #current_user
}
else
render json: {
logged_in: false
}
end
end
def logout
reset_session
render json: { status: 200, logged_out: true }
end
end
Figured it out.
I set a before_action in my controller to set the #token variable. This way I can use #token in any action within the controller.
class Api::V1::SessionsController < ApplicationController
skip_before_action :authenticate_request
before_action :set_token
end
Then I created a private method to set the token.
def set_token
command = AuthenticateUser.call(params[:email], params[:password])
if command.success?
#token = command.result
else
nil
end
end
And called the #token variable inside my create action passing it to set_headers.
response.set_header('token', #token)
The workflow should be users should be able to attach files to comments on zendesk ticket regardless if it's a new ticket or existing ticket.
Currently attaching files to comments on existing tickets works perfectly fine. However, if you look at the create action is where it does nothing as far as being able to attach the file. It doesn't throw an error but just doesn't attach the file. I'm sure it's the way my code is flowing but can't figure it out.
require_dependency 'zen_support/application_controller'
module ZenSupport
class TicketsController < ApplicationController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
before_action :authenticate_user!, except: :zen_update
before_action :set_new_ticket, only: [:new, :create]
before_action :get_ticket, only: [:show, :edit, :update, :zen_update]
before_action :authorize_ticket, except: :zen_update
rescue_from ZendeskAPI::Error::NetworkError, with: :network_error
def new
respond_to do |format|
format.js
end
end
def index
if zen_list_type == 'datatable'
#tickets = tickets
else
smart_listing
end
respond_to do |format|
format.html
format.js
end
end
def create
if(!#ticket.valid? && (#ticket.errors.keys - [:zendesk_id]).present?)
# test if ticket is invalid beyond just missing zendesk_id
raise ActiveRecord::RecordInvalid.new #ticket
else
ActiveRecord::Base.transaction do
#zendesk_ticket.save!
upload_to_zendesk(params[:comment], params[:attachments])
#ticket.zendesk_id = #zendesk_ticket.id
#ticket.status = #zendesk_ticket.status
#ticket.save!
smart_listing
flash.now[:success] = "Your help request was successfully submitted.\n
Your support ticket number is ##{#zendesk_ticket.id}.\n\n
You should receive a confirmation email shortly.\n\n
Thank you!"
end
end
rescue Exception => exception
flash.now[:error] = exception.to_s
#zendesk_ticket.delete if #zendesk_ticket.id
render :new
end
def show
render action: :edit
end
def update
respond_to do |format|
format.js do
# don't save over comment, just use the field for validation
upload_to_zendesk(params[:comment], params[:attachments])
#zendesk_ticket.update(ticket_update_params)
if #ticket.valid? && #zendesk_ticket.save! && #ticket.update(updated_at: Time.now)
flash.now[:success] = "Your help request was successfully updated.\n
Your support ticket number is ##{#zendesk_ticket.id}.\n\n
You should receive a confirmation email shortly.\n\n
Thank you!"
else
flash.now[:error] = if #ticket.errors.present?
#ticket.errors.full_messages.join "\n"
else
'There was a problem sending out your request.'
end
render action: :edit
end
end
end
end
def zen_update
ZenSupport::Ticket.find_by(
zendesk_id: params[:id]
)&.update(zen_update_params)
render nothing: true
end
def network_error
flash.now[:error] = 'There was a network error connecting to the Zendesk API. Try again later.'
render 'network_error'
end
private
def upload_to_zendesk(comment_body, files)
#zendesk_ticket.comment = { value: comment_body }
Array(files).each do |file|
#zendesk_ticket.comment.uploads << file
end
end
def tickets
ZenSupport::Ticket.where user: current_user
end
def smart_listing
smart_listing_create(
:support_tickets,
tickets,
partial: 'zen_support/tickets/list',
array: tickets.count != 0
# we want to use array: true if there are records present because it pre-renders the activerecord
# objects so we can do sorting on the encrypted field 'subject'. BUT, if there are no records,
# then array: true gives us a pagination error
)
end
def ticket_params
{
subject: subject,
comment: comment,
zendesk_id: zendesk_id,
zendesk_submitter_id: submitter_id,
ticket_type: ticket_type,
priority: priority,
tags: tags,
user: current_user
}
end
def zendesk_ticket_params
{
subject: subject,
type: ticket_type,
comment: { value: comment },
submitter_id: submitter_id,
requester_id: requester_id,
priority: priority,
tags: tags
}
end
def ticket_update_params
{
comment: {
body: params[:comment],
author_id: zendesk_user.id
}
}
end
def zen_update_params
{
zendesk_id: zendesk_id,
status: #zendesk_ticket.status,
priority: #zendesk_ticket.priority,
updated_at: #zendesk_ticket.updated_at
}
end
def subject
params.dig :zen_support_ticket, :subject
end
def comment
params.dig :zen_support_ticket, :comment
end
def zendesk_id
#zendesk_ticket.id
end
def tags
[
*params.dig(:zen_support_ticket, :tags),
*ZenSupport.configuration.options[:support_ticket_attributes][:static_tags]
]
end
def ticket_type
params.dig(:zen_support_ticket, :ticket_type).to_s.downcase
end
def set_new_ticket
#zendesk_ticket = ZendeskAPI::Ticket.new(
zen_client, zendesk_ticket_params
)
#ticket = ZenSupport::Ticket.new(ticket_params)
end
def get_ticket
#zendesk_ticket = ZendeskAPI::Ticket.find!(
zen_client,
id: params[:id]
)
#ticket = ZenSupport::Ticket.find_by!(zendesk_id: params[:id])
end
def priority
(params.dig(:zen_support_ticket, :priority) || ZenSupport.configuration.options[:support_ticket_attributes][:default_priority]).downcase
end
def submitter_id
zendesk_user.id
end
def requester_id
zendesk_user.id
end
def user_params
params.require(:zen_support_user).permit(tags: [])
end
def zendesk_user
#zendesk_user ||= (get_zendesk_user || create_zendesk_user)
end
def get_zendesk_user
zen_client.users.search(
query: "email:#{zen_current_user.email}"
).first
end
def create_zendesk_user
ZendeskAPI::User.create(
zen_client,
email: zen_current_user.email,
name: zen_current_user.full_name,
tags: user_tags
)
end
def user_tags
ZenSupport.configuration.user_setup[:static_tags]
end
def authorize_ticket
authorize Ticket
end
end
end
try adding this one-line to your create-method
def create
if(!#ticket.valid? && (#ticket.errors.keys - [:zendesk_id]).present?)
# test if ticket is invalid beyond just missing zendesk_id
raise ActiveRecord::RecordInvalid.new #ticket
else
ActiveRecord::Base.transaction do
#zendesk_ticket.save!
upload_to_zendesk(params[:comment], params[:attachments])
#zendesk_ticket.save!
...
I'm new to JWT authorization and have followed the boiler plate to set up auth in Rails. When I try to test my routes by calling localhost:5000/api/v1/users or any controller for that matter, I get the following everytime:
JWTSessions::Errors::Unauthorized in Api::V1
Nil JSON web token
Obviously a token isn't being generated but not sure how to create one from just checking controllers in Rails. Is there a way to do this with Postman?
Here are my relevant controllers:
Application Controller:
class ApplicationController < ActionController::API
include JWTSessions::RailsAuthorization
rescue_from JWTSessions::Errors::Unauthorized, with: :not_authorized
private
def current_user
#current_user ||= User.find(payload['user_id'])
end
def not_authorized
render json: { error: 'Not authorized' }, status: :unauthorized
end
end
Signup:
class SignupController < ApplicationController
def create
user = User.new(user_params)
if user.save
payload = { user_id: user.id }
session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
tokens = session.login
response.set_cookie(JWTSessions.access_cookie,
value: tokens[:access],
httponly: true,
secure: Rails.env.production?)
render json: { csrf: tokens[:csrf] }
else
render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
end
end
private
def user_params
params.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation)
end
end
UsersController:
class Api::V1::UsersController < ApplicationController
before_action :find_user, only: [:update, :show, :destroy]
def index
#users = User.all
render json: #users, status: :accepted
end
def create
#user = User.new(user_params)
if #user.save
render json: {user: UserSerializer.new(#user), token: Rails.application.credentials.jwt}, status: :ok
else
render json: {errors: #user.errors.full_messages}
end
end
def show
if #user
if curr_user.id == #user.id
render json: #user
else
render json: {errors: #user.errors.full_messages }, status: :unprocessible_entity
end
else
render json: {errors: "User not found!"}
end
end
def update
if curr_user.id == #user.id
#user.update(user_params)
if #user.save
render json: #user, status: :accepted
else
render json: { errors: #user.errors.full_messages }, status: :unprocessible_entity
end
end
end
def destroy
if curr_user.id == #user.id
#user.delete
render json: "user deleted", status: :ok
else
render json: { errors: "You are not authorized to delete"}
end
end
private
def user_params
params.permit(:first_name, :last_name, :email, :username, :password_digest)
end
def find_user
#user = User.find(params[:id])
end
end
Routes
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
namespace :api do
namespace :v1 do
resources :users, only: [:index, :show, :create, :update, :destroy]
resources :categories, only: [:index, :show, :create, :update, :destroy]
resources :opportunities
resources :opportuniy_api, only: [:index, :show]
end
end
post 'refresh', controller: :refresh, action: :create
post 'signin', controller: :signin, action: :create
post 'signup', controller: :signup, action: :create
delete 'signin', controller: :signin, action: :destroy
end
It is showing up "Nil JSON Web Token" because rails is unable to find any authorization token in request.headers["Authorization"].
Going through the jwt_sessions readme file https://github.com/tuwukee/jwt_sessions you will find that "Headers must include Authorization: Bearer with access token." This is what you are missing in your case.
Secondly, you don't need to use CSRF tokens in rails. As a Rails developer, you basically get CSRF protection for free. It starts with this single line in application_controller.rb, which enables CSRF protection:
protect_from_forgery with: :exception
I have tried the same and my code works fine:
Signup:
class SignupController < ApplicationController
skip_before_action :verify_authenticity_token
def create
user = User.new(user_params)
if user.save
payload = { user_id: user.id }
session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
tokens = session.login
response.set_cookie(JWTSessions.access_cookie,
value: tokens[:access],
httponly: true,
secure: Rails.env.production?)
render json: tokens
else
render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
end
end
private
def user_params
params.permit(:username, :email, :password, :password_confirmation)
end
end
Or you can make it even simpler: Signup
class SignupController < ApplicationController
def create
user = User.new(user_params)
if user.save
payload = { user_id: user.id }
session = JWTSessions::Session.new(payload: payload, refresh_by_access_allowed: true)
render json: session.login //or render json: session.login[:access]
else
render json: { error: user.errors.full_messages.join(' ') }, status: :unprocessable_entity
end
end
private
def user_params
params.permit(:email, :password, :password_confirmation, :signup)
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery prepend: true, with: :exception
include JWTSessions::RailsAuthorization
rescue_from JWTSessions::Errors::Unauthorized, with: :not_authorized
def index
render template: 'application'
end
private
def current_user
#current_user ||= User.find(payload['user_id'])
end
def not_authorized
render json: { error: 'Not authorized' }, status: :unauthorized
end
end
ajax call from frontend(vue) to rails: Inspect your token and you will get the access_token within it. Or render token[:access] from rails to frontend. Include this access token in the Header for every request you make to the rails api.
$.ajax({
beforeSend: function(xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + <access_token>);
},
url: '/api/home'..
Hope this helps :)
I dit it, for me it worked
def current_user
return unless request.headers.include? "Authorization"
#current_user ||= User.find(payload['user_id'])
end
I have an API based Rails app and I need to add a changing password section for clients after login. this is y codes so far:
# routes.rb
resources :passwords, only: %i[index]
post '/passwords/update_password', to: 'passwords#update_password'
passwords_controller.rb
class Api::PasswordsController < ApplicationController
respond_to :json
before_action :auth_check
def auth_check
if !user_signed_in?
render json: {:status => false, :msg => 'Access denied!'}
end
end
def update_password
user = User.find(current_user['_id'])
password = params["password"]
if password && !password.blank?
user.password = user.password_confirmation = password
end
if user.save
render json: {company: user}, status: 200
else
render json: {message: "Problem updating company"}, status: 500
end
end
end
And this is XHR request from client-side
axios({
url: '/api/passwords/update_password',
method: 'POST',
body: {
password: password,
password_confirmation: password_confirmation
}
})
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
Its not working!
You should be able to use current_user. I edited the code. If it doesn't work, can you write the error here? Make sure the post request goes to update_password action.
class Api::PasswordsController < ApplicationController
respond_to :json
before_action :auth_check
def update_password
password = params.dig(:password)
password_confirmation = params.dig(:password_confirmation)
if password.present? && password == password_confirmation
if current_user.update(password: password, pasword_confirmation: password_confirmation)
render json: { company: user }, status: 200
else
render json: { message: 'Problem updating company' }, status: 500
end
end
end
private
def auth_check
render json: { status: false, msg: 'Access denied!' } unless user_signed_in?
end
end
I have a rails app with two controllers that have very similar behaviors.
One is a UsersController related to the concept of Hotel, the other is also named UsersController but related to the concept of association, so it is stored in a folder association :class Api::V1::Association::UsersController < Api::V1::BaseController
These controllers have very similar behaviors, methods with minor differences (they rely on different database tables for certain variables...). I was reading about inheritance and thought that it could be interesting to make the Association::UsersController inherit from the UsersController. Do you think this could be the right thing to do in my case ? For example I have been trying to rewritte the method invite of Association::UsersController to use inheritance but I am a bit confused on how to do it. Could you tell me how you would rewrite this method if the Association::UsersControllerinherits from the usersController. Here how both controllers look like :
users_controller.rb :
class Api::V1::UsersController < Api::V1::BaseController
skip_after_action :verify_authorized, only: [:invite, :update_specific, :show]
before_action :set_user, except: [:invite, :index, :update_specific]
before_action :set_account, only: [:index, :invite, :show]
# creates user linked to account / only account owner can create users linked to account
# input account_id & email
def invite
unless current_user.id != #account.admin_user_id
user_already_exists_or_email_blank?
set_new_user
ActiveRecord::Base.transaction do
set_hotels_access
save_user_and_send_invitation_email
end
else
render_error("not_admin")
end
end
def show
if ((current_user == #user) || (#account.admin == current_user))
else
render_error("unauthorized")
end
end
# admin can update employee or manager
def update_specific
#user_to_update = User.find(params[:id])
if #user_to_update.account != current_user.created_account
render_error("unauthorized")
else
ActiveRecord::Base.transaction do
update_user_and_hotels_access
end
end
end
# update self
def update
authorize #user
if #user.update(user_params)
render_success("updated")
else
render_error("")
end
end
def destroy
authorize #user
if #user.destroy
render json: {message: "User successfully destroyed"}
else
render json: {error: "There was an error please try again"}
end
end
# envoyer account params
def index
if (current_user.created_account == #account) || ((current_user.account == #account) && (current_user.status == "manager"))
#users = policy_scope(User).where(account: #account)
#admin = #account.admin
render json: {users: #users, admin: #admin}
else
render json: {message: "Unauthorized"}
end
end
# unlincks user from account
#input user_id
def unlinck
authorize #user
#user.account = nil
if #user.save && #user.hotels.delete_all.nil?
render json: {user: #user}
else
render_error("db")
end
end
private
def user_already_exists_or_email_blank?
if User.find_by_email(params[:user][:email])
render_error("mail_exists") and return
elsif params[:user][:email].blank?
render_error("empty_email") and return
end
end
def set_new_user
password = SecureRandom.hex
invitation_token = SecureRandom.uuid
#user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_id: params[:user][:account_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "hotel")
end
def set_hotels_access
if params[:hotel_access].first == "all"
#hotels = #account.hotels
else
#hotels = Hotel.where(id: params[:hotel_access])
end
end
def save_user_and_send_invitation_email
if #user.save && #user.hotels << #hotels
if UserMailer.send_invitation(#user, params[:app_base_url]).deliver_now
#user.invitation_sent_at = Time.now
if #user.save
render_success("mail_sent")
else
render_error("db")
end
else
render_error("mail_processing")
end
else
render_error("db")
end
end
def update_user_and_hotels_access
#hotels = Hotel.where(id: params[:hotel_access])
if #user_to_update.hotels.destroy_all
if #user_to_update.hotels << #hotels
if #user_to_update.update(user_params)
render json: {message: "User successfully updated"}
else
render_error("db")
end
else
render("db")
end
else
render_error("db")
end
end
def set_user
#user = User.find(params[:id])
end
def set_account
if params[:account_id]
#account = Account.find(params[:account_id])
elsif params[:user][:account_id]
#account = Account.find(params[:user][:account_id])
end
end
def user_params
params.require(:user).permit(
:email,
:account_id,
:first_name,
:last_name,
:telephone,
:position,
:status,
:user_id
)
end
def render_error(error_type)
case error_type
when "not_admin"
render json: {error: "You are not allowed to create a user for this account"}
when "mail_exists"
render json: {error: "Please fill the email field and try again"}
when "empty_email"
render json: {error: "Please fill the email field and try again"}
when "mail_processing"
render json: { error: "We couldnt send an email to your invitee. Please try again" }
when "db"
render json: {error: "An error occured. Please try again"}
when "unauthorized"
render json: {error: "Unauthorized"}
else
render json: { errors: #user.errors.full_messages }, status: :unprocessable_entity
end
end
def render_success(success_type)
case success_type
when "mail_sent"
render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." }
when "password_changed"
render json: {success: "Your password was successfully changed"}
when "updated"
render json: {success: "Your infos were successfully updated"}
end
end
end
association/users_controller.rb
class Api::V1::Association::UsersController < Api::V1::BaseController
skip_after_action :verify_authorized, only: [:invite, :update_specific, :show]
before_action :set_user, except: [:invite, :index, :update_specific]
before_action :set_account_asso, only: [:index, :show, :invite]
# creates user linked to account / only account owner can create users linked to account
# input account_id & email
def invite
unless current_user.id != #account_asso.admin_user_id
user_already_exists_or_email_blank?
set_new_user
ActiveRecord::Base.transaction do
set_offices_access
save_user_and_send_invitation_email
end
else
render_error("not_admin")
end
end
def show
if ((current_user == #user) || (#account_asso.admin == current_user))
else
render_error("unauthorized")
end
end
# admin can update employee or manager
def update_specific
#user_to_update = User.find(params[:id])
if #user_to_update.account != current_user.created_account
render_error("unauthorized")
else
ActiveRecord::Base.transaction do
update_user_and_offices_access
end
end
end
# update self
def update
authorize #user
if #user.update(user_params)
render_success("updated")
else
render_error("db")
end
end
def destroy
authorize #user
if #user.destroy
render json: {message: "User successfully destroyed"}
else
render_error("db")
end
end
# envoyer account params
def index
if (current_user.created_account_asso == #account_asso) || ((current_user.account_asso == #account_asso) && (current_user.status == "manager"))
#users = policy_scope(User).where(account_asso: #account_asso)
#admin = #account_asso.admin
render json: {users: #users, admin: #admin}
else
render_error("unauthorized")
end
end
# unlincks user from account
#input user_id
def unlinck
authorize #user
#user.account_asso = nil
if #user.save && #user.offices.delete_all.nil?
render json: {user: #user}
else
render_error("db")
end
end
private
def user_already_exists_or_email_blank?
if User.find_by_email(params[:user][:email])
render_error("mail_exists") and return
elsif params[:user][:email].blank?
render_error("empty_email") and return
end
end
def set_new_user
password = SecureRandom.hex
invitation_token = SecureRandom.uuid
#user = User.new(first_name: params[:user][:first_name], last_name: params[:user][:last_name], telephone: params[:user][:telephone], account_asso_id: params[:user][:account_asso_id], email: params[:user][:email], status: params[:user][:status], password: password, password_confirmation: password, invitation_token: invitation_token, invitation_created_at: Time.now, role: "asso")
end
def set_offices_access
if params[:office_access].first == "all"
#offices = account_asso.offices
else
#offices = Office.where(id: params[:office_access])
end
end
def save_user_and_send_invitation_email
if #user.save && #user.offices << offices
if UserMailer.send_invitation(#user, params[:app_base_url]).deliver_now
#user.invitation_sent_at = Time.now
if #user.save
render_success("mail_sent")
else
render_error("db")
end
else
render_error("mail_processing")
end
else
render_error("db")
end
end
def update_user_and_offices_access
#offices = Office.where(id: params[:office_access])
if #user_to_update.offices.destroy_all
if #user_to_update.offices << #offices
if #user_to_update.update(user_params)
render json: {message: "User successfully updated"}
else
render_error("db")
end
else
render("db")
end
else
render_error("db")
end
end
def set_user
#user = User.find(params[:id])
end
def set_account_asso
if params[:account_asso_id]
#account_asso = AccountAsso.find(params[:account_asso_id])
elsif params[:user][:account_asso_id]
#account_asso = AccountAsso.find(params[:user][:account_asso_id])
end
end
def user_params
params.require(:user).permit(
:email,
:account_id,
:first_name,
:last_name,
:telephone,
:position,
:status,
:user_id
)
end
def render_error(error_type)
case error_type
when "not_admin"
render json: {error: "You are not allowed to create a user for this account"}
when "mail_exists"
render json: {error: "Please fill the email field and try again"}
when "empty_email"
render json: {error: "Please fill the email field and try again"}
when "mail_processing"
render json: { error: "We couldnt send an email to your invitee. Please try again" }
when "db"
render json: {error: "An error occured. Please try again"}
when "unauthorized"
render json: {error: "Unauthorized"}
else
render json: { errors: #user.errors.full_messages }, status: :unprocessable_entity
end
end
def render_success(success_type)
case success_type
when "mail_sent"
render json: { success: "An email was sent to your collaborator asking him to join your Quickbed team." }
when "password_changed"
render json: {success: "Your password was successfully changed"}
when "updated"
render json: {success: "Your infos were successfully updated"}
end
end
end
Maybe I should rewritte the usersController linked to the concept of Hotel or maybe I should create a third superusersControllerfrom which both the usersController linked to the concept of hotel and the usersController linked to the concept of Association would inherit ? Could you help me find the best fit to my situation ?
You can take a look at Service Objects. They are just plain old Ruby objects. You can extract your invite method into something like UsersService#invite then call it from both controllers. Differences in logic can be handled by passing it a parameter in which context it runs in (users or associations)