My sessions_controller is as follows:
class SessionsController < ApplicationController
require 'omniauth-facebook'
require 'omniauth'
def create
#user = User.find_or_create_from_auth_hash(auth_hash)
self.current_user = #user
redirect_to '/'
end
protected
def auth_hash
request.env['omniauth.auth']
end
end
So... it's THERE isn't it?
Here's my users.rb file:
class User < ActiveRecord::Base
acts_as_voter
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
has_many :posts
has_many :tasks
end
And my routes file:
LiquidAdmin::Application.routes.draw do
devise_for :users
get '/auth/:provider/callback', to: 'sessions#create'
resource :sessions, :only => :create
get "home/bandwall"
get "home/index"
root :to => "home#index"
So where's the problem? "auth_hash" is clearly defined... The SessionsController is loading... so why is it complaining about no method for find_or_create_from_auth_hash?
In Rails 3.2, the method you'll want to use is called first_or_create:
User.where(auth_hash: auth_hash).first_or_create
According to the Rails 3.2 release notes:
Add first_or_create, first_or_create!, first_or_initialize methods to
Active Record. This is a better approach over the old
find_or_create_by dynamic methods because it's clearer which arguments
are used to find the record and which are used to create it.
Given this, the following is made possible through the query:
User.where(auth_hash: auth_hash).first_or_create(foo: 'bar') # Assuming no other User entries exist
#=> #<User id: 1, auth_hash: "your_auth_hash", foo: "bar">
User.where(auth_hash: auth_hash).first_or_create(foo: 'baz')
#=> #<User id: 1, auth_hash: "your_auth_hash", foo: "bar">
Given that this question is based on OmniAuth, I think a better answer would be:
#user = User.where(auth_hash).first_or_create
or if in Rails version greater than 4.1.14
#user = User.where(uid: auth_hash[:uid], provider: auth_hash[:provider]).first_or_create
auth_hash is not a field in the User model, but rather a Hash of fields that could be on the User model.
Related
Started to learn and develop rails - while it is pretty straight forward I got stuck changing the implementation of the /users/edit view and endpoint in the default configuration of devise.
My approach is pretty simple, all routes and logic for authentication, password resetting etc. get handled by devise and it's routes. My problem is that I want users to change their passwords and email via my custom /settings route and view. For me /users/edit just doesn't make sense and I want to remove it from the accessible routes and ideally use its logic for my custom route.
routes.rb
Rails.application.routes.draw do
devise_for :users
# Defines the root path route ("/")
root "home#index"
# SETTINGS
get "settings/profile" => "settings#profile"
get "settings/account" => "settings#account"
get "settings/billing" => "settings#billing"
get "settings/notifications" => "settings#notifications"
end
user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :lockable,
:trackable, :omniauthable
def remember_me
true
end
end
settings_controller.rb
class SettingsController < ApplicationController
before_action :authenticate_user!
def profile
end
def account
end
def billing
end
def notifications
end
end
I am trying to override my devise registration controller, with no luck.
I finally got the routes working, but now I'm getting an superclass mismatch for class error.
Heres my setup:
Registration Controller (app/controllers/users/registrations_controller.rb)
class RegistrationsController < Devise::RegistrationsController
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
params.require(:user).permit(:email, :password, profile_attributes: [:username])
end
def new
super
end
def create
end
def update
super
end
end
Routes
root 'welcome#index'
devise_for :users, :controllers => {:registrations => "users/registrations"}
Views
--edit.html.erb && new.html.erb exist in the folder (app/views/users/registrations)
User Model (just in case)
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile
accepts_nested_attributes_for :profile
def profile
super || build_profile
end
end
Any idea why this error is appearing?
Thanks!
Your controller is underneath the users directory but does not have a Users module (it is not in the Users namespace, you might say). Either change the controller to this:
module Users
class RegistrationsController < Devise::RegistrationsController
...
end
end
Or move your controller up a directory
app/controllers/registrations_controller.rb
Define your RegistrationsController as below
class Users::RegistrationsController < Devise::RegistrationsController
...
end
By defining the controller as suggested above, you don't need to define the module explicitly.
You get the error because you have placed the RegistrationsController inside users folder.
So, rails expects that RegistrationsController is a class belonging to Users module.
I'm new to rails and I tried to make simple authentication with anonymous user. I followed this tutorial and I have this error:
undefined method `find_or_initialize_by_token'
This is my AnonymousUser model:
class AnonymousUser < User
ACCESSIBLE_ATTRS = [:name, :email]
attr_accessible *ACCESSIBLE_ATTRS, :type, :token, as: :registrant
def register(params)
params = params.merge(type: 'User', token: nil)
self.update_attributes(params, as: :registrant)
end
end
This is my User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:rememberable, :registerable, :trackable, :timeoutable, :validatable,
:token_authenticatable
attr_accessible :email, :password, :password_confirmation, :remember_me
end
And the last one important is my ApplicationController which has this error:
class ApplicationController < ActionController::Base
protect_from_forgery
def authenticate_user!(*args)
current_user.present? || super(*args)
end
def current_user
super || AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
end
private
def anonymous_user_token
session[:user_token] ||= SecureRandom.hex(8)
end
end
Someone told me that if AnonymousUser user inherits from User then AnonymousUser have method called find_or_initialize_by_token, but i don't know how to fix it.
Provided you have latest rails installed, try to refactor:
# in ApplicationController#current_user
AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
to something like this:
AnonymousUser.safely_find(anonymous_user_token)
and push the find_or_initialize_by_token and save(validate: false) into the model.
I wrote the blog post you referenced, but today, I would use
AnonymousUser.where(anonymous_user_token: anonymous_user_token).first_or_initialize
Dynamic finders have been deprecated AFAIK.
However, #Saurabh Jain is absolutely correct in his suggestion to refactor that block into a nice little push-button class method on the AnonymousUser.
Something very strange happening with my devise setup.
I have a custom ConfirmationsController which I'm using for custom behaviour with devise.
My customer model:
class Customer
include Mongoid::Document
after_create :prepare_demo_app
devise :validatable,
:registerable,
:database_authenticatable,
:confirmable,
:trackable,
:rememberable,
:recoverable,
:mailchimp
## Confirmable
field :confirmation_token, :type => String
field :confirmed_at, :type => Time
field :confirmation_sent_at, :type => Time
My custom controller
class ConfirmationsController < Devise::ConfirmationsController
def create
puts "resource #{resource}"
puts "resource name #{resource_name}"
super
end
enter code here
My routes.rb
devise_for :customers,
:controllers => {:confirmations => "confirmations" },
:skip => [:sessions, :passwords], :format => false do
#... other gets and posts but nothing to do with confirmations
#...
end
When I hit this controller as per my routes file I enter an email. Click submit and get a null pointer for the resources. But not the resource name. Has anyone any ideas what I might be missing or why the customer would be coming through as null?
resource isn’t being set anywhere. In the default ConfirmationsController, Devise initialises resource like this (depending on what version you’re running):
self.resource = resource_class.send_confirmation_instructions(resource_params)
If you put super before your puts statements, resource should be set.
Hi everyone Im working in my app and I run into this error
NoMethodError in GasStationsController#new
undefined method `gas_stations' for #<Class:0x12cf77510>
Rails.root: /Users/Users/Documents/myapps/app1
Application Trace | Framework Trace | Full Trace
app/controllers/gas_stations_controller.rb:4:in `new'
I dont understand if my routes are ok. I put my routes.rb and my GasStationsController
Estaciones::Application.routes.draw do
root :to => "static_pages#home"
match '/contact', :to=>'static_pages#contact'
match '/about', :to=>'static_pages#about'
devise_for :users
resources :users do
resources :gas_stations
end
....
user_gas_stations GET /users/:user_id/gas_stations(.:format) gas_stations#index
POST /users/:user_id/gas_stations(.:format) gas_stations#create
new_user_gas_station GET /users/:user_id/gas_stations/new(.:format) gas_stations#new
edit_user_gas_station GET /users/:user_id/gas_stations/:id/edit(.:format) gas_stations#edit
user_gas_station GET /users/:user_id/gas_stations/:id(.:format) gas_stations#show
PUT /users/:user_id/gas_stations/:id(.:format) gas_stations#update
DELETE /users/:user_id/gas_stations/:id(.:format) gas_stations#destroy
as you see the method is there "gas_stations"
I only have this on my controller
class GasStationsController < ApplicationController
def new
#user = User.find(params[:user_id])
#gas_station = #user.gas_stations.build
end
end
User model
class User < 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 :name, :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
has_many :cars
validates_presence_of :email
end
As the error says, Rails has no idea what gas_stations are as it pertains to a user. You need to set that association:
class User ...
...
has_many :gas_stations
...