Empty argument - form for - ruby-on-rails

I want to implement a reset password functionality so I have followed this railscast, I receive the mail with the link to redirect to an edit password page but I get an error here.
View
<h1>Reset Password</h1>
<%= form_for #user, :url => password_reset_path(params[:id]) do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Update Password" %></div>
<% end %>
The error is :First argument in form cannot contain nil or be empty
I'm assuming that #user is empty, I'm new on RoR and I don't know why I get this error
Password Controller
class PasswordResetsController < ApplicationController
def new
render :layout => false
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to :connect, :notice => "An E-mail has been send"
end
def edit
render :layout => false
#user = User.find_by_password_reset_token!(params[:id])
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password ↵
reset has expired."
elsif #user.update_attributes(params[:user])
redirect_to root_url, :notice => "Password has been reset."
else
render :edit
end
end
end

Change your def edit to
def edit
#user = User.find_by_password_reset_token!(params[:id])
render :layout => false
end

you have to add
#user = User.new
to your new method.
you have also another error for your create method. there is no user creation.
class PasswordResetsController < ApplicationController
def new
#user = User.new
render :layout => false
end
def create
#user = User.new user_params
if #user.save
# your code to render success
else
# your code to render error
end
end
private
def user_params
params.require(:user).permit(:email) # add more
end
end

This is the answer to '#user.update_attributes(params[:user])' with forbidden attributes error.
Rails 4 has new feature known as strong parameters.
Change your password controller to:
class PasswordResetsController < ApplicationController
def new
render :layout => false
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to :connect, :notice => "An E-mail has been send"
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
render :layout => false
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password ↵
reset has expired."
elsif #user.update_attributes(user_params)
redirect_to root_url, :notice => "Password has been reset."
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :email_id, :password)
end
end

Related

Getting user phone number and sending a message in ruby on rails

I am working on a messaging app in ruby and i am currently encountering a blocker which i can not fix. I have been using tutorials for this and i think part of the reason i cannot find the solution is because of that. My app allows the users to log in and sign up,they can then add,view and edit contact. Finally the can send a message to different recipients. The problem is, i cannot get the recipients in the contacts and send them a message. I am only able to select my name as a user(which is not what its intended to do). I have attached the controllers used here:
contacts_controller
class ContactsController < ApplicationController
def index
#contacts = Contact.all
end
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
if #contact.save
flash[:success]= "new contact successfully added!"
redirect_to contacts_path
else
render 'new'
end
end
def edit
#contact = Contact.find(params[:id])
end
def update
#contact = Contact.find(params[:id])
permitted_columns = params.require(:contact).permit(:name, :company, :email, :phone)
#contact.update_attributes(permitted_columns)
redirect_to contacts_path
end
def destroy
#contact = Contact.find(params[:id])
#contact.destroy
redirect_to contacts_path
end
private
def contact_params
params.require(:contact).permit(:name, :company, :email, :phone)
end
end
messages_controller
class MessagesController < ApplicationController
def index
#messages = Recipient.where(:user_id => current_user.id).order('created_at DESC')
end
def new
#message = Message.new
#recipients = Contact.all
end
def create
#message = current_user.messages.build(message_params)
if #message.save
flash[:success]= "Message sent!"
redirect_to contacts_path
else
flash[:alert]= "sorry!message unsent"
render :new
end
end
private
def message_params
params.require(:message).permit(:body, :sender_id, user_tokens:[])
end
end
users_controller
class UsersController < ApplicationController
def index
end
def create
user = User.new(user_params)
if user.save
session[:user_id] = user.id
redirect_to '/contact'
else
flash[:register_errors] = user.errors.full_messages
redirect_to '/'
end
end
private
def user_params
params.require(:user).permit(:fname, :lname, :email, :password, :password_confirmation)
end
end
sessions_controller
class SessionsController < ApplicationController
def create
user = User.find_by(email:login_params[:email])
if user && user.authenticate(login_params[:password])
session[:user_id] = user.id
redirect_to '/contact'
else
flash[:login_errors] = ['invalid username or password']
redirect_to '/'
end
end
def destroy
session[:user_id] = nil
redirect_to '/', notice: 'Successfully logged out!'
end
private
def login_params
params.require(:login).permit(:email,:password)
end
end
The _recipient.html.erb is rendered by the new.html.erb. Here is the code:
<div class="container vertical-center">
<div id ="stream">
<%= form_for :message, url:messages_path do |f| %>
<%= f.text_area :body, id: "url", placeholder: "Message", class: "message_body" %>
<div id="stream-list" class="follow-list">
<ul>
<% #recipients.each do |contact| %>
<label for="user<%=contact.id%>" >
<li id="stream_item">
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]",user.id, #message.users.include?(user), id: "user#{user.id}" %>
</li>
</label>
<br>
<% end %>
</ul>
</div>
<div class="stream-footer">
<%= f.button :submit, class: "btn btn-success" %>
<% end %>
</div>
</div>
</div>
Here is the error when i try to write a message
It's not very clear why you use local variable user in your view template. I think it's just an error and contact variable is supposed to be used instead:
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]", contact.id, #message.users.include?(contact), id: "user#{contact.id}" %>
Also, a small HTML error: ul tag should contain li tags; other tags are not allowed as direct descendants. So I would also rewrite that list as:
<ul>
<% #recipients.each do |contact| %>
<li id="stream_item">
<label for="user<%=contact.id%>" >
<span class="list-group-item"><%= contact.name %></span><%= check_box_tag "message[user_tokens][]", contact.id, #message.users.include?(contact), id: "user#{contact.id}" %>
</label>
</li>
<br>
<% end %>
</ul>

Rails user login is nil

I have my rails app and when I try to login (I have created user called "test") I see this in the console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tlKwtMBNJ4LzJuJq13bUscAGpumdr+HVmUlGlfIudT9032DMXNxqa0d2VCxCvDZRDe1D6pFfaTafSRiL6tUvhw==", "session"=>{"login"=>"", "password"=>"[FILTERED]"}, "commit"=>"Log in"}
User Load (1.7ms) SELECT `users`.* FROM `users` WHERE `users`.`login` IS NULL LIMIT 1
I see that in the session parameters application can't get user login (and maybe password too). Below are my user and session controllers:
class UsersController < ApplicationController
before_action :require_admin
def new
#users = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
current_user = #user.id
redirect_to #user
else
redirect_to '/login'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :login)
end
end
Session controller:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_login(params[:login])
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to '/'
else
flash[:error] = 'err'
redirect_to '/login'
end
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
I have also tested the user creation and the record is in the database.
#update here is my view for the login form
<%= form_for(:session, url: login_path) do |f| %>
<div class="hidden-sm hidden-xs col-md-12 col-lg-12 ">
<%= f.text_field :login, :placeholder => "login" %>
<%= f.password_field :password, :placeholder => "password" %>
<%= f.submit "Log in", class: "btn-submit"%>
</div>
You have nested hash in your params(login param is under session key).
Try
def create
#user = User.find_by_login(params[:session][:login])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/'
else
flash[:error] = 'err'
redirect_to '/login'
end
end
Also, in your example login param is empty - i guess it's not being supplied from the form.
#update: using form tag
<%= form_tag login_path, method: :post do %>
<div class="hidden-sm hidden-xs col-md-12 col-lg-12 ">
<%= text_field_tag :login, :placeholder => "login" %>
<%= password_field_tag :password, :placeholder => "password" %>
<%= submit_tag "Log in", class: "btn-submit"%>
</div>
<% end %>
and for create method(since params are not nested anymore):
def create
#user = User.find_by_login(params[:login])
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to '/'
else
flash[:error] = 'err'
redirect_to '/login'
end
end

Unable to update password with Bcrypt

I've tried this many ways but it seems BCrypt is encrypting a users submitted password twice.
When a user signs up- Bcrypt works great, and I am able to sign in. But when I try and update their password in my password_resets_controller, I'm no longer able to log in. My database shows that the password is being updated and hashed, but I can't sign in.
I even removed the line #customer.save, yet my database is still showing that the password is being updated !
Is something being updated under the hood I'm not aware of? See relatd SO thread:
Updating password with BCrypt
In my Customer.rb
require 'bcrypt'
class Customer < ActiveRecord::Base
include BCrypt
def password
#password ||= Password.new(password_hash)
end
def password=(new_password)
#password = Password.create(new_password)
self.password_hash = #password
end
def self.authenticate(email, password)
#customer = Customer.find_by_email(email)
if #customer && #customer.password == password
return #customer
else
return nil
end
end
end
In my customer_controller, the create code that actually works
require 'bcrypt'
class CustomersController < ApplicationController
def create_customer_account_iphone
#customer_count = Customer.where(email: params[:email]).size rescue nil
if(#customer_count == 0 || #customer_count == nil ||)
#customer = Customer.new(first_name: params[:first_name], email: params[:email])
#customer.password = params[:password] //this calls my model methods
#customer.save //here I am saving
unless (!#customer.save)
respond_to do |format|
msg = {:status => "SUCCESS", :messages => "Customer created", :data => #customer.as_json}
format.json { render :json => msg } # don't do msg.to_json
end
else
respond_to do |format|
msg = {:status => "FAILED", :messages => "Customer Not Saved"}
format.json { render :json => msg } # don't do msg.to_json
end
end
def sign_in_iphone
#customer = Customer.authenticate(params[:email], params[:password])
unless (#customer == 0 || #customer == nil)
respond_to do |format|
msg = {:status => "SUCCESS", :message => "CUSTOMER", :data => #customer.as_json}
format.json { render :json => msg } # don't do msg.to_json
end
else
respond_to do |format|
msg = {:status => "FAILED"}
format.json { render :json => msg } # don't do msg.to_json
end
end
end
In my password_reset_controller
class CustomerPasswordResetsController < ApplicationController
def edit
#customer = Customer.find_by_password_reset_token!(params[:id])
end
def update
#customer = Customer.find_by_password_reset_token!(params[:id])
if #customer.password_reset_sent_at < 2.hours.ago
redirect_to new_customer_password_reset_path, :alert => "Password reset has expired."
else
#customer.password_hash = BCrypt::Password.create(params[:password])
# #customer.save
unless !#customer.save
redirect_to new_customer_password_reset_path, :alert => "Password has been reset!"
else
render :edit
end
end
end
In my password_reset.html.erb
<%= form_for #customer, :url => customer_password_reset_path(params[:id]), :method => :patch do |f| %>
<% if #customer.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #customer.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Update Password" %></div>
Given your form the new password will be in params[:customer][:password] not params[:password] - your existing code always sets the password to nil.
Changing the password resets controller update action to instead do
#customer.password = params[:customer][:password]
should do the trick. As a side note the commented out customer.save doesn't matter because you save again on the next line.
Next time something like this happens consider using the debugger to examine what is happening in your action - it would be easy enough to spot that the password was being set to nil. The debugging guide has lots more tip on this.
It's possible that you're assigning password as well as doing some post-processing with password_hash. The way this is intended to be used is via password alone if you have the model code with that password= method. This means you won't need to do any additional work beyond simply assigning it.
What you want in your password_reset method is:
#customer.password = params[:password]
#customer.save!
That should take care of it by running it through the appropriate model code.

sessions handling in rails when signed up

When I log in I get sessions working, I can log out etc. But when I create an account I can't do that, the link to logging out is not there. Any suggestions?
Here is the code for logging out layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Auth</title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!--Detta kod säger bara när du loggar in ska man kunna se länkarna... du måste skriva om den så att den säger bara
när du är inloggad ELLER skapat konto visa dessa länkar-->
<div id="user_nav">
<% if current_user %>
Logged in as <%= current_user.email %> DETTA ÄR APPLICATION.HTML.ERB.
<%= link_to "Log out", log_out_path %>
<% else %>
<%= link_to "Sign up", sign_up_path %> or
<%= link_to "log in", log_in_path %>
<% end %>
</div>
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %>
<%= yield %>
</body>
</html>
Here is sessions_controller
class SessionsController < ApplicationController
#auth
#behöver new defineras? ska den vara tom? varför måste den finnas? ny session?
#är det korrekt att skriva params[:blabla] etc?
#varför kickar sessions in bara när man loggar in? och inte när man skapat konto?
def new
end
#det känns som sessions skapas bara när man loggar in.. AKA AUTHENTICATE
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to testsida_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end
Here is users controller
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to testsida_url, :notice => "Signed up!"
else
render "new"
end
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Here is application controller
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def authorize
redirect_to login_url, alert: "Not authorized" if current_user.nil?
end
end
So I dont really know why sessions is not working when creating accounts, but when logging in they work? :S
When you create a new user, you aren't creating a new session as well (or at the very least it doesn't appear like you are). The easiest fix would be to set your :user_id session variable when a new user is created.
class UsersController < ApplicationController
# new
def create
#user = User.new(user_params)
if #user.save
# Set the current user id below
session[:user_id] = #user.id
redirect_to testsida_url, :notice => "Signed up!"
else
render "new"
end
end
# user_params
end

admincontroller using wrong helper for create action

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].

Resources