Rails Devise : how to update user by id? - ruby-on-rails

I would like to update a user by id.
I don't know if I need to create another function or the devise update use function.
This doesn't work, it updates my current user instead of the user of data id (I update my user by axios api call):
const data = {
user = {
first_name: 'firstNameChanged'
id: 10
}
};
axios.put('http://localhost:3000/users', data).then((res) => {
console.log('user updated');
});
EDIT:
route.rb
devise_for :users, defaults: { format: :json }, controllers: { registrations: "registrations" }
devise_scope :user do
delete 'users/:id', to: 'registrations#destroy_by_id', defaults: { format: :json } # custom delete_by_id
end
rake routes
new_user_session GET /users/sign_in(.:format) devise/sessions#new {:format=>:json}
user_session POST /users/sign_in(.:format) devise/sessions#create {:format=>:json}
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy {:format=>:json}
new_user_password GET /users/password/new(.:format) devise/passwords#new {:format=>:json}
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit {:format=>:json}
user_password PATCH /users/password(.:format) devise/passwords#update {:format=>:json}
PUT /users/password(.:format) devise/passwords#update {:format=>:json}
POST /users/password(.:format) devise/passwords#create {:format=>:json}
cancel_user_registration GET /users/cancel(.:format) registrations#cancel {:format=>:json}
new_user_registration GET /users/sign_up(.:format) registrations#new {:format=>:json}
edit_user_registration GET /users/edit(.:format) registrations#edit {:format=>:json}
user_registration PATCH /users(.:format) registrations#update {:format=>:json}
PUT /users(.:format) registrations#update {:format=>:json}
DELETE /users(.:format) registrations#destroy {:format=>:json}
POST /users(.:format) registrations#create {:format=>:json}
DELETE /users/:id(.:format) registrations#destroy_by_id {:format=>:json}
thanks !

Devise actually only has routes and controllers to modify your own account. If you want an interface to administrate other users you are best off just creating it yourself or finding an existing implementation.
While its certainly possible to shoehorn this functionality into Devise its just going to get messy and violates the SRP as your RegistrationsController is no longer just responsible for handling user registration but also administrating other users.
You can pretty much just work off the Rails scaffolds (rails g scaffold users --skip-migration --skip-model) as its not really that different from CRUD'ing any other resource. What you really need is just something like:
# routes.rb
resources :users, except: [:new, :create]
# This controller is for administrating other users
class UsersController < ApplicationController
# ensures that there is a logged in user
# you should also implement authorization that ensures that the user is allowed to administrate other users
before_action :authenticate_user!
# sets the user to be acted upon
before_action :set_user, only: [:show, :edit, :update, :destroy]
# PUT|PATCH /users/1
def update
if #user.update(user_params)
head :ok
else
head :unprocessable_entity
end
end
# ...
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:first_name)
end
end
const data = {
user = {
first_name: 'firstNameChanged'
}
};
axios.put('http://localhost:3000/users/10', data).then((res) => {
console.log('user updated');
});

Check your rake routes | grep user and you'll find there is an entry under PUT. The path would look like /users/:id, that's your first mistake. This would also map (typically) to a UsersController#update action.
You can then access the id that's passed via the params (use strong params too) and find your user with User.find_by(id: permitted_params[:id]). You can create a private method called permitted_params along the lines of
def permitted_pararms
params.permit(:id)
end

Related

Passing nested params from create in redirect to show of nested controller

I have a schema like:
Company belongs to Users (devise)
Quote belongs to Company
Employees belong to Company
I have a simple_form_for using cocoon to create Company & Quote & Employees from the create action in the Company controller, all objects being created just fine by the create method. But on .save of these objects I am trying to redirect to Quotes#show of the quote created by Companies#create but I'm having trouble getting the quote_id over to Quotes#show.
Can you help me understand how to get the right params over to succesfully redirect? Thanks.
companies.rb
class CompaniesController < ApplicationController
before_action :authenticate_user!, only: [ :new, :create, :edit, :update, :destroy ]
def new
#company = Company.new
#company.quotes.build
#company.employees.build
end
def create
#company = current_user.companies.new(company_params)
if #company.save
redirect_to company_quote_url(#company.id), notice: 'Quote request created'
else
render :new
end
end
private
def company_params
params.require(:company).permit(:co_name, :co_number, :postcode, :industry,
:quotes_attributes => [:id, :lives_overseas, :payment_frequency],
:employees_attributes => [:id, :first_name, :last_name, :email, :gender, :date_of_birth, :salary, :_destroy] )
end
end
quotes.rb
class QuotesController < ApplicationController
def show
#quote = #company.quotes.find(params)
end
end
routes
quotes_show GET /quotes/show(.:format) quotes#show
quotes_index GET /quotes/index(.:format) quotes#index
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
company_quotes GET /companies/:company_id/quotes(.:format) quotes#index
company_quote GET /companies/:company_id/quotes/:id(.:format) quotes#show
company_employees GET /companies/:company_id/employees(.:format) employees#index
company_employee GET /companies/:company_id/employees/:id(.:format) employees#show
companies GET /companies(.:format) companies#index
POST /companies(.:format) companies#create
new_company GET /companies/new(.:format) companies#new
edit_company GET /companies/:id/edit(.:format) companies#edit
company GET /companies/:id(.:format) companies#show
PATCH /companies/:id(.:format) companies#update
PUT /companies/:id(.:format) companies#update
DELETE /companies/:id(.:format) companies#destroy
root GET / companies#new
error message
No route matches {:action=>"show", :company_id=>65, :controller=>"quotes"} missing required keys: [:id]
I can't see how to get the quote_id route accross from Companies#create over to Quotes#show. When I run the redirect like; redirect_to company_quote_url(company_params) the error shows the header params being passed like this, i.e. this is what's available;
No route matches {:action=>"show", "co_name"=>"acme1", "co_number"=>"12345678", :controller=>"quotes",
"employees_attributes"=>{"0"=>{"first_name"=>"brian", "last_name"=>"blessed", "email"=>"brian#test.com", "gender"=>"m", "date_of_birth(1i)"=>"2001", "date_of_birth(2i)"=>"6", "date_of_birth(3i)"=>"28", "salary"=>"10000", "_destroy"=>"false"}}, "industry"=>"financial_services", "postcode"=>"al8 8ba",
"quotes_attributes"=>{"0"=>{"lives_overseas"=>"true", "payment_frequency"=>"annually"}}} missing required keys: [:company_id, :id]
I've played and failed with different variations of;
(params[:company][:quote_attributes[:id]])
(#company.quote.id)
yet i just can't seem to get it right, can anyone help please. Thanks
Since company has_many quotes, you should track the latest quote for that company and redirect to that show view of the quote.
def create
#company = current_user.companies.new(company_params)
if #company.save
#quote = #company.quotes.last
redirect_to company_quote_url(#company,#quote), notice: 'Quote request created'
else
render :new
end
end
last will give you the latest record with the help of created_at
Also you should tweak your quotes#show like below else it will error out.
def show
#company = Company.find(params[:company_id])
#quote = #company.quotes.find(params[:id])
end

Routes not changing upon editing controller

I'm configuring devise to work with two omniauth providers: twitter and github. Having implimented github first, I created a github method in my OmniauthCallbacksController. Deciding later that I wanted to use twitter as well, I reconfigured my controller, discarding the github method in favor of a more sophisticated implementation for both providers.
The Problem is that when I run rake routes, the old github method is all that appears and it seems that my changes to the controllers haven't even been recognized. I can even delete everything out of the controller and my rake routes result is left unchanged. I've attached the relevant files below. Many thanks in advance for any insight you can give me.
My routes file is below (note the existence of the now nonexistent users/omniauth_callbacks#github method):
Rails.application.routes.draw do
resources :issues
resources :submissions
resources :home
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup
root to: "home#index"
end
When I run rake:routes, I get the following:
$ rake routes
Prefix Verb URI Pattern Controller#Action
issues GET /issues(.:format) issues#index
POST /issues(.:format) issues#create
new_issue GET /issues/new(.:format) issues#new
edit_issue GET /issues/:id/edit(.:format) issues#edit
issue GET /issues/:id(.:format) issues#show
PATCH /issues/:id(.:format) issues#update
PUT /issues/:id(.:format) issues#update
DELETE /issues/:id(.:format) issues#destroy
submissions GET /submissions(.:format) submissions#index
POST /submissions(.:format) submissions#create
new_submission GET /submissions/new(.:format) submissions#new
edit_submission GET /submissions/:id/edit(.:format) submissions#edit
submission GET /submissions/:id(.:format) submissions#show
PATCH /submissions/:id(.:format) submissions#update
PUT /submissions/:id(.:format) submissions#update
DELETE /submissions/:id(.:format) submissions#destroy
home_index GET /home(.:format) home#index
POST /home(.:format) home#create
new_home GET /home/new(.:format) home#new
edit_home GET /home/:id/edit(.:format) home#edit
home GET /home/:id(.:format) home#show
PATCH /home/:id(.:format) home#update
PUT /home/:id(.:format) home#update
DELETE /home/:id(.:format) home#destroy
user_github_omniauth_authorize GET|POST /users/auth/github(.:format) users/omniauth_callbacks#passthru
user_github_omniauth_callback GET|POST /users/auth/github/callback(.:format) users/omniauth_callbacks#github
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
finish_signup GET|PATCH /users/:id/finish_signup(.:format) users#finish_signup
root GET / home#index
And my new Oauth callbacks controller looks like this:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
#user = User.find_for_oauth(env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect #user, event: :authentication
set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
else
session["devise.#{provider}_data"] = env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
}
end
[:twitter, :github].each do |provider|
provides_callback_for provider
end
def after_sign_in_path_for(resource)
if resource.email_verified?
super resource
else
finish_signup_path(resource)
end
end
end
Figured it out! Turns out the issue wasn't with any of the files I posted. In the User model, I had the following line: omniauth_providers: [:github] I needed to add twitter to it.

Rails 4: Edit/Update Threads, Edit/Update Posts

Before I begin yes I know I need a edit and update function in the posts and threads controller, but the issue I have is with the forum_post.user details getting lost in the update and the thread duplicating posts after the update, so I removed the code entirely so I can get help solving the problem by posting the controllers themselves.
But you're going to need the routes, before I post it /forum/ is just a fake route to nest the forum_threads/posts in and does not exist outside of it's scope.
Rake Routes output
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
forum_thread_forum_posts GET /forum/forum_threads/:forum_thread_id/forum_posts(.:format) forum_threads/forum_posts#index
POST /forum/forum_threads/:forum_thread_id/forum_posts(.:format) forum_threads/forum_posts#create
new_forum_thread_forum_post GET /forum/forum_threads/:forum_thread_id/forum_posts/new(.:format) forum_threads/forum_posts#new
edit_forum_thread_forum_post GET /forum/forum_threads/:forum_thread_id/forum_posts/:id/edit(.:format) forum_threads/forum_posts#edit
forum_thread_forum_post GET /forum/forum_threads/:forum_thread_id/forum_posts/:id(.:format) forum_threads/forum_posts#show
PATCH /forum/forum_threads/:forum_thread_id/forum_posts/:id(.:format) forum_threads/forum_posts#update
PUT /forum/forum_threads/:forum_thread_id/forum_posts/:id(.:format) forum_threads/forum_posts#update
DELETE /forum/forum_threads/:forum_thread_id/forum_posts/:id(.:format) forum_threads/forum_posts#destroy
forum_threads GET /forum/forum_threads(.:format) forum_threads#index
POST /forum/forum_threads(.:format) forum_threads#create
new_forum_thread GET /forum/forum_threads/new(.:format) forum_threads#new
edit_forum_thread GET /forum/forum_threads/:id/edit(.:format) forum_threads#edit
forum_thread GET /forum/forum_threads/:id(.:format) forum_threads#show
PATCH /forum/forum_threads/:id(.:format) forum_threads#update
PUT /forum/forum_threads/:id(.:format) forum_threads#update
DELETE /forum/forum_threads/:id(.:format) forum_threads#destroy
import_users POST /users/import(.:format) users#import
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
root GET / forum_threads#index
Routes:
Rails.application.routes.draw do
devise_for :users
scope "/forum" do
resources :forum_threads do
resources :forum_posts, module: :forum_threads
end
end
resources :users do
collection do
post :import
end
end
root 'forum_threads#index'
end
Forum Threads Controller
class ForumThreadsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_forum_thread, except: [:index, :new, :create]
def index
#q = ForumThread.search(params[:q])
#forum_threads = #q.result(distinct: true)
end
def show
#forum_post = ForumPost.new
end
def new
#forum_thread = ForumThread.new
#forum_thread.forum_posts.new
end
def create
#forum_thread = current_user.forum_threads.new forum_thread_params
#forum_thread.forum_posts.first.user_id = current_user.id
if #forum_thread.save
redirect_to #forum_thread
else
render action: :new
end
end
def destroy
#forum_thread.destroy
redirect_to root_path
end
private
def set_forum_thread
#forum_thread = ForumThread.find(params[:id])
end
def forum_thread_params
params.require(:forum_thread).permit(:subject, forum_posts_attributes: [:body])
end
end
Forum Posts Controller
class ForumThreads::ForumPostsController < ApplicationController
before_action :authenticate_user!
before_action :set_forum_thread
def create
#forum_post = #forum_thread.forum_posts.new forum_post_params
#forum_post.user = current_user
if #forum_post.save
redirect_to forum_thread_path(#forum_thread, anchor: "forum_post_#{#forum_post.id}"), notice: "Successfully posted!"
else
redirect_to #forum_thread, alert: "Unable to save your post"
end
end
private
def set_forum_thread
#forum_thread = ForumThread.find(params[:forum_thread_id])
end
def forum_post_params
params.require(:forum_post).permit(:body)
end
end
I know the forum edit path for link_to will be edit_forum_thread_path or just correct me if I'm wrong, but it's the posts edit/delete path I need help with since that controller is nested under forum_threads and using the module forum_threads, I originally figured it would be edit_forum_threads_forum_posts_path but that wasn't it either last time I tried before I removed those functions.
It would be edit_forum_thread_forum_post_path based on your rake routes output.

devise redirect on login error: ActiveRecord::RecordNotFound in DocumentsController#show

I 'm trying to redirect to a specific page after sign_in & sign_up. I have two models users & resources. After sign_in I want to show list of documents that belong to the user.
If there are no documents then it should redirect to users/:id/document#create otherwise users/:id/document#index.
Any suggestions how do i do that?
I get the following error for the redirect path defined in my controller.
ActiveRecord::RecordNotFound in DocumentsController#show
Couldn't find Document without an ID
Application_controller.rb
def after_sign_in_path_for(user)
user_documents_url(user)
end
Routes.rb
root :to => 'home#index'
devise_for :users
resources :users do
resources :documents
end
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy' end
Routes
root / home#index
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
user_password POST /password(.:format) devise/passwords#create
new_user_password GET /password/new(.:format) devise/passwords#new
edit_user_password GET /password/edit(.:format) devise/passwords#edit
PUT /password(.:format) devise/passwords#update
cancel_user_registration GET /cancel(.:format) devise/registrations#cancel
user_registration POST / devise/registrations#create
new_user_registration GET /sign_up(.:format) devise/registrations#new
edit_user_registration GET /edit(.:format) devise/registrations#edit
PUT / devise/registrations#update
DELETE / devise/registrations#destroy
user_confirmation POST /confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /confirmation/new(.:format) devise/confirmations#new
GET /confirmation(.:format) devise/confirmations#show
user_documents POST /users/:user_id/documents(.:format) documents#create
new_user_documents GET /users/:user_id/documents/new(.:format) documents#new
edit_user_documents GET /users/:user_id/documents/edit(.:format) documents#edit
GET /users/:user_id/documents(.:format) documents#show
PUT /users/:user_id/documents(.:format) documents#update
/user/:user_id/documents(.:format) user/documents#index
Thanks
The code itself has no problem as I see. But you need to build some "documents" data before this test, either by FactoryGirl or stubs.
Because you really don't have "documents" data for any users, of course Rails gave you to RecordNotFound error.
use this method according to following code
def after_sign_in_path_for(resource_or_scope)
// redirect path
end
i hope this will help
I fixed my problem by following this question.Following is my routes.rb
resources :users do
resources :documents, only: [:index]
end
resource :documents, except: [:index]
this gives me document#index path as well as document#new path.

User Profile Controller Rspec Test Fails due to route

I'm having a problem testing my new user profile page with Rspec. It's working through the browser, but Rspec is blowing up.
I'm using devise with a separate controller for editing profile fields.
This is a request spec.
it 'Shows the user profile with their non-private data' do
visit user_path(#user)
page.should have_content #user.full_name
end
Fails with this error:
Failure/Error: visit user_path(#user)
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"users"}
I disagree
#routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
resources :users, :only => [:edit, :update, :show]
The update and edit path helpers are working just fine.
The controller action:
class UsersController < ApplicationController
layout 'profile', :except => [:show]
#... edit and update omitted
def show
#user = User.find(params[:id])
end
end
rake routes shows:
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) registrations#cancel
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
PUT /users(.:format) registrations#update
DELETE /users(.:format) registrations#destroy
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
So it doesn't really look like devise is interfering with my route, and more importantly, everything works in the browser. What am I missing here?
I also tried making a member action called profile instead of the default show, that had the same result
The problem here was I started a new context block and didn't set up #user before the it block. The route thing was just a red herring.
Also proof that you should walk away from your code for awhile if you can't figure things out.

Resources