NoMethodError in AuthenticationsController#create | omniauth + devise - ruby-on-rails-3

NoMethodError in AuthenticationsController#create
undefined method `user' for # /Authentication:0x00000105c7b1f8\
I'm pulling my hair out.. I downloaded the sample app from railscasts and it works.. mine has what looks like one last bug.
I am attempting to follow the railscasts to add this in to my app that is/was otherwise working -
http://railscasts.com/episodes/236-omniauth-part-2
It seems that it's mostly getting there - in the authorizations table there is a record..
I'm not getting as far as the step where the page asks for an email because it doesn't have one.
I'm sure this is super simple - here are some snippets:
controller:
class AuthenticationsController < ApplicationController
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
#user = User.new
#user.apply_omniauth(omniauth)
if #user.save
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
end
devise user model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
has_many :authentications
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
#attr_accessible :email, :password, :password_confirmation, :remember_me
def apply_omniauth(omniauth)
self.email = omniauth['user_info']['email'] if email.blank?
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
end
some of the routes.rb:
resources :authentications
match '/auth/:provider/callback' => 'authentications#create'
get "search/show"
#devise_for :users
devise_for :users, :controllers => {:registrations => 'registrations'}

There should be #user in sign_in_and_redirect(:user, user). Not user.

Related

devise in rails 3 : 'user_signed_in?' false 'signed_in?' true 'current_user' nil

I am migrating a Rails 2 app to Rails 3 and had to use a new authentication solution since restful_authentication is no longer supported. I am trying out Devise and am having problems with it.
I have a login page, which then directs you to the app. You can also use the app without logging in but some options are not available until you login.
Once logging in Devise says that I have logged in via a flash message, but any current_user will evaluate to nil, current_user.blank? evaluates to true and any user_signed_in? will evaluate to false. Oddly signed_in? evaluates to true. Checking my session data shows that warden.user.user.id contains the correct user id and a csrf token exists. This is true both in the view and in the controller.
Here is routes.rb
MyApp::Application.routes.draw do
devise_for :users
match "/:controller(/:action(/:id))"
match "/:controller(/:action(/:id))(.:format)"
match "/:controller(/:action(.:format))"
devise_scope :user do
get 'signup', :to => 'devise/registrations#new'
get 'login', :to => 'devise/sessions#new'
get 'signout', :to => 'devise/sessions#destroy'
end
root :to => 'main#design'
end
User.rb
require 'digest/sha1'
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :confirmable, :validatable,
:encryptable, :encryptor => :restful_authentication_sha1
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_company, :profile_state, :profile_city, :profile_postcode, :profile_country, :profile_phone, :profile_address
validates_length_of :name, :maximum => 100
validates_presence_of :email
validates_length_of :email, :within => 6..100
validates_uniqueness_of :email
def profile_complete?
if !(self.profile_address.blank? || self.profile_city.blank? || self.profile_state.blank? || self.profile_phone.blank? || self.name.blank? || self.state != 'active')
true
else
false
end
end
end
I've seen a lot of similar questions on SO, but none of the answers seem to fit my scenario. Any help would be greatly appreciated, thanks!
EDIT: warden.authenticate(:scope => :user) returns what i would expect current_user to return.
I believe that I have solved this issue, the restful_authentication plugin added a UsersHelper file that I believe was somehow interfering with how Devise was handling the User class.

Devise's current_user only works for admins

I've got a standard User model, it has in it an admin boolean. All's well and good for users that have that set to true, but for normal users I get this error:
undefined local variable or method `current_user'
app/models/doc.rb:18:in `mine'
app/controllers/docs_controller.rb:9:in `index'
The Doc model on line 18 reads like this:
def self.mine
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
My User model looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
attr_accessor :current_password
attr_accessible :name, :password, :password_confirmation, :current_password, :email, :remember_me, :admin
end
class Ability
include CanCan::Ability
def initialize(user)
can :manage, :all if user.admin
end
end
And in my application controller I have the following:
class ApplicationController < ActionController::Base
protect_from_forgery
after_filter :user_activity
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_path
end
def admin?
self.admin == true
end
def authenticate_admin
redirect_to :new_user_session_path unless current_user && current_user.admin?
end
private
def user_activity
current_user.try :touch
end
end
I think that's everything relevant. I can't for the life of me figure this out.
the current_user helper is a controller method that is not accessible from a model. You should pass current user in as a parameter from the controller to the model.
def self.mine(current_user)
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
EDIT: Side note
It looks like user_id is a string in your logic. If this is what you are doing, you should reconsider. Setting up a belongs_to and a has_many with rails using identifiers in the database is far more maintainable. Using string ids is unconventional, and its a rabbit hole that ends in very bad places.

Rails 3.0 devise account validation from admin to user - undefined method `edit_user_path'

I'm trying to make an admin account to validate the registration of a user, for that I have 2 devise models: admin and user.
I've followed these steps:
https://github.com/plataformatec/devise/wiki/How-To%3a-Require-admin-to-activate-account-before-sign_in
But from the view I get this error:
Undefined method `edit_user_path'
This is my app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
def active_for_authentication?
super && approved?
end
def inactive_message
if !approved?
:not_approved
else
super # Use whatever other message
end
end
def self.send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
if !recoverable.approved?
recoverable.errors[:base] << I18n.t("devise.failure.not_approved")
elsif recoverable.persisted?
recoverable.send_reset_password_instructions
end
recoverable
end
end
App/controllers/unapproved_users_controller.rb
class UnapprovedUsersController < ApplicationController
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
end
App/views/unapproved_users.html.haml
%h1 Users
= link_to "All Users", :action => "index"
|
= link_to "Users awaiting approval", :action => "index", :approved => "false"
%table
- #users.each do |user|
%tr
%td= user.email
%td= user.approved
%td= link_to "Edit", edit_user_path(user)
This path makes the problem:
= link_to "Edit", edit_user_path(user)
Option #1 - Check rake routes for the correct helper
Option #2 - You need to setup an administrator interface to edit users as I'm pretty sure devise only provides the interface for current_user not for people wanting to edit another user.
Option #3 - Use something like RailsAdmin

Ruby on Rails updating devise user attributes without password

I have two classes of accounts in my application. I'm trying to update the attributes of one of them (Investors). They are created using one form via devise. As a result, when an investor tries to update their account information, the form requires that they provide and confirm their password. I would like for them to be able to edit (First name, last name, etc) without having to input their password unless they want to change their password with those fields.
Here is my update method in the Investor controller
def update
session[:investor_params] ||= {}
session[:investor_params].deep_merge!(params[:investor]) if params[:investor].present?
#investor.attributes = session[:investor_params]
params[:investor_params].delete(:password) if params[:investor_params][:password].blank?
params[:investor_params].delete(:password_confirmation) if params[:investor_params][:password_confirmation].blank?
respond_to do |format|
if #investor.update_attributes(params[:investor_params])
session[:investor_params] = nil
sign_in(#investor.account, :bypass => true)
format.html { redirect_to(projects_url, :notice => 'Investor was successfully updated.') }
format.xml { render :xml => #investor, :status => :created, :location => #investor }
else
format.html { render :action => "edit", :layout => "investor" }
format.xml { render :xml => #investor.errors, :status => :unprocessable_entity }
end
end
end
Here is my registrations controller
class RegistrationsController < Devise::RegistrationsController
layout "index"
protected
def after_sign_up_path_for(resource)
new_user_url(:account => resource)
end
end
Here's my routes.rb
devise_for :accounts, :controllers => {
:registrations => 'registrations',
:passwords => 'passwords',
:sessions => 'sessions' }
devise_scope :account do
root :to => 'registrations#new'
And this is a portion of my investor model that references attributes for the account model.
class Investor < ActiveRecord::Base
has_one :account, :as => :profile
accepts_nested_attributes_for :account
Here is the portion of the account model that is referenced
class Account < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :invited_by, :invited_by_id
I tried the recommendations on the devise github repo but I wasn't able to get it working for me.
If you have any suggestions or if I am missing anything, please let me know!
Are you sending a :current_password anywhere in your params? (even if it is blank?) Normally devise wants you to use #update_with_password when requiring a password, so I'm not sure why you are getting this with :update_attributes.

devise rails adding user_id to another model

I want to add the current_user.id from devise to another model...
question model:
class Question < ActiveRecord::Base
belongs_to :user
attr_accessible :content
validates :content, :presence => true
end
user model:
class User < ActiveRecord::Base
has_many :questions
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
my question migration:
class CreateQuestions < ActiveRecord::Migration
def change
create_table :questions do |t|
t.string :content
t.date :deadline
t.integer :user_id
t.timestamps
end
end
end
In my questions controller:
def create
params[:question][:user_id]=current_user.id
#question = Question.new(params[:question])
if #question.save
redirect_to questions_path, :notice => "Successfully created question."
else
setup_questions
render :index
end
end
When i save the question the current_user.id won't be recorded in my database?
Try this instead:
def create
#question = Question.new(params[:question])
#question.user_id = current_user.id
if #question.save
redirect_to questions_path, :notice => "Successfully created question."
else
setup_questions
render :index
end
end