Currently, I'm receiving the following error:
NoMethodError in EventsController#create
undefined method `events' for nil:NilClass
Here are the following files...
EventsController. I've omitted some of the methods. Including Events#new
class EventsController < ApplicationController
include SessionsHelper
def create
#event = current_user.events.build(event_params)
if #event.save
flash[:success] = "You created an event"
redirect_to events_path
else
redirect_to new_event_path
end
end
private
def event_params
params.require(:event).permit(:description)
end
end
The SessionsHelper holds current_user...I've posted the whole file here just in case.
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attributes(remember_token: User.hash(remember_token))
self.current_user = user
end
def current_user
remember_token = User.hash(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user=(user)
#current_user = user
end
def sign_out
current_user.update_attributes(remember_token:
User.hash(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
def signed_in?
!current_user.nil?
end
end
And, finally, here is the Events#new. This is the view that calls the Events#create action:
<h1>Events#new</h1>
<!-- url: will send all form data to the action specified -->
<%= form_for(:event, url: {action: "create"}) do |f| %>
<%= f.label "Description" %>
<%= f.text_area :description, value: "Write here" %><br>
<%= f.submit "Create event" %>
<% end %>
Nevermind, all that's needed is to update the server. So close the server and type rails s.
Related
When I'm trying to login I'm getting:
undefined method `admin' for nil:NilClass
which is called from the layouts/_head.html.erb partial
_head.html.erb:
<% if session[:user_id] %>
<% if #current_user.admin %>
<%= button_to 'Swap to user', to_user_path(User.find_by(id: session[:user_id]).id), method: :put,
class: 'btn btn-warning' %>
<% else %>
<%= button_to 'Swap to admin', to_admin_path(User.find_by(id: session[:user_id]).id), method: :put,
class: 'btn btn-warning' %>
<% end %>
<% end %>
As you can see, session[:user_id] exists. Here is application_controller.rb:
class ApplicationController < ActionController::Base
before_action :set_user
protect_from_forgery with: :exception
def set_user
if session[:user_id]
#current_user = User.find_by(session[:user_id])
end
end
end
Also the login button works through Ajax. So why am I getting #current_user as nil, if it's defines before_action in the application controller? (Remember: session[:user_id] != nil)
Your use of find_by is incorrect. It should be:
#current_user = User.find_by(:id => session[:user_id])
So the solve is to define #current_user in create method,like
def create
user = User.find_by(name: params[:name])
respond_to do |format|
if user and user.authenticate(params[:password])
session[:user_id] = user.id
#current_user = user
format.js { }
else
format.js {flash.now[:notice] = 'Wrong pass/name'}
end
end
end
guesss its not absolute right,but one of possible method
When my app fails to log in due to incorrect email / password combo, it erases the entered fields from the form.
I'd like to keep the entered email while clearing the password field
sessions_controller.rb
def create
#! Do this using email index
user = User.find_by(email: params[:session][:email].downcase)
correct_password = #user.authenticate(params[:session][:password]) unless user.nil?
if user && correct_password
log_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination.'
render 'new'
end
end
def new
redirect_to user_path(current_user) if logged_in?
#user ||= User.new
end
For creating new users or records in the database, I know the behavior i want is achieved by using the .save method in the if condition, but Logging in iwith sessions is a different story, since you're not creating any new record, nor is there a sessions table.
sessions/new.html.erb
<%= form_for(:session, url: sessions_path) do |s| %>
<p>
<%= s.label :email %>:
<%= s.text_field :email %>
</p>
<p>
<%= s.label :password %>:
<%= s.password_field :password %>
</p>
<p>
<%= s.submit "Log In" %>
</p>
<%= link_to 'Create Account', signup_path %>
sessions_helper.rb
module SessionsHelper
def log_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
def log_in(the_user)
# Create new token.
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
# Update_attribute bypasses validations.
# Bypassing validations is necessary here a required password is absent in the inputs
the_user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = the_user
end
def logged_in?
!current_user.nil?
end
def current_user=(the_user)
#current_user = the_user
end
def current_user
# Local remember_token variable encrypts token value stored in cookie.
remember_token = User.encrypt(cookies[:remember_token])
# Find user whose remember_token attribute value matches the encrypted result of the token stored in the cookie.
# Using ||= handles login as well as navigating pages during the session.
# Doesn't hit database if value is already set - checks value before quering. Good!
# ||= here uses short-circuit evaluation.
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user? (the_user)
the_user == current_user
end
def store_location
session[:return_to] = request.url if request.get?
end
def redirect_back_or(page)
redirect_to(session[:return_to] || page)
session.delete(:return_to)
end
end
You'll need to use an instance variable in your form_for call:
<%= form_for #session, url: sessions_path do |f| %>
//your fields
<% end %>
You'll have to set #session in your controller like this:
#app/controllers/sessions_controller.rb
def new
#session = Session.new # or however it needs to work
end
Instance
The reason your form isn't re-populating is that you don't have any data to re-populate with. By using an instance variable, the form data is held within that (allowing it to be called again)
You'll probably benefit from reading this: Difference between :model and #model in form_for?
Update
I still stand by the idea you need to create an instance of the #session object
I think I would create a session model to handle the #session variable:
#app/models/session.rb
class Session
include SessionsHelper
def initialize(session)
#session = session
end
def new
#session ||= []
end
#replace log_in method
def create
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
#user.update_attribute(:remember_token, User.encrypt(remember_token))
current_user = #user
end
#replace log_out method
def destroy
token = User.encrypt(User.new_remember_token)
current_user.update_attribute(:remember_token, token)
cookies.delete(:remember_token)
current_user = nil
end
end
#app/controllers/sessions_controller.rb
def create
#user = User.find_by(email: params[:session][:email].downcase)
correct_password = #user.authenticate(params[:session][:password]) unless #user.nil?
if #user && correct_password
Session.create(#user)
redirect_to #user
else
flash.now[:error] = 'Invalid email/password combination.'
render 'new'
end
end
def new
redirect_to user_path(current_user) if logged_in?
#session ||= Session.new
end
I am trying to implement the follow actions from M. Hartl's tutorial in my rails composer, devise app.
But for some reason i get this error
undefined method `current_user?' for
when using this code
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
Any idea why?
Thanks
Devise gives you the current_user helper by default. However, it doesn't give you current_user? boolean method. You need to define this method yourself in application_helper.rb:
def current_user?(user)
user == current_user
end
Now you have current_helper? defined you can pass in your #user instance variable
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
Thats all you have to do. You don't have to touch your ApplicationController or SessionsHelper in any way. You are simply using current_user which Devise gives you in order to define current_user?(user). This way is much easier to implement. Hope this helps
Update
Hopefully you should have the following setup:
Your ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
# Force signout to prevent CSRF attacks
def handle_unverified_request
sign_out
super
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not Autherized" if current_user.nil?
end
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable
end
end
You should also have a sessions_helper
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def current_user?(user)
user == current_user
end
#CHECK THE ABOVE LINE!
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
Then you can do in your view the following:
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
I'm having issues trying to figure out why i'm getting undefined methodcurrent_user?'`
In my Application controller:
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
# Force signout to prevent CSRF attacks
def handle_unverified_request
sign_out
super
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not Autherized" if current_user.nil?
end
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable
end
end
In my session helper:
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
I'm still new to rails I'm following some tutorials, but I'm trying to figure out why I'm getting undefined method for current_user?
This is where my error is occurring- users view folder:
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
You have not defined a current_user? method anywhere, and you are calling current_user?(#user).
Perhaps, you need to call signed_in? instead of current_user?, or define what you mean by current_user?(#user)
You have not defined current_user? method.
there is a difference between current_user and current_user? current_user? always return a boolean response.
but you can try with current_user(#user)? or unless current_user(#user).nil?
Try this:
def current_user?(user)
user == current_user
end
I am trying to create an admin instance through my admins controller create action, but I keep getting an error that says:
ActiveRecord::RecordNotFound in AdminsController#show: Couldn't find User with id=4
The trace indicates that it is attempting to use the sessions helper (for user) instead of the appropriate adminsessions helper.
app/helpers/sessions_helper.rb:20:in `current_user'
app/helpers/sessions_helper.rb:12:in `signed_in?'
app/views/layouts/application.html.erb:13:in
app_views_layouts_application_html_erb__1013605049_93953830
I can log in correctly and the admin is created. I just think the problem has to do with the redirect_to #admin in my admins controller, though I'm not sure.
How do I set it up so that my admins controller uses the adminsessions helper instead of the sessions helper? Any help would be greatly appreciated.
adminsessions_controller.rb
class AdminsessionsController < ApplicationController
def new
#title = "Log in"
end
def show
#title = "Admin session"
end
def create
admin = Admin.authenticate(params[:adminsession][:email],
params[:adminsession][:password])
if admin.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Log in"
render 'new'
else
sign_in admin
redirect_to admin
end
end
def destroy
sign_out
redirect_to root_path
end
end
admins_controller.rb
class AdminsController < ApplicationController
def index
#user = User.all
end
def show
#admin = Admin.find(params[:id])
end
def new
#admin = Admin.new
#title = "New admin"
end
def create
#admin = Admin.new(params[:admin])
if #admin.save
sign_in #admin
flash[:success] = "Welcome admin!"
redirect_to #admin
else
#title = "New admin"
render 'new'
end
end
end
new.html.erb (form where I create new user)
<div id="signupform_new">
<%= form_for(#admin) do |f| %>
<div class="field">
<%= f.label :username %>
<%= f.text_field :name, :class => "round" %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email, :class => "round" %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password, :class => "round" %>
</div>
<div class="field">
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, :class => "round" %>
</div>
<div class="action">
<%= button_tag "", :class => "acctSubmit" %>
</div>
<% end %>
</div>
sessions_helper.rb
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def current_user?(user)
user == current_user
end
def authenticate
deny_access unless signed_in?
end
def sign_out
session[:user_id] = nil
self.current_user = nil
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end
end
adminsessions_helper.rb
module AdminsessionsHelper
def sign_in(admin)
adminsession[:admin_id] = admin.id
self.current_admin = admin
end
def signed_in?
!current_admin.nil?
end
def current_admin=(admin)
#current_admin = admin
end
def current_admin
#current_admin ||= Admin.find(adminsession[:admin_id]) if adminsession[:admin_id]
end
def current_admin?(admin)
admin == current_admin
end
def authenticate
deny_access unless signed_in?
end
def sign_out
adminsession[:admin_id] = nil
self.current_admin = nil
end
def redirect_back_or(default)
redirect_to(adminsession[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
adminsession[:return_to] = request.fullpath
end
def clear_return_to
adminsession[:return_to] = nil
end
end
All helpers are (by default) mixed in and available in all controllers. Looks like the methods you are using should be protected or private members of your controllers instead. You can make them helper methods to be available in your views, i.e. helper_method :signed_in?.
Personally I never liked the lack of namespacing with helpers anyway. I like the presenter pattern much better (see RailsCasts Pro].