How can a user log in a user right after signing up? - ruby-on-rails

I know I should put the code in the create action of the users controller, but I'm not sure what code.
this is my controller code:
# frozen_string_literal: true
class UsersController < ProtectedController
skip_before_action :authenticate, only: [:signup, :signin]
# POST '/sign-up'
def signup
user = User.create(user_creds)
if user.valid?
render json: user, status: :created
else
render json: user.errors, status: :bad_request
end
end
# POST '/sign-in'
def signin
creds = user_creds
if (user = User.authenticate creds[:email],
creds[:password])
render json: user, serializer: UserLoginSerializer, root: 'user'
else
head :unauthorized
end
end
# DELETE '/sign-out/1'
def signout
if current_user == User.find(params[:id])
current_user.logout
head :no_content
else
head :unauthorized
end
end
# PATCH '/change-password/:id'
def changepw
if !current_user.authenticate(pw_creds[:old]) ||
(current_user.password = pw_creds[:new]).blank? ||
!current_user.save
head :bad_request
else
head :no_content
end
end
def index
render json: User.all
end
def show
user = User.find(params[:id])
render json: user
end
def update
head :bad_request
end
private
def user_creds
params.require(:credentials)
.permit(:email, :password, :password_confirmation)
end
def pw_creds
params.require(:passwords)
.permit(:old, :new)
end
private :user_creds, :pw_creds
end
i know i should change something
in my create user but not sure where
i tried to use #current_user = user under the sign up part but it didnt work.

Do you want user to be signed in when he/she sign up?
# POST '/sign-up'
def signup
user = User.create(user_creds)
if user.valid?
User.authenticate(user_creds[:email], user_creds[:password])
render json: user, status: :created
else
render json: user.errors, status: :bad_request
end
end

Related

Rails API not able to destroy session

I am using Rails API and devise for authentication but when sending a request to destroy the session, it doesn't return any response other then status 200.It returns the same response no matter if the user exists, is logged in or the password is incorrect.
url http://localhost:3000/users/sign_in
I'm sending a DELETE request through Postman and it just returns a 200 response. It should be returning the data which is stored in the #message
{
"user":{
"email":"abc#abc.com",
"password":"abc#abc.com"
}
}
I even tried to destory the session using the session id:
curl -X DELETE -d "3" http://localhost:3000/users/sign_out
sessions_controller.rb
class API::V1::SessionsController < Devise::SessionsController
def create
#user = User.find_by_email(user_params[:email])
if #user && #user.valid_password?(user_params[:password])
session[:user_id]=#user.id
sign_in :user, #user
render json: #user
elsif #user && not(#user.valid_password?(user_params[:password]))
invalid_attempt
else
no_user
end
end
def destroy
#message = "signed out"
session.delete(:user_id)
sign_out(#user)
render json: #message
end
private
def no_user
render json: {error: "An account with this email doesn't exist. Please create a new one"}, status: :unprocessable_entity
end
def invalid_attempt
render json: { error: "Your password isn't correct" }, status: :unprocessable_entity
end
def user_params
params.require(:user).permit(:email, :password)
end
end
routes.rb
devise_for :users, controllers: { registrations: 'api/v1/registrations', sessions:'api/v1/sessions'}

Unable to destroy session/logout in Rails

I am trying to learn Rails API with React front end and have created a login, signup and logout feature. Currently, I am using localstorage to check if a user is signed in or registered. If the value is true, the logout button appears, and clicking logout empties the localstorage and sets the value to false. But I think this isn't the correct way of doing it since rails devise has its own session and logout endpoint. I tried writing some code for the destroy session and when testing it using the endpoint in POSTMAN it doesn't seem to work the way I want.
Here's the code:
class API::V1::SessionsController < Devise::SessionsController
def create
#user = User.find_by_email(user_params[:email])
if #user && #user.valid_password?(user_params[:password])
session[:user_id]=#user.id
sign_in :user, #user
render json: #user
elsif #user && not(#user.valid_password?(user_params[:password]))
invalid_attempt
else
no_user
end
end
def destroy
puts "logout clicked"
#user = User.find_by_email(user_params[:email])
if #user.valid_password(user_params[:password]) && #user.destroy
render :json => { success: "user was successfully deleted" }, :status => 201
else
render :json => { error: "user could not be deleted" }, :status => 422
end
end
private
def no_user
render json: {error: "An account with this email doesn't exist. Please create a new one"}, status: :unprocessable_entity
end
def invalid_attempt
render json: { error: "Your password isn't correct" }, status: :unprocessable_entity
end
def user_params
params.require(:user).permit(:email, :password)
end
end
http://localhost:3000/users/sign_out
{
"user":{
"email":"test1#test.com",
"password":"test1#test.com"
}
}
Please note that this user does exist. Sending a delete request to http://localhost:3000/users/sign_out isn't even logging the "logout clicked" and the status gives 204.

Rails update action fails to check params

I am building a Rails API and found out that put request passes without required parameters. That is weird for me as app won't allow post request without parameters. Moreover, when I’m trying to update the spending without attributes via Rails console, it fails. But via Postman/CURL request passes successfully
The controller looks like this:
class SpendingsController < ApplicationController
before_action :find_spending, only: %i[show update destroy]
def create
spending = Spending.new(spending_params)
spending.user = current_user
spending.category = Category.find_by(id: spending_params[:category_id])
if spending.valid?
spending.save
render json: SpendingSerializer.new(spending), status: :ok
else
render json: ActiveRecordErrorsSerializer.new(spending), status: :bad_request
end
end
def index
spendings = Spending.where(user_id: current_user.id).order("#{sort_spendings}")
total_value = Spending.where(user_id: current_user.id).pluck(:amount).sum
render json: {spendings: SpendingSerializer.new(spendings), total_amount: total_value}, status: :ok
end
def show
if #spending.valid?
render json: SpendingSerializer.new(#spending), status: :ok
else
render json: ActiveRecordErrorsSerializer.new(#spending), status: :not_found
end
end
def update
if #spending.valid?
#spending.update(spending_params)
render json: SpendingSerializer.new(#spending), status: :ok
else
render json: ActiveRecordErrorsSerializer.new(#spending), status: :bad_request
end
end
def destroy
if #spending.destroy
head :no_content
else
render json: ActiveRecordErrorsSerializer.new(#spending), status: :not_found
end
end
private
def spending_params
params.require(:spending).permit(:description, :amount, :category_id)
end
def find_spending
begin
#spending = Spending.find(params[:id])
rescue ActiveRecord::RecordNotFound
render json: {errors: "Spending with id #{params[:id]} not found"}, status: :not_found
end
end
def sort_spendings
sort = { sort_by: "created_at", sort_dir: "desc"}
sort[:sort_by] = params[:sort_by].split(" ").first if params[:sort_by].present?
sort[:sort_dir] = params[:sort_by].split(" ").last if params[:sort_by].present?
sort.values.join(" ")
end
end
And my model:
class Spending < ApplicationRecord
belongs_to :user
belongs_to :category
validates :description,
presence: true
end
I’m really out of ideas, why is that happening. Any guesses what can that be related to?
First thing that I noticed is your update method. You check validation before updating the model. #spending.valid? always returns true in this case. My suggestion to modify it. #spending.update(spending_params) returns true if it update is successful and false if it fails.
def update
if #spending.update(spending_params)
render json: SpendingSerializer.new(#spending), status: :ok
else
render json: ActiveRecordErrorsSerializer.new(#spending), status: :bad_request
end
end
created method an be also optimised. You don't need find and assign category separately. It will be assigned as all spending_params.
def create
spending = Spending.new(spending_params)
spending.user = current_user
spending.save
render json: SpendingSerializer.new(spending), status: :ok
else
render json: ActiveRecordErrorsSerializer.new(spending), status: :bad_request
end
end

add automatically value to column database in rails

notes use rails 5.2 and postgresql
I have Foluser model contains name,email,password,id_watch
I need when admin add new foluser
generate password
when admin create new foluser generate password like Secure Password Generator
get id_watch from admin model and put it to id_watch from Foluser model
Adminwhen register enterusername,email,password,id_watch`
in point 2 need take this id_watch and save it in user model .
admin only create foluser
`
class FolusersController < ApplicationController
before_action :set_foluser, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show, :new , :create, :edit]
# GET /folusers
# GET /folusers.json
def index
#folusers = current_master.foluser.all
#render json: #folusers
end
# GET /folusers/1
# GET /folusers/1.json
def show
##folusers = Foluser.where(master_id: #master.id).order("created_at DESC")
##foluser = Foluser.find(params[:id])
#render json: #foluser
end
# GET /folusers/new
def new
#foluser = current_master.foluser.build
end
# GET /folusers/1/edit
def edit
#render json: #foluser
end
# POST /folusers
# POST /folusers.json
def create
#foluser = current_master.foluser.build(foluser_params)
respond_to do |format|
if #foluser.save
format.html { redirect_to #foluser, notice: 'Foluser was successfully created.' }
format.json { render :show, status: :created, location: #foluser }
else
format.html { render :new }
format.json { render json: #foluser.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /folusers/1
# PATCH/PUT /folusers/1.json
def update
respond_to do |format|
if #foluser.update(foluser_params)
format.html { redirect_to #foluser, notice: 'Foluser was successfully updated.' }
format.json { render :show, status: :ok, location: #foluser }
else
format.html { render :edit }
format.json { render json: #foluser.errors, status: :unprocessable_entity }
end
end
end
# DELETE /folusers/1
# DELETE /folusers/1.json
def destroy
#foluser.destroy
respond_to do |format|
format.html { redirect_to folusers_url, notice: 'Foluser was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_foluser
#foluser = Foluser.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone, :password)
end
end
foluser model
class Foluser < ApplicationRecord
belongs_to :admin, :optional => true
end
admin model
class Master < ApplicationRecord
has_many :foluser
end
Using your current code, setting the id_watch can be done here in the controller:
class FolusersController < ApplicationController
def create
#foluser = current_master.folusers.build(foluser_params)
#foluser.id_watch = current_master.id_watch # <-- !!!
respond_to do |format|
if #foluser.save
# ...
end
end
end
end
Despite our extended conversation above, I'm still unclear what you're trying to achieve with the "password generation".
(Should it be generated in the front-end, or the back-end? Should it be stored encrypted, or in plain text? If encrypted, do you need to be able to reverse this encryption? Is it a "permanent" password, or a "temporary" password? ...)
Therefore, the following code should be taken with a big pinch of salt - since I still don't really know what the desired/correct behaviour is.
In the FolusersController, you've defined the following method:
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone, :password)
end
However, if you want the password to be generated by the server then you shouldn't be allowing the admin to set the password through the controller. Therefore, remove this parameter:
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone)
end
And then somewhere - perhaps in the controller, or as a hook in the model - set this password to something random:
class FolusersController < ApplicationController
def create
#foluser = current_master.folusers.build(foluser_params)
#foluser.password = SecureRandom.hex(10 + rand(6))
# ...
end
end
# or
class Foluser < ApplicationRecord
after_initialize :default_password
def default_password
self.password ||= SecureRandom.hex(10 + rand(6))
end
end
I think you found the solution, use rails callbacks in your model to extract this kind of logic from the controller.
But I'd rather use after_initialize than before_save so that you won't set a default password before each save(so possibly even update action)
Then use things like SecureRandom (ActiveSupport concern) (already bundled by rails, no requires required)
after_initialize :defaultpassword
...
def default_password
self.password ||= SecureRandom.hex(10 + rand(6))
end
not the best way to do random I know but feel free to customize it.
secure_random output examples:
=>bf8d42b174d297f6460eef
=>efd28869171a1ec89c3438
=>3855c61fb6b90ed549d777

Rails 4 testing controller failure

Good afternoon,
I've done a scaffold of a class, here the example: User - At the moment I was executing the test I saw this bug:
Minitest::Assertion: "User.count" didn't change by 1.
Expected: 3
Actual: 2
test/controllers/users_controller_test.rb:20:in `block in <class:UsersControllerTest>'
the refering code of the bug is this one:
test "should create user" do
assert_difference('User.count') do
post :create, user: { name: 'test', password: 'secret', password_confirmation: 'secret' }
end
assert_redirected_to user_path(assigns(:user))
end
So the code above was created by the scaffold, I just change the name reference.
UserController:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy, :reset_password]
# GET /users
# GET /users.json
def index
#users = super
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: get_action_message }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
#user.update(user_params)
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: get_action_message }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: get_action_message }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :password, :password_confirmation)
end
def search_params
super - ['password_digest']
end
def show_attributes
#show_attributes = super - ['password_digest']
end
end
UserModel
class User < ActiveRecord::Base
nilify_blanks
validates :name, presence: true, uniqueness: true;
has_secure_password
end
For what I was able to understand, the "create" it's not being executed. I've put the breakpoint on the Controller create but its not stoping there..
What am I doing wrong, besides my poor english skills?
Tks for the helping!!
Thks guys,
I found this bug.
I had forgotten to put in the user Session

Resources