Devise unable to get current_user - ruby-on-rails

I want to get the token of the successfully logged user so I created the get_token method in my Application Controller:
def after_sign_in_path_for(resource)
if current_user.role.role_type === 'user'
current_user.regenerate_token
#user_token = current_user.token
puts #user_token #logging properly
user_profile_path
else
rails_admin_path
end
end
def get_token
return #user_token
end
Now, I want to get the value of the token in my controller namely, Api::V1::CommentController so i have my code
class Api::V1::CommentController < ApplicationController
def initialize
#http_status = { :status => false }
end
def create
puts get_token #I just want to log this
render :json => #http_response
end
end
With the code above, I am not getting the generated token when testing it using POSTMAN. What am I doing wrong?
EDIT:
I have this in my routes:
namespace :api do
namespace :v1 do
devise_scope :user do
post 'comment/create' => 'comment#create'
end
end
end

The instance variable you are setting will be available for only that specific request.
Just change the method to
def get_token
current_user.token
end

Related

Nested resource: controller spec doesn't call the wanted action

I have a ReportsController, nested in ProjectsController, with a #show method:
def show
# Some stuff
do_something(#report)
end
Routes:
resources :projects do
resources :reports
end
I need to test that the do_something method is called:
it 'calls do_something' do
expect(controller).to receive(:do_something)
project = create :project
report = create :report, project: project
get :show, params: {project_id: project.id, id: report.id}
end
I placed binding.pry within the #show action, but this doesn't get called. So what's wrong with my spec?
The problem was that I wasn't logged in:
before do
#user = create :user, :admin
sign_in_as #user
end

Why I still get all user when use get method with params for specific user?

I am using Rails 4.2.4 with Ruby 2.2.3
This is my users_controller.rb
class Api::UsersController < ApplicationController
def index
#users = User.all
render json: #users
end
def show
#user = User.where('email = ?', params[:email]).first
if #user.present?
render json: {info: 'Find a user'}
else
render json: {error: 'User not found'}
end
end
end
This is my routes file
Rails.application.routes.draw do
namespace :api do
resources :users
end
end
I am trying to build a Rails API.
When I use this url to send on postman
localhost:3000/api/users
I can get all users.(total 3)
Then I use this url to send on postman
localhost:3000/api/users?email=example.com
I still get all users and I am sure that only one user match this email.
Where is the problem? I suppose get {info: 'Find a user'}.
this is because this url trigger index:
localhost:3000/api/users?email=example.com
to solve send your request to:
localhost:3000/api/users/example.com
and change your routes:
resources :users do
member do
get 'users/:email', to: 'users#show'
end
end

User sessions and logins

I am trying to implement signup & login features on ROR. on Index page i have created 2 links saying 'new user' and 'login' and in userscontroller i have signup & login methods(updated routes accordingly).
prob: upon clicking new user or login i am getting an error saying
"The action 'show' could not be found for UsersController"
routes.rb:
Rails.application.routes.draw do
resources :users
get 'users/register', :to=>'users#register'
get 'users/signup', :to=>'users#signup'
post 'users/signup', :to=>'users#signup'
post 'users/login', :to=>'users#login'
get 'users/login', :to=>'users#login'
post "users/change_password" => "users#change_password"
get "users/change_password" => "users#change_password"
index.html.erb
<%= link_to "New User", users_register_path %><br>
<%= link_to "Login", users_login_path %><br>
<%= link_to "Change Password", users_change_password_path %><br>
userscontroller:
def index
#user_details = User.all
end
def register
puts "**********************"
puts params
#new_user = User.new
end
def signup
#new_user = User.new(user_register)
if #new_user.save
session[:user] = User.authenticate(#user.name,#user.password)
redirect_to :action=>"welcome"
else
redirect_to :action=>"login"
end
end
def login
puts params
if request.post?
session[:user] = User.authenticate(params[:user][:name], params[:user][:password])
redirect_to :action=>"welcome"
else
# redirect_to :action=>"signup"
end
end
def change_password
puts "**********************"
puts params
puts "**********************"
if request.post?
#pass_change = User.new_password(params[:user][:name], params[:user][:password], params[:user][:new_password])
end
end
def welcome
end
def user_register
params.require(:user).permit(:name,:email,:password,:password_confirmation)
end
end
usermodel.rb:
require 'digest/sha1'
class User < ActiveRecord::Base
attr_accessor :password, :password_confirmation
def password=(pass)
#password = pass
self.salt = User.random_met(10)
self.hashedpassword = User.encrypt(#password, self.salt)
end
def self.encrypt(pass,salt)
Digest::SHA1.hexdigest(pass+salt)
end
def self.authenticate(login, pass)
user_auth = User.find(:first, :conditions=>["login = ?", login])
return nil if user_auth.nil?
return user_auth if User.encrypt(pass,user_auth.salt)==user_auth.hashedpassword
end
def self.new_password(name,old,new)
user = where(:name=>name)
#puts user.email
# how to call setter(password) method from here. because My idea is
#if User.encrypt(old, user.salt)==user.hashedpassword
# run def password=(pass), thereby storing new password.
end
def self.random_met(len)
char = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
salted = ""
1.upto(len) { |i| salted << char[rand(char.size-1)] }
return salted
end
end
As written in the Guides,
Rails routes are matched in the order they are specified, so if you
have a resources :photos above a get 'photos/poll' the show action's
route for the resources line will be matched before the get line. To
fix this, move the get line above the resources line so that it is
matched first.
You have defined resources :users above the get routes, so the rails will look for a show route, so is the error.

NoMethodError in controller#new - undefined method

I'm getting a NoMethodError in the new action of my business_controller.
It seems to be acessing the #business object for a form in my view and the error occurs then:
undefined method `businesses_path' for
Here is my new method:
def new
if Business.where(:user_id => current_user.id).first.blank?
#business = Business.new
else
redirect_to user_businesses_path(current_user.id)
end
end
My routes are:
resources :users do
resources :businesses
member do
get 'account'
post 'payment'
put 'update_password'
get 'membership'
end
end
mind.blank's suggested changes
before_filter :check_if_user_has_business, :only => :index
def new
#business = Business.new
end
private
def check_if_user_has_business
redirect_to new_user_business_path(current_user) unless current_user.business
end
Do you have a route businesses_path or only user_businesses_path? If you only have the second one then you should specify that URL in your form:
<%= form_for #business, url: user_businesses_path do |f| %>
Also, if you have the correct associations set up, then you can write your if statement as follows:
if current_user.business.nil? # since it's a has_one association
Here's how I would write it:
Class BusinessesController < ApplicationController
before_filter :check_if_user_has_business, only: :new
def new
#business = Business.new
end
private
def check_if_user_has_business
redirect_to user_businesses_path(current_user) if current_user.business
end
end

Devise how to redirect to different page (based on some parameter) after sign in?

In my application, I have two different login forms from two controller which will both sign_in through the Devise::SessionsController, the problem is after successful sign in (or failure) I need to redirect to different pages that specific to the controller. How can I do this. I currently have this in my Devise::SessionsController, which
class SessionsController < Devise::SessionsController
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
return sign_in_and_redirect(resource_name, resource)
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
redirect_to dashboard_path
end
def failure
redirect_to index_path
end
end
In application controller
before_filter :store_location
def store_location
unless params[:controller] == "devise/sessions"
url = #calculate the url here based on a params[:token] which you passed in
session[:user_return_to] = url
end
end
def stored_location_for(resource_or_scope)
session[:user_return_to] || super
end
def after_sign_in_path_for(resource)
stored_location_for(resource) || root_path
end
If anyone is still looking for a work around. I was able to solve this by:
First, create a Sessions controller inheriting from Devise::SessionsController
class SessionsController < Devise::SessionsController
def new
get_pre_login_url(request.referer)
super
end
def create
##referer_url
super
end
private
def get_pre_login_url(url)
##referer_url = url
end
def after_sign_in_path_for(resource)
# ##referer_url
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => 'http')
if ##referer_url == sign_in_url
super
else
stored_location_for(resource) || ##referer_url || root_path
end
end
end
You'll notice I'm setting a class variable (##variable_name), which I'm not keen on, but this is what I came up with after 4 hours of trying various other ways of solving this. I'm also trying to be careful not to screw with Devise's controller too much and using super and only including the actions I care about.
Next, in routes you can now point Devise's defaults to the Controller above. You don't need it exactly like below for the devise_for, just the part referencing the controllers: { sessions: "sessions" }
MyPortfolio::Application.routes.draw do
devise_for :users, path_names: { sign_in: "login",
sign_out: "logout" },
controllers: { omniauth_callbacks: "omniauth_callbacks",
sessions: "sessions" }
resources :posts do
resources :comments
end
resources :projects do
resources :comments
end
resources :users
root :to => 'home#index'
get 'login' => 'devise/sessions#new'
get 'about_me' => 'about#index'
end
It might not be the DRYest solution around, but it was the only one that I was able to come up with to point the redirect back to the page of origin instead of root or an infinite loop.
You can do this by defining after_sign_in_path_for method in your controller, where you want to customize this redirect path.
The following is more global solution but it can be used in your case.
It uses attr_accessor. No extra params to after_sign_in_path_for action and no class variable required.
class User < ActiveRecord::Base
attr_accessor :redirect_to
end
Then, with a dedicated sessions_controller file (override as recommended by Devise), copy-paste the original devise action and add the line resource.redirect_to = sign_in_params[:redirect_to] before respond_with.
Add the new redirect to the after_sign_in_path_for action and add the :redirect_to params to devise allowed signin params.
# app/controllers/devise/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
before_filter :configure_sign_in_params, only: [:create]
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
# set redirect_to
resource.redirect_to = sign_in_params[:redirect_to]
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
# set url to redirect_to url if present
def after_sign_in_path_for(resource_or_scope)
return resource_or_scope.redirect_to if resource_or_scope.redirect_to.present? && !resource_or_scope.respond_to?(:devise_scope)
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
end
# add redirect_to to devise signin allowed params
def configure_sign_in_params
devise_parameter_sanitizer.for(:sign_in) << :redirect_to
end
end
Finally, update your view to set a hidden param for the redirect_to url
# app/views/users/sessions/new.html.haml
# from params in url
<% if (param_redirect_to = params[:redirect_to]).present?
<%= f.hidden_field :redirect_to, value: param_redirect_to %>
<% end %>
# or hardcoded if you have 2 sign-in forms
<%= f.hidden_field :redirect_to, value: 'your custom redirect url' %>
GET http://localhost:3000/login?redirect_to=www.test.com will redirect your user to www.test.com after successful signing

Resources