How To Update User Profile to user authentication from scratch - ruby-on-rails

I have followed the revised Railscast for user authentication from scratch.
I wanted to know how I can add in parts for user to modify profile as I have other fields that they need to enter after registering such as gender, ethnicity, career, about me, children, height, etc.
Is there a tutorial that shows you how to do this or can someone help point me in the right direction?
My project files can be viewed at https://github.com/pwz2k/date
UPDATE
I have started working on it, not sure if I am doing this right. I want the user to be able to modify their account settings (fields used when registering).
Below is my edit.html in the /users folder.
<h1>Account Information</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br/>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br/>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br/>
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :username %><br/>
<%= f.text_field :username %>
</div>
<div class="field">
<%= f.label :zip_code %><br/>
<%= f.text_field :zip_code %>
</div>
<div class="field">
<%= f.label :birthday %><br/>
<%= f.text_field :birthday %>
</div>
<div class="actions"><%= f.submit %></div>
<% end %>
Here's my routes:
Dating::Application.routes.draw do
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
get 'edit' => 'edit#edit'
resources :users
resources :sessions
resources :password_resets
root to: 'users#new'
And here is what I added to users_controller that I am not sure I did properly:
def edit
#user = User.find(params[:user])
end
def update
#user = User.find(params[:user])
if #user.update_attributes(params[:user])
flash[:success] = "Account updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
How I will eventually have everything working is user will go to /edit to modify their account settings with all their private information that was filled our during registration. Then users can edit the profile information (gender, race, career, about me, etc) directly on their profile page (will use in-place editing). So I just need to know if the steps I have taken are correct (I haven't used the terminal yet) and if so how do I get the edit page to display as it shows routing error atm.

Just a few general pointers.
In the Railscasts the users_controller's new and create actions are being created. You'd like to edit a user, so you could build out the edit and update actions of this very controller.
# app/controllers/users_controller.rb
class UsersController < ...
def new
# exists
end
def create
# exists
end
def edit
# load the current_user; make sure a user can only edit his record!
end
def update
# save edit for the current_user, same security as above
end
end
In your routes you could figure out how to route a resource :profile singular resource (Rails guides) to map to the appropriate actions.

Related

Devise gem admin can add user into user model

I am using devise gem for authentication in Rails. I want to create a admin dashboard that can add user into User model. I am able to render form into admin#index view, but I am not able to insert data in user model.
routes.rb
# when i use post method in this route i get routing error
get '/admin' => "admin#index", as: :create_user
Admin index.html.erb
<%= form_for User.new, url: create_user_path do |f| %>
<div class="log-in-form">
<h2 class="login-header text-center">Sign up</h2>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
admin_controller.rb
def index
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if User.save
redirect_to root_path
else
render :new
end
end
private
def user_params
params.require(:user).permit(:name,:password)
end
Sir, you badly need to read and understand this: https://guides.rubyonrails.org/routing.html
Answer:
You have defined the route as a get method yourself and you are expecting to post to it. Do you see something very odd here?
As a beginner, try not to deviate from basic CRUD routes that rails provides for you. In your case, do this in routes.rb:
resources :users
# OR:
# resources :users, only: %i[index show create update destroy]
# any names of CRUD functions that you probably will use (to avoid extra routes)
Now, in your html file change url: create_user_path to url: users_path.
BTW, at least make it a habit to check your routes in terminal like in your case: rails routes | grep user will give you the rails routes having word user in them.
It should work now.
Add following line in your config/routes.rb
post '/admin' => 'admin#index'

Update information of different user with extension of Devise

I setup a platform that uses Devise to create and manage users and CanCanCan to manage permissions. Users have a role (admin or client) that allows them access to certain areas. Admin users have the ability to can :manage, :all
I extended Devise so that I have a users/registrations and users/sessions controller.
Admin users have access to views in a ManagerController dashboard that allows them to manage other users. I've figured out how to show the details of a different user, but I can't figure out how to save the information. I get errors that indicate it either can't find the User or that it requires a POST route.
I'm fairly new to Rails, so it could be something simple. I was able to find solutions that included the regular Devise installation, but not the extension. I feel like the problem may be in my routes.
I also can't create new users from here either.
Routes.rb
get 'users' => 'manager#users'
get 'users/edit' => 'manager#edit'
post 'users/edit' => 'manager#edit'
get 'users/new' => 'manager#new'
devise_for :users, :controllers => { registrations: 'users/registrations', sessions: 'users/sessions' }
devise_scope :user do
authenticated :user do
root 'users/registrations#edit', as: :authenticated_root
end
unauthenticated do
root 'users/sessions#new', as: :unauthenticated_root
end
end
Manager Controller
class ManagerController < ApplicationController
authorize_resource :class => false
include ManagerHelper
def users
#users = User.where.not(:id => current_user.id)
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:notice] = "Successfully created User."
redirect_to root_path
else
render :action => 'new'
end
end
def edit
#user = User.find(params[:id])
#companies = Company.all
end
def update
#user = User.find(params[:id])
params[:user][:id].delete(:password) if params[:user][:password].blank?
params[:user][:id].delete(:password_confirmation) if params[:user][:password].blank? and params[:user][:password_confirmation].blank?
if #user.update(user_params)
flash[:notice] = "Successfully updated User."
redirect_to root_path
else
render :action => 'edit'
end
end
end
private
def user_params
params.require(:user).permit(:email, :first_name, :last_name, :company_id, :role, :password, :password_confirmation)
end
end
ManagerHelper
module ManagerHelper
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Manager/Edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => #user, :url => edit_user_registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= f.hidden_field :id %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name%>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :company %><br />
<%= f.collection_select :company_id, #companies, :id, :name, prompt: true %>
</div>
<div class="field">
<%= f.label :role %><br />
<%= f.text_field :role %>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "new-password" %>
<% if #minimum_password_length %>
<br />
<em><%= #minimum_password_length %> characters minimum</em>
<% end %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
I would like the updated information to be saved to the User database.
Currently, I get this error when I click update after changing the user info.
ActiveRecord::RecordNotFound in ManagerController#edit
Couldn't find User without an ID
Weirdly, when I see the User info, the url is: http://localhost:3000/users/edit?id=2
But when I update (and get the error), the url changes to: http://localhost:3000/users/edit.user
I would also like to be able to create New Users from this screen.
Currently, the user form populates with the information of the user who is logged in. (To be fair, I have been trying to get the edit user correct before tackling this issue.)
I think You want to update existing user info.
If that is the case:
I find your url path is wrong
:url => edit_user_registration_path(resource_name)
you donot have to user registration here .
If the admin going to update info
in routes file . some thing like this
namespace :admins do
resources :users
end
then use the path creatd from this
Many tries later, I've found a solution. There were a lot of errors, so bear with me.
Routes.rb -- Was using the wrong URL in the form submission, so needed to add the routes for the Update function in the Manager controller.
get 'users/edit' => 'manager#edit'
post 'users/edit' => 'manager#edit'
get 'users/update' => 'manager#update'
post 'users/update' => 'manager#update'
Manager Controller -- I had to change the password rules so that I could update without a password. Similar concept, slightly different execution.
def update
#user = User.find(params[:user][:id])
#companies = Company.all
if params[:user][:password].blank? && params[:user][:password_confirmation].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if #user.update(user_params)
flash[:notice] = "Successfully updated User."
redirect_to root_path
else
render :action => 'edit'
end
end
Rendered Form.html.erb - Updated with newly created URL path.
<%= form_for(resource, as: #user, url: users_update_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>

Get Request is passed instead of post request from new.html

I am trying out for basic login and registration in ruby on rails,
ISSUE: When I click register button from new.html I am getting GET request but I can see method="post" in page source of that html
I have posted my code below
new.html.erb
<form>
<%= form_for(#user) do |f| %>
<%= f.label :user_name %>
<%= f.text_field :user_name %></br>
<%= f.label :email_id %>
<%= f.text_field :email_id %></br>
<%= f.label :password %>
<%= f.password_field :password %></br>
<%= f.label :college %>
<%= f.text_field :college %></br>
<%= f.label :major %>
<%= f.text_field :major %></br>
<%= f.label :current_job %>
<%= f.text_field :current_job %></br>
<%= f.submit("Create Account",class: "btn btn-primary") %>
<% end %>
</form>
My index.html.erb code which is loaded while application starts
<div class="container">
<div class="row">
<div class="login">
<%= form_tag("/user/login",:method => :post) do %>
<%= label_tag(:EmailId) %>
<%= text_field_tag(:email, params[:email]) %></br>
<%= label_tag(:password) %>
<%= password_field_tag(:password, params[:password]) %></br>
<%= submit_tag("Log In",class: "btn btn-primary") %>
<%= submit_tag("Register",class: "btn btn-primary") %>
<% end %>
</div>
</div>
</div>
My controller code
class UsersController < ApplicationController
def index
#user = User.all
end
def login
print "In Sign in controller"
#user = User.new
if params[:commit] == 'Register'
print "inside Register class"
redirect_to '/users/new'
else
#user = User.find(params[:email_id])
if #user and user.authenticate(params[:password])
sessions[:userId] = #user.user_id
end
end
end
def new
puts "****Inside New Method******"
#user = User.new
end
def create
puts "****Inside create Method******"
end
private
def user_params
end
end
My Route code
Rails.application.routes.draw do
root 'users#index'
resources :users
post '/users/login' => 'users#login'
As per my understanding post request should hit create method, but get /users method is hitting. Please help me out regarding this
Why do you have nested forms in new.html.erb? Remove the first form tag
<form>
<%= form_for(#user) do |f| %>
You have a form tag inside another form tag. Remove the tag at the top of your form. <%= form_for(#user) %> takes care everything that's needed to build the correct form.

Redirect_to(:back) in Rails after saving form to database causing routing errors

I am building a Rails from from scratch (without the use of Scaffold for the first time) to do a simple thing: submit to a database the username and a post.
To do that, in my Stories Controller, I have set up a create method:
class StoriesController < ApplicationController
def index
#posts = Post.where(slug: params[:id]).all
end
def create
#comments = Comment.new(params[:comments])
#comments.save
redirect_to(:back)
end
end
Then, in my view, I have this form in my Stories view:
<%= form_for :comments do |f| %>
<div class="form-group">
<div class="field">
<%= f.label :username %><br>
<%= f.text_field :username, class: "form-control" %>
</div>
</div>
<div class="form-group">
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :post, class: "form-control" %>
</div>
</div>
<p>
<%= f.submit %>
</p>
<% end %>
What's weird is that when I click save, it fails to save to the table and has a routing error:
No route matches [POST] "/stories"
Troubleshooting
First off, I want to redirect back to the same page I was on, which has a URL like http://localhost:3000/stories?id=example-post-slug. I thought the routing error was weird, because shouldn't it just go back based on my controller code?
I also thought my routes.rb file could be an issue, but I have added it as a resource as other answers have suggested:
routes.rb
Rails.application.routes.draw do
resources :posts
resources :comments
get "stories" => "stories#index", as: :stories
....
end
Thus, I am confused. Why am I having a routing issue when I have defined the create method, added the Comments table as a resource, and I have chosen a redirect in my controller?

edit link for "admins" in devise rails

I have a rails app using devise for registrations and rolify for roles. I would like to have an index page that has edit links for each of the users that can be accessed by an admin. This edit page should also work without having to use a password. Right now the edit_user_path goes to the edit page of the current user, which is not what i want.
What is the best way to implement this sort of sitation? i've read a few of the posts on here about this but none seem to give me what i want.
Please point me in the right direction!
EDITED
I'm attempting to do it this way, still running into "Current password can't be blank"
From Users_controller:
def update
#user = User.find(params[:id])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if #user.update_attributes(user_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
And in my views i have an edit.html.erb file that is rendering the following form:
<div class="panel-body">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: "form-control", :autofocus => true %>
</div>
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :username, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :firstname %>
<%= f.text_field :firstname, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :lastname %>
<%= f.text_field :lastname, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :city %>
<%= f.text_field :city, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :zip %>
<%= f.text_field :zip, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :state %>
<%= f.text_field :state, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :country %>
<%= f.text_field :country, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit "Update", class: "btn btn-primary" %>
</div>
<% end %>
</div>
and finally in my routes.rb file i have this line to render the edit page. I can get the edit page to show up but entering info and then hitting update just shoots me to /users with the error "Current Password can't be blank"
get 'pressroom/accounts/:id/edit' => 'users#edit', :as => :admin_edit_user
Devise doesn't come with any sort of Admin interface. If you are the only administrator and don't mind a little crudeness - there is always the console and/or scaffolding. You could create a UserController which inherits from ApplicationController and execute basic view, edit methods in the same controller. By placing the appropriate new.html.erb, edit.html.erb etc files in the User Views folder, adding/editing/deleting Users should work no differently as any other CRUD, as Devise's User is another model like any. Use a scaffold on the user and you could get what you are looking for.
There are also a lot of good gems that make setting up admin interfaces a cinch: https://github.com/gregbell/active_admin Active Admin, https://github.com/sferik/rails_admin Rails Admin and I'm sure there are a bunch more out there.
It looks like i got it working by adding:
<div class="panel-body">
<% #user = User.find(params[:id]) %>
<%= form_for(#user) do |f| %>
to the top of my _form.html.erb file
Thanks for the help everyone!
If the only thing you need is for the admin to EDIT an existing user, you can have the edit, show and update actions in a separate UsersController (and leave new and create actions up to devise). That way you can move that #user = User.find(params[:id] logic out of your form, into the controller, as #Saurabh Lodha mentioned.
I just thought one thing was missing from the answers though: Make sure to also edit your routes.rb. Use a path prefix so your routing doesn't get confusing, kind of like this:
devise_for :users, :path_prefix => 'my'
resources :users
this means that when you call edit on a current_user, it will go to my/users/edit, and when you call edit on any selected user from your user list in the admin panel, it will take you to users/user_id/edit.
I hope that clarified it a bit more! good luck! :)

Resources