Remember Me authenticity token not working rails - ruby-on-rails

I followed RailsCast 274 to add Remember Me & Reset Password functionality to my app.
I have no problem locally, the app seems to run and authenticate users fine. The problem is when I deploy the production version to Heroku I get the error:
undefined method `find_by_auth_token!' for #<Class:0x007f35fbe37a78>
current_user is defined in my ApplicationController as:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
before_action :require_user
def current_user
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
def require_user
if current_user.nil?
redirect_to new_session_path
end
end
end
This is my SessionsController:
class SessionsController < ApplicationController
layout false
skip_before_action :require_user
def create
user = User.find_by(email: params["email"])
if user && user.authenticate(params["password"])
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
redirect_to root_path, notice: "Login successful!"
else
redirect_to new_session_path, alert: "Email or password incorrect"
end
end
def destroy
cookies.delete(:auth_token)
redirect_to new_session_path, notice: "Logout successful!"
end
end
And this is the User model:
class User < ActiveRecord::Base
has_secure_password
has_one :patient, :dependent => :destroy
has_one :clinician, :dependent => :destroy
accepts_nested_attributes_for :patient, :allow_destroy => true
accepts_nested_attributes_for :clinician, :allow_destroy => true
validates :password,
:length => { :minimum => 6 }, :if => :password_digest_changed?
validates_presence_of :password, on: :create
before_validation(on: :update) do
# only want confirmation validation to run if user enters password
self.password_confirmation = nil unless self.password.present?
end
# validates_uniqueness_of :email
before_create { generate_token(:auth_token) }
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
And in my schema.rb:
create_table "users", force: true do |t|
t.string "timezone"
t.boolean "terms_agreement", default: false
t.string "email"
t.string "password_digest"
t.string "auth_token"
t.string "password_reset_token"
t.datetime "password_reset_sent_at"
end
Why is this working in development but not production?
Ruby 2.2.1 & Rails 4.1.8
development:
PostgresSQL 9.4.1

It's an old tutorial, rails 4 has different dynamic matchers
Rails 3
User.find_by_auth_token!(cookies[:auth_token])
Rails 4
User.find_by!(auth_token: cookies[:auth_token])

Related

Rails says that "role", a property I made doesn't exist

I clearly made the role for users (as you can see down below) but it says it doesn't exist. Help please? By the way, you can see how I'm hardcoding myself.
app/controllers/application-controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def require_user
redirect_to '/login' unless current_user
end
def require_admin
redirect_to '/' unless current_user.admin
end
end
User.create(first_name: "Johnny", last_name: "Appleseed", email: "j.appleseed#example", password: "MY AWESOME PASSWORD THAT NOBODY KNOWS", role: "admin")
db/migrate/20160109170743_create_users:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.string :role, :default => "reader"
t.timestamps null: false
end
end
end
app/controllers/users-controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to '/'
else
redirect_to '/signup'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :role)
end
end
Without knowing the specific error message, I can only speculate that your error is here:
def require_admin
redirect_to '/' unless current_user.admin
end
Regardless of the attributes you have in your model / db, you'll only get instance methods you've defined. You don't have admin in your User object, thus making current_user.admin invalid.
You'd need to use the following:
#app/models/user.rb
class User < ActiveRecord::Base
def admin?
self.role == "admin"
end
end
current_user.admin? #-> true / false
Whilst the question mark isn't required, it denotes the evaluation of an object's properties (true / false).
As an aside, you may want to look at adding an enum to your User model:
#app/models/user.rb
class User < ActiveRecord::Base
enum role: [:reader, :admin]
end
This will give you a series of instance & class methods to better help your logic:
#user = User.find params[:id]
if #user.admin?
...
#admins = User.admin
#-> collection of "admin" users
To do it, you'll need to change your role column from string to integer
I would suggest that you use boolean for the column role.
User.rb
def admin?
self.role == true
end
so you can do
redirect_to '/' unless current_user.admin?

undefined method `get_access_token' while implementing koala gem in rails app

I want to implement koala gem in rails app
But i am getting an error "undefined method get_access_token'
My facebook controller code is
class FacebookController < ApplicationController
before_filter :authenticate_user!
def index
unless current_user.facebook_oauth_setting
#oauth = Koala::Facebook::OAuth.new("app-id", "secret", "http://#{request.host}:#{request.port}/callback")
session["oauth_obj"] = #oauth
redirect_to #oauth.url_for_oauth_code
else
redirect_to "/facebook_profile"
end
end
def callback
unless current_user.facebook_oauth_setting
#oauth = session["oauth_obj"]
Rails.logger.info("**************#{#oauth}***************")
Rails.logger.info("**********#{params[:code]}*************")
FacebookOauthSetting.create({:access_token => #oauth.get_access_token(params[:code]), :user_id => current_user.id})
redirect_to "/facebook_profile"
else
redirect_to "/"
end
end
def facebook_profile
if current_user.facebook_oauth_setting
#graph = Koala::Facebook::API.new(current_user.facebook_oauth_setting.access_token)
#profile = #graph.get_object("me")
#picture = #graph.get_picture("me")
#feed = #graph.get_connections("me","feed")
#friends = #graph.get_connections("me", "friends")
else
redirect_to "/"
end
end
end
My model to store access token is
class TwitterOauthSetting < ActiveRecord::Base
belongs_to :user
end
My migration to store access_token is
class CreateFacebookOauthSettings < ActiveRecord::Migration
def change
create_table :facebook_oauth_settings do |t|
t.string :access_token
t.integer :user_id
t.timestamps null: false
end
end
end
Create the #oauth object inside the callback method rather than bringing it from the session. So do this:
#oauth = Koala::Facebook::OAuth.new("app-id", "secret", "http://#{request.host}:#{request.port}/callback")
FacebookOauthSetting.create(:access_token => #oauth.get_access_token(params[:code]), :user_id => current_user.id)
It should solve your problem.
type of object should be Koala::Facebook

Rails not saving model field

I was wondering why my rails is not saving my encrypted_password field.
Here is my UserController
class UserController < ApplicationController
require 'bcrypt'
before_filter :save_login_state, :only => [:new, :create]
def new
new_user = User.new(user_params)
new_user.numRatings = 0
if new_user.save
flash[:notice] = "You signed up successfully"
flash[:color]= "valid"
else
flash[:notice] = "Form is invalid"
flash[:color]= "invalid"
end
redirect_to(:controller => 'sessions', :action => 'login')
end
def create
end
def update
end
def view
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
Here is my User model
class User < ActiveRecord::Base
require 'BCrypt'
attr_accessor :password, :encrypted_password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :name, :presence => true
validates :password, :confirmation => true, :presence => true, :on => :create
before_save :encrypt_password
after_save :clear_password
def encrypt_password
if password.present?
self.salt = BCrypt::Engine.generate_salt
self.encrypted_password = BCrypt::Engine.hash_secret(password, salt)
end
end
def clear_password
self.password = nil
end
def self.authenticate(username_or_email="", login_password="")
if EMAIL_REGEX.match(username_or_email)
user = User.find_by_email(username_or_email)
end
if user && user.match_password(login_password)
return user
else
return false
end
end
def match_password(login_password="")
encrypted_password == BCrypt::Engine.hash_secret(login_password, salt)
end
end
In addition, I use this function to save it
def login_attempt
authorized_user = User.authenticate(params["user"]["email"],params["user"]["password"])
if authorized_user
session[:user_id] = authorized_user.id
flash[:notice] = "Wow Welcome again, you logged in as #{authorized_user.username}"
redirect_to(:action => 'home')
else
flash[:notice] = "Invalid Username or Password"
flash[:color]= "invalid"
render "login"
end
end
One thing that I suspect that I created my first migration
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :password
t.string :name
t.float :rating
t.integer :numRatings
t.timestamps
end
end
end
However, I changed the :password field to :encrypted_password and it's reflected in a the table. I've been stuck on this for 2 hours. I was wondering if anything sticks out. Thanks.
The logs say that the data is being injected minus the encrypted password
INSERT INTO "users" ("created_at", "email", "name", "numRatings", "salt", "updated_at") VALUES (?, ?, ?, ?, ?, ?) [["created_at", "2014-08-05 06:22:41.335373"], ["email", "w#w.com"], ["name", "w"], ["numRatings", 0], ["salt", "$2a$10$pagmnNzT4FWEBmaPmiLX1u"], ["updated_at", "2014-08-05 06:22:41.335373"]]
Your attr_accessor :encrypted_password sticks out - this is overwriting the Rails-generated attribute getter/setter with one that will simply set an instance variable called #encrypted_password in your model instance.
You mentioned you changed the migration :password field to :encrypted_password field, but are you sure you reinitialized the models? I.e. correctly migrated the changes? Finally, if you did change the migration, there is no need for an attr_accessor of encrypted_password. Having both of them may cause shadowing and be the problem.

How to make Users automatically Follow Admin User on Sign Up

Currently I allow users to follow one another on my rails app (similar to twitter).
I would love if New Users that sign up to the site Automatically follow Admin User.
Similar to how MySpace use to automatically make Tom your first friend
Below is the code I use to create new users and allow users to follow one another.(i know this is a very broad question but .....)
(Can someone please point me in the right direction onto how I can get this started. Would I need to create a method....in my models or add code to the controller?)
New to Rails Please help)... :)
USER CONTROLLER
class UsersController < ApplicationController
before_filter :admin_user, only: [:destroy]
respond_to :html, :js
def new
#user = RegularUser.new
end
def index
#users = User.paginate(page: params[:page], :per_page => 100).search(params[:search])
end
def destroy
User.find_by_username(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_url
end
def create
#user = RegularUser.new(params[:regular_user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
UserMailer.welcome_user(#user).deliver
sign_in #user
flash[:success] = "Welcome to the ClickOnComics!"
redirect_to (publishers_path)
else
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def follow_admins
admins = User.find_by_admin(true)
admins.each do |admin|
self.follow!(admin)
end
end
class RelationshipsController < ApplicationController
before_filter :current_user
respond_to :html, :js
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_with #user
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_with #user
end
end
MODELS
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :relationships, foreign_key: "follower_id", dependent: :destroy
has_many :followed_users, through: :relationships, source: :followed
has_many :reverse_relationships, foreign_key: "followed_id",
class_name: "Relationship",
dependent: :destroy
has_many :followers, through: :reverse_relationships, source: :follower
after_create :follow_admins
def follow_admins
admins = User.find_all_by_admin(true)
admins.each do |admin|
self.follow!(admin)
end
end
def following?(other_user)
relationships.find_by_followed_id(other_user.id)
end
def follow!(other_user)
relationships.create!(followed_id: other_user.id)
end
def unfollow!(other_user)
relationships.find_by_followed_id(other_user.id).destroy
end
end
I used this tutorial to help me establish privileged administrative users with a boolean admin attribute in the User model
http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-users#sec-administrative_users
SCHEMA
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.string "role"
t.string "username"
t.timestamp "created_at", :null => false
t.timestamp "updated_at", :null => false
t.boolean "admin", :default => false
t.string "password_reset_token"
t.timestamp "password_reset_sent_at"
end
Would I need to create a Method that defines user_admin?
In user.rb add a after_create filter
after_create :follow_admin!
def follow_admin!
relationships.create!(followed_id: admin_user.id)
end
In create action before sign_in add
#user.follow! admin_user
you need to fetch admin user first somehow.
Good idea would be to make follow!, following? and unfollow! methods to accept either id or object as in
def follow!(user_or_id)
id = (user_or_id.is_a?(User) ? user_or_id.id : user_or_id)
relationships.create!(followed_id: id)
end

Rails: Undefined method error on authentication

I am trying to create an authentication system on RAILS with find_by_user_name_and_password()
I have the following problem:
undefined method `find_by_user_name_and_password' for #<Class:0x007fae373d5698>
Rails.root: /ror/blog/Blog`
Application Trace | Framework Trace | Full Trace
app/controllers/sessions_controller.rb:7:in `create'
Here is my code from sessions_controller
class SessionsController < ApplicationController
skip_before_filter :authorizes
def new
end
def create
user = User.find_by_user_name_and_password(params[:name], params[:password])
if user
session[:user_id] = user.id
redirect_to admin_url
else
redirect_to login_url, alert: "Bad datas"
end
end
def destroy
session[:user_id] = nil
rederect_to blog_url, notice: "End seans"
end
end
model defenition:
class User < ActiveRecord::Base
attr_accessible :name, :password_digest, :password_confirmation
validates :name, presence: true, uniqueness: true
#validates_confirmation_of :password
has_secure_password
end
Migrate
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :password_digest
t.timestamps
end
end
end
Looking at your model that you just posted, I see you don't have a password field... so no find_by_whatever_and_password.
You need to use
user = User.find_by_name(params[:user][:name])
if user && user.authenticate(params[:user][:password])
# etc.

Resources