I'm still working on my very first Ruby on Rails project. The latest issue I'm dealing with is the user management system. I tried using Devise but I couldn't get past a certain error so I decided to create my sign in/login system manually. I'm using Ruby 3.0.2 w/ Rails 7.0.0alpha2.
I got a lot farther this manual way but I'm getting 'undefined method `cost' for BCrypt::Engine:Class' I've googled and they mention changing the version of bcrypt, I did with no luck
They mention going to my user_controller and changing my create method from old code to this '#user = User.new(user_params)' doing this changed my error from 'forbidden' to the error I'm currently writing to you about.
Not to sure on where my issue is, my guess is somewhere in the model or controller, thank your for your time!
User Controller
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank your for signing up!"
else
flash[:danger] = 'Invalid email/password combination'
render "new"
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Session Controller
class SessionsController < ApplicationController
def create
#user = User.find_by_email(params[:email])
if #user && #user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "logged in!"
else
flash.now.alert = "Email or passwrod is invalid"
render "new"
end
end
def destroy
session.delete(:user_id)
#current_user = nil
end
end
User Model
require 'bcrypt'
class User < ApplicationRecord
include BCrypt
validates :email, uniqueness: true
has_secure_password
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Routes
Rails.application.routes.draw do
get 'sessions/new'
resources :users, only: [:new, :create]
resources :fighters
resources :sessions
get 'home/about'
root 'home#index'
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
end
Error
User Controller
User Model
Routes
Session Controller
I logged on this morning and all of a sudden my problem was fixed! Maybe something having to do with the terminal closing because I compared the code I posted here and what I have in my files, very little changes.
1 change I made was adding # to 'session[:user_id] = user.id' to make '#user.id'
After I was able to log on, I was getting an error to log off. The change I made was adding 'session.clear' and 'redirect_to login_path' in my destroy method.
Both changes made in my sessions_controller.rb
I also added "delete 'sessions', to: 'session#destroy'" to routes.rb
Related
I am trying from last 7 hours to auto signin the user after email confirmation but when I click the confirmation link then it says "Your email address has been successfully confirmed." but not sign in the user. I have written this code in my confirmations controller and route
devise_for :users, controllers: {confirmations: 'users/confirmations'}
class ConfirmationsController < Devise::ConfirmationsController
#private
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
render plain: "here"
redirect_to "/admins/view_account", notice: "User deleted."
end
end
Any help would be highly appreciated Thanks.
Notice that automatically sign in after e-mail confirmation used to be Devise's default behavior and was then changed (after 3.1) due to security measures as you can see more here and here.
If you still want to do it, depending on the Devise's version make sure to set the line below on the config/initializers/devise.rb file within your project:
config.allow_insecure_sign_in_after_confirmation=true
If you are using latest Devise version, you may have to instead of that, extend the default controller with this code on app/controllers/users/confirmations_controller.rb as a replacement of what you have mentioned above for controller code (please mind the namespaces and path mentioned):
class Users::ConfirmationsController < Devise::ConfirmationsController
def show
super do |resource|
sign_in(resource) if resource.errors.empty?
end
end
end
And make sure the code you pasted in the beginning of the question belongs in config/routes.rb:
devise_for :users, controllers: { confirmations: 'users/confirmations' }
Hope it helps!
I have solved it myself.
routes should be like this
devise_for :users, controllers: {confirmations: 'confirmations'} do
#put "confirm_user", to: "confirmations#confirm_user"
get "confirmation", to: "confirmations#after_confirmation_path_for"
end
Controller is like this
class ConfirmationsController < Devise::ConfirmationsController
#private
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
#render plain: "here"
#redirect_to "/admins/"
end
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message(:notice, :confirmed) if is_flashing_format?
sign_in(resource) # <= THIS LINE ADDED
redirect_to "/your path/"
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
end
I want to allow Users to have two edit pages, one which is the default Devise page that requires a password and the other edit page which allows them to edit some parts of their profile without a password.
I have seen their guide pages like this which allows them to edit their profile without providing a password. However I want to have both options available to the user instead of just one.
How would I go about doing this?
My Attempt
I have tried to create my own update route in the Users controller which will solve the problem but this creates a problem when a User resets their password as it gets routed to the User#update which will cause an error as there is no User available during the password reset in Devise.
class UsersController < ApplicationController
before_action :authenticate_user!, :only => [:crop] #:edit , :update
def show
#user = User.find(params[:id])
authorize #user
end
def update
#user = User.find(params[:id])
authorize #user
if #user.update(user_params)
flash[:success] = "You have successfully updated your profile!"
redirect_to user_path(#user)
else
render :edit
end
end
def crop
#user = User.find(params[:id])
authorize #user
end
def index
end
private
def user_params
params.require(:user).permit(:poster_image_crop_x, :poster_image_crop_y, :poster_image_crop_w, :poster_image_crop_h)
end
end
Routes
Rails.application.routes.draw do
resources :users,only: [:show] do
member do
get :crop
end
end
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks",:registrations => :registrations,:passwords => "passwords" }
as :user do
get "/login" => "devise/sessions#new"
get "/register" => "devise/registrations#new"
get "/edit" => "devise/registrations#edit"
delete "/logout" => "devise/sessions#destroy"
end
The code by Devise is suggesting to create your own controller. They probably always require password to be passed if it comes from an action in the UsersController. So you should create a seperate controller, let's call it ProfilesController, this controller is like your normal controller although it does not update a Profile model, but the User model directly... nothing special actually, just check authorization and let the User update any field you'd like directly on the User mode, do not forget to authorize the fields you'd wish to let the user update:
class ProfilesController < ApplicationController
def index
end
....... more code
def update
#user = User.find(params[:id])
authorize #user
if #user.update(user_params)
flash[:success] = "You have successfully updated your profile!"
redirect_to user_path(#user)
else
render :edit
end
end
....... more code
private
def user_params
params.require(:user).permit(:poster_image_crop_x, :poster_image_crop_y, :poster_image_crop_w, :poster_image_crop_h)
end
end
And add resources :profiles to your routes file.
I've been following the latest version of M.Hartl's Rails tutorial and I've encountered a problem at Chapter 7.4.1. I've created a signup form which is associated with the new action of the users controller. When the form is submitted with valid information the controller should redirect to the new users profile, however I incur the error below...
I've included the routes.rb code as well as the Users controller code. Could anyone help me?
When I access the url ../users/1 the page actually renders my user, so I know the user has been created and saved to the database. I don't know if maybe it is an error in the implementation of the redirect_to method?
Any help will be greatly appreciated!
ArgumentError in UsersController#create
wrong number of arguments (2 for 1)
Extracted source (around line #19):
private
def _compute_redirect_to_location_with_xhr_referer(options)
store_for_turbolinks begin
if options == :back && request.headers["X-XHR-Referer"]
_compute_redirect_to_location_without_xhr_referer(request.headers["X-XHR-Referer"])
Users Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
Routes.rb :
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users
end
It looks like your version of turbolinks is old. Try updating to the latest:
gem 'turbolinks', '~> 2.3.0'
When my user signs up, it originally gets redirected to its blank profile page.
However, I need the user to be redirected to a additional info page in order to retrieve more information
My users controller looks like this
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to users: 'additional_info'
flash[:success] = "Welcome to InYourShoes!"
return #user
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
As you can see, additional_info is the other page I'm trying to redirect to. I'm aware that I create 2 users objects, but I'm not sure if its correct. Frankly speaking I'm kind of lost.
my routes for the pages is this:
resources :users
resources :sessions, only: [:new, :create, :destroy]
match '/additionalinfo',to: 'users#additional_info', via: 'get'
Thanks for the help!
in yours routes
match '/additionalinfo',to: 'users#additional_info', via: 'get', as: :additional_info
in controller
redirect_to additional_info_path
Alternatively, you can change the redirect line to:
redirect_to action: 'additional_info'
Assuming you have the action defined in your routes:
get :additional_info, to: 'users#additional_info' # use get rather than match
Learning rails development and would usually prefer to search out an answer than waste peoples time but this has been doing my head in all night.
Essentially I'm trying to present user-dependant views ala github etc.
I'm trying to follow the instructions laid out here:
http://collectiveidea.com/blog/archives/2011/05/31/user-centric-routing-in-rails-3/
My authentication at the moment is from the railscast "Authentication from Scratch - revised" which uses sessions, my sessions_crontroller.rb:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
And my routes.rb:
C::Application.routes.draw do
root :to => "static_pages#home", :constraints => LoggedInConstraint.new(false)
root :to => "users#show", :constraints => LoggedInConstraint.new(true)
resources :users
resources :sessions
As per my understanding, because I'm not using cookies the final comment under that blog posts recommends using request.session[:your_key] in place of request.cookies.key?("user_token") however when logged in I am still taken to static_pages#home? If anyone could shed some light on the topic I would very much appreciate it.
I also apologise for any formatting errors etc, this is my first question on stackoverflow.
Thanks again!
Not sure about your exact question, but I just did something kind of similar to this, so maybe my code will help you:
My routes:
# Except from config/routes.rb
require File.expand_path("../../lib/role_constraint", __FILE__)
MyApp::Application.routes.draw do
mount Resque::Server, :at => "/resque", :constraints => RoleConstraint.new('admin')
...
...
...
My constraint:
# lib/role_constraints.rb
class RoleConstraint < Struct.new(:value)
def matches?(request)
request.session[:role] == value
end
end
My sessions controller:
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
before_filter :require_user, :only => :destroy
def new
end
def create
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
# Just for /resque
# Not secure - if you change a user's role, it will not be updated here
# until they log out and log in again.
session[:role] = user.role
if user.email.nil?
redirect_to user, :notice => "Please add your email address to your account"
else
redirect_to root_url, :notice => "Logged in!"
end
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
session[:user_id] = nil
session[:current_project_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end