I have created an app with simple login authentication, it is actually a twitter clone. The user logs in and access the pages, etc.
But when the user posts something from there profile. It gives an error
NoMethodError in RibbitsController#create
undefined method `id=' for nil:NilClass
The error is around line 5:
class RibbitsController < ApplicationController
def create
#ribbit = Ribbit.create(user_ribbits)
#ribbit.userid = current_user.id
if #ribbit.save
redirect_to current_user
else
flash[:error] = "Problem!"
redirect_to current_user
end
end
private
def user_ribbits
params.require(:ribbit).permit(:content, :userid)
end
end
The request given to app:
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"dwVmjDNO4GOowphGFgChMDBxBfvka+M/xSUHvJMECzwxtv4NF6OuWtiaX74NLz91OwQJ9T9+wm7yMiPQ0BLpGA==",
"ribbit"=>{"content"=>"hi. test.\r\n"},
"commit"=>"Ribbit!"}
The sessions controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:userid] = user.id
redirect_to rooturl, notice: "Logged in!"
else
flash[:error] = "Wrong Username or Password."
redirect_to root_url
end
end
def destroy
session[:userid] = nil
redirect_to root_url, notice: "Logged out."
end
end
The users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to #user, notice: "Thank you for signing up!"
else
render 'new'
end
end
def show
#user = User.find(params[:id])
#ribbit = Ribbit.new
end
private
def user_params
params.require(:user).permit(:name, :username, :email, :password, :password_confirmation, :avatar_url)
end
end
And the application controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
I would really appreciate it if you guys would help!
Thanks.
You're trying to assign current_user.idto #ribbit.userid without ensuring that current_user is set. 'current_user' would be set only if a user has been previously saved before.
Therefore, you need either to make sure that an authenticated user is trying to create a Ribbit, or if you consider the userid as a non mandatory field, you can simply change your line 5 by:
#ribbit.userid = current_user.id unless current_user.blank?
If you only want authenticated user to create Ribbits, then consider using a gem to handle authentication such as Devise. You could then use before_filter :authenticate_user! in your controller to make sure users are properly authenticated.
Related
I have some code here that is supposed to create a session upon login, and create "#current_user". However, neither of these things are working, and after 2 days of speculating, I can't figure out why.
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to login_path
flash[:success] = "Account created. You may now log in"
else
redirect_to '/signup'
flash[:warning] = "Something went wrong. Try again."
end
end
private
def user_params
params.require(:user).permit(:username, :jabber_id, :password)
end
end
Sessions controller:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:name])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
session[:session_id] = nil
redirect_to login_path
end
end
Application controller:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
I am having a rather difficult problem i want to update the user profile only if they submit the current password.I am not using devise.And another post here at stack overflow didn't really help me.
This is my User controller code:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
#user_posts = #user.posts if #user
if #user
if #user_posts
render 'show.html'
else
render 'show.html'
end
else
render file: 'public/404.html', status: 404, formats: [:html]
end
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to root_path
flash[:notice] = "Successfully Signed up :-)"
else
redirect_to signup_path
flash[:notice] = "You didn't sign up successfully :-("
end
end
def edit
#user = User.find(params[:id])
if current_user.id = #user.id
render 'edit'
else
redirect_to #user
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:notice] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
:password == :password_confirmation
private
def user_params
params.require(:user).permit(:user_name, :email, :password, :password_confirmation)
end
end
And this is my user.rb:
class User
has_secure_password
has_many :posts
has_many :comments
def admin?
self.role == 'admin'
end
def moderator?
self.role == 'moderator'
end
end
Please help because I have been working with this for a long time now. And the other solution about this topic here at stack overflow didn't work.
One way is to use virtual attributes
1. The User model
class User < ActiveRecord::Base
attr_accessor :current_password
end
2. The form
add the current_password attribute to the form as a text_field input
3. The UsersController
def update
#user = User.find params[:id]
if #user.authenticate(update_params[:current_password])
# update the user
# maybe check if the data are valid
#user.update(update_params)
else
flash[:warning] = "Please provide your password"
#user.errors.add :current_password, "invalid"
render :edit
end
end
def update_params
params.require(:user).permit(:current_password, :email)
end
First, you have a problem in your edit action:
current_user.id = #user.id
That assigns #user.id to current_user.id - you wanted == to test that it's the correct User. You should put a similar check on update, and probably extract it into a before_action so you can easily apply it anywhere you want to.
To check that the password is present, add it to your form like any other field and then get it out of params to verify it. That would look something like this:
class UsersController < ApplicationController
def update
encrypted = encrypt(params[:password]) # Using whatever your mechanism is
if encrypted == #user.encrypted_password
# Update the user
else
flash[:notice] = 'Password is required to update user information.'
redirect_to edit_user(path(#user))
end
end
end
The error is coming in the create method user mailer section.
I am trying to resolve it, but nothing happens.
How can it be resolved? I come when I apply the validations.
The error is: Expected a URI like gid://app/Person/1234: #<URI::GID gid://email>
My mailer controller:
class UserMailer < ApplicationMailer
def welcome_email(user)
#user = user
#url = 'http:3000//example.com/login#u'
mail(to: #user.email, subject: 'Welcome to My Awesome Site')
end
end
My user controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
#user.save
UserMailer.welcome_email(#user).deliver_later[here the error come about the invalid url]
render 'token'
end
def verify
#user = User.authenticate(params[:auth_token])
if #user
redirect_to edit_user_path(#user)
else
flash.now.alert = "Invalid email or password"
render 'token', :alert =>"Invalid email or password"
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to new_login_path
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :dob, :email,
:password, :confirm_password, :auth_token)
end
end
You are trying to pass the Mailer an unpersisted object, ie. an object that was not saved to the database.
From your code, that means that the previous #user.save statement failed probably due to a validation error. In that case, you don't want to send the email anyway.
Change your create action like this:
def create
#user = User.new(user_params)
if #user.save
UserMailer.welcome_email(#user).deliver_later
render 'token'
else
flash[:error] = 'User was not saved'
render 'new'
end
end
I am new to programming and getting the following errors while trying to get through the 9th chapter of Rails Tutorial. I checked the code several times but still didn’t understand why my local variable or method isn’t being defined. Every time I rewrite the code I get similar errors: undefined local variable or method ‘current_user’.
Error:
ERROR["test_layout_links", SiteLayoutTest, 0.888518]
test_layout_links#SiteLayoutTest (0.89s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `current_user' for #<#<Class:0x007fcd97c44cf0>:0x007fcd97c4c4a0>
app/helpers/sessions_helper.rb:22:in `logged_in?'
app/views/layouts/_header.html.erb:8:in `_app_views_layouts__header_html_erb__1982327839123609485_70260496954760'
app/views/layouts/application.html.erb:12:in `_app_views_layouts_application_html_erb___2753884707929057206_70260450931560'
test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'
app/helpers/sessions_helper.rb:22:in `logged_in?'
app/views/layouts/_header.html.erb:8:in `_app_views_layouts__header_html_erb__1982327839123609485_70260496954760'
app/views/layouts/application.html.erb:12:in `_app_views_layouts_application_html_erb___2753884707929057206_70260450931560'
test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'
sessions_controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user
else
flash.now[:danger] = 'Invalid email/password combination' #Not quite right!
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
users_controller
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
sessions_helper
module SessionsHelper
#logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
#Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
#Returns the user corresponding to the remember token cookie.
def current_user?(user)
user == current_user
end
#returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
#Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
#logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
# Redirects to stored location (or to the default).
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
sessions_helper_test
require 'test_helper'
class SessionsHelperTest < ActionView::TestCase
def setup
#user = users(:michael)
remember(#user)
end
test "current_user returns right user when session is nil" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
I think you may be missing the current_user method. It's defined here.
Though the name is similar, current_user is a completely different method to current_user?. The question mark is a convention that typically means the method will return either true or false.
You're missing a current_user method in your sessions_helper.rb. Check back in Chapter 8.57
I am trying to block all default methods except create and update in my users controller using declerative_authorization. But at the time I add filter_resource_access or filter_access_to into my usersController i always get "Couldn't find User without an ID". Anyone care to explain why this could be happening?
class UsersController < ApplicationController
filter_resource_access
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Account registered!"
redirect_to account_url
else
render :action => :new
end
end
def show
#user = #current_user
end
def edit
#user = #current_user
end
def update
#user = #current_user # makes our views "cleaner" and more consistent
if #user.update_attributes(params[:user])
flash[:notice] = "Account updated!"
redirect_to account_url
else
render :action => :edit
end
end
end
You should set the #user variable before the filter_access_to call with a before_filter as declarative_authorization tries to access #user when you call filter_access_to.
before_filter :set_user
filter_access_to :all
...
protected
def set_user
#user = #current_user
end
Maybe you are setting the attribute_check parameter to true in your filter_access_to call? I have a similar controller and I don't really need the before_filter.
Another thing that might be causing it is a using_access_control call in your User model.