I get this error while clicking in form Log In button:
undefined method `[]' for nil:NilClass
View with signup form is below:
<%= form_for(:session, url: login_path) do |f| %>
<%= f.text_field :login, :placeholder => "login" %>
<%= f.password_field :password, :placeholder => "Password" %>
<%= f.submit "Log in", class: "btn-submit"%>
<% end %>
SessionsController :
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_login(params[:login][:password]) ////ERROR LINE
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/'
else
flash.now[:danger] = 'err'
redirect_to '/login'
end
end
def destroy
session[:user_id] = nil
redirect_to '/'
end
end
User controller:
class UsersController < ApplicationController
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
Routes:
get 'logout' => 'sessions#destroy'
post 'logout' => 'sessions#destroy'
delete 'logout' => 'sessions#destroy'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
resources :users, :user_types
Also, I do not want to create 'signup' view - there should be no possibility to create user through website
Looking at your form, I don't think you have params[:login]. So it'll be nil and params[:login][:password] is evaluated to nil[:password]. That's why you have the error.
What you have, according to the form, should be params[:session][:login] and params[:session][:password]. So the only remaining question is how you implemented your User.find_by_login method.
Related
I had some nice form that had been working well, but once I add some translations, I get following error:
Here are some important files I have:
routes.rb
Rails.application.routes.draw do
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
get 'sessions/new'
get 'teamscrs/index'
get 'teamscrs/new'
get 'teamscrs/show'
get 'profile', to: 'teamscrs#show'
get 'login', to: 'sessions#new'
get 'users', to: 'users#new'
delete 'logout', to: 'sessions#destroy'
post 'login', to: 'sessions#create'
resources :users
root 'teamscrs#index'
end
match '*path', to: redirect("/#{I18n.default_locale}/%{path}"), :via => [:get, :post]
match '', to: redirect("/#{I18n.default_locale}"), :via => [:get, :post]
#get '/teamscrs' => 'teamscrs#home'
end
users_controller.rb
class UsersController < ApplicationController
def index
end
def show
#user = User.find(params[:id])
end
def new
#user= User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = t(".sukces")
redirect_to #user
else
flash.now[:danger] = t(".fail")
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :set_locale
helper_method :current_user, :logged_in?
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
!!current_user
end
def must_login
if !logged_in?
flash[:danger] = t(".mustlogin")
redirect_to login_path
end
end
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
def default_url_option(options = {})
{locale: I18n.locale}
end
end
users/new.html.erb
...
<%= form_with scope: :user, url: users_path, local: true do |form| %>
<div class="form-group">
<%= form.label(:name,t('.username'))%>
<%= form.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label(:email,t('.email'))%>
<%= form.text_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label(:password_digest,t('.pass'))%>
<%= form.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label(:password2, t('.passc'))%>
<%= form.password_field :password_confirmation, class: 'form-control' %>
</div>
<%= form.submit t('.join'), class: 'btn btn-success' %>
<% end %>
...
users/show.html.erb
<p>
<strong>Użytkownik:</strong>
<%= #user.name %>
</p>
<p>
<strong>email:</strong>
<%= #user.email %>
</p>
config/environment.rb
...
Rails.application.configure do |variable|
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**/*.{rb,yml}').to_s]
I18n.available_locales = [:en, :pl]
I18n.default_locale = :pl
end
...
I spent whole day reading stackoverflow, I18n guides and watching youtube videos. I'm just a beginner. Please support.
I solved it by changing:
redirect_to #user
to:
redirect_to controller: 'users', action: 'show', id: #user.id
after I read that cause of implementing default_url_options, I have to explicitly let know Rails to pass the id
In the users_controller.rb, there is one update method defined where redirect_to #user. This is in fact which is redirecting to some URL. But this error says this #user is no URL matching against this.
Solution:
The best way to write routes is to run rails routes. From there copy the path for user#index and paste in the arguments of redirect_to.
it may be like
redirect_to user_path
or
redirect_to users_path
or
redirect_to user_index_path
I have Photo model which belongs to User model. Rails returns this error whenever I try to access new view for /users/4/photos/new:
No route matches {:action=>"index", :controller=>"photos", :user_id=>"4"} missing required keys: [:id]
This is my PhotosController:
class PhotosController < ApplicationController
def index
find_user
#photos = #user.photos
end
def new
find_user
#photo = #user.photos.build
end
def show
find_photo
end
def create
#photo = Photo.new(params[:photo])
if #photo.save
if params[:images]
params[:images].each { |image|
#user.photos.create(image: image)
}
end
else
render 'new'
end
end
def update
find_user
#photo = #user.photos.find(params[:id])
if #photo.update
redirect_to photos_path
else
render 'edit'
end
end
def destroy
find_photo
#photo.destroy
redirect_to photos_path
end
private
def find_user
#user = User.find(params[:user_id])
end
def find_photo
#photo = Photo.find(params[:id])
end
def photo_params
require(:photo).permit(:title, :image, :user_id)
end
end
And this is my _form partial for photos views.
<%= form_for #photo, :html => { class: 'form-horizontal', multipart: true } do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "input-field form-control" %>
<%= f.label :pictures %>
<%= file_field_tag "images[]", type: :file, multiplue: true %>
<%= f.submit nil, class: "btn btn-primary" %>
I don't understand how ID is missing, I'm providing it via find_user method.
Update:
# routes.rb
Rails.application.routes.draw do
root 'welcome#index'
# prevedene rute
get "/pocetna" => "welcome#index", as: "index"
get "/o-sajtu" => "welcome#about", as: "about"
get "/moj-profil" => "users#show", as: "profile"
post "/users" => "users#create"
get "/users" => "users#index", as: "users"
get "/user" => "users#index"
get "/users/:id" => "users#show", as: "user"
get "/users/:id/edit" => "users#edit", as: "edit_user"
patch "/users/:id" => "users#update"
get "/users/add" => "users#new", as: "new_user"
resources :sessions, only: [:new, :create, :destroy]
get "/login" => "sessions#new", as: "login"
post "/login" => "sessions#create"
get "/logout" => "sessions#destroy", as: "logout"
delete "/logout" => "sessions#destroy"
resources :users do
resources :photos
end
end
Update
I get new error now
undefined method `photos_path' for #<<Class:0x007f4f14f16160>:0x00000004f040e8>
First line of the form is marked.
change your form_for in _form partial to
form_for([#user, #photo]) do |f|
#rest of your code
end
How do you call the /users/4/photos/new in your view? Ideally you should pass the user_id as id not as user_id. Once, you do that this issue should be resolved.
I have Rails 4.0.10. I'm following Michael Hartl's Ruby on Rails tutorial, and I'm trying to build a login function, but I'm getting the following error when I press the login button:
Routing Error
uninitialized constant SessionController
I followed the instructions exactly, so I'm confused about why I'm getting an error. What did I do wrong?
My Sessions Controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(id: params[session][:id])
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to root_path
else
flash.now[:danger] = 'Invalid'
render 'new'
end
end
def destroy
end
end
Routes:
Website::Application.routes.draw do
get 'login' => 'sessions#new'
post 'login' => 'session#create'
delete 'logout' => 'sessions#destroy'
get "users/new"
root 'home_page#home'
end
Sessions/new View:
<div id= "admin-sign-in">
<%= form_for(:session, url: login_path) do |f| %>
<%= f.label :id %>
<%= f.text_field :id %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>
</div>
Sessions Helper:
module SessionsHelper
def log_in(user)
session[:user_id] = user.id
end
end
User Model:
class User < ActiveRecord::Base
has_secure_password
end
Users Controller:
class UsersController < ApplicationController
def new
#user = User.new
#users = User.all
end
def create
#user = User.new(user_params)
if #user.save
render :action => "crop"
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
end
ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
end
Instead of:
post 'login' => 'session#create'
Use the plural:
post 'login' => 'sessions#create'
With my set up I have 2 types of Devise users Admins and Users I would like to be able to have the admins manage the users.
I have found some tutorials about this but they approach the problem from the perspective of a single User model with roles.
So far I've gotten to the point where, when I'm logged in as an admin, I can list the users, destroy the users and create new users, however, when I try to edit a user I get a blank form (as opposed to one that's populated by user information)
Any advice would be appreciated.
Below are the relevant files. Let me know if you need to see anything else.
/config/routes.rb
TestApp::Application.routes.draw do
devise_for :admins
devise_for :users
root to: 'pages#home'
# Admin Routes
if Rails.env.production?
devise_for :admins, :skip => [:registrations]
else
devise_for :admins
end
namespace :admins do
resources :users
end
authenticated :admin do
# For production because of skip registrations
get 'admins/edit' => 'devise/registrations#edit', as: :edit_admin_registration
put 'admins' => 'devise/registrations#update', as: :admin_registration
get 'admins/dashboard' => 'admins#dashboard', as: :admin_dashboard
devise_scope :admin do
get 'admins/list' => 'admins/users#index', as: :manage_users
get 'admins/users/new' => 'admins/users#new', as: :new_admins_user
get 'admins/users/:id/edit' => 'admins/users#edit', as: :edit_admins_user
post 'admins/users' => 'admins/users#create', as: :users
delete 'admins/users/:id' => 'admins/users#destroy', as: :destroy_admins_user
end
# Manage Content Routes
get '/pages/manage' => 'pages#manage', as: :manage_pages
get '/products/manage' => 'products#manage', as: :manage_products
end
authenticated :user, :admin do
get '/products' => 'products#index'
get '/pages/4' => 'products#index'
get '/gallery' => 'products#index'
end
unauthenticated do
devise_scope :users do
get '/pages/4' => 'devise/registrations#new'
get '/gallery' => 'devise/registrations#new'
end
end
resources :pages
resources :products
end
/controllers/admins_controller.rb
class AdminsController < ApplicationController
load_and_authorize_resource
def dashboard
render "admins/dashboard"
end
def index
respond_to do |format|
format.html
end
end
def destroy
#admin.destroy
redirect_to manage_admins_path
end
end
/controllers/admins/users_controller.rb
class Admins::UsersController < ApplicationController
load_and_authorize_resource
def index
#users = User.all
respond_to do |format|
format.html
end
end
def new
#resource = User.new
respond_to do |format|
format.html
end
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to manage_users_path, notice: 'User was successfully created.' }
else
format.html { render new_admin_user_path }
end
end
end
def update
#user = User.find(params[:id])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to manage_users_path, notice: 'User was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to manage_users_path
end
# private
# def check_permissions
# authorize! :create, resource
# end
end
/views/admins/users/edit.html.haml
.input-form
%h2
Edit #{resource_name.to_s.humanize}
= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f|
= devise_error_messages!
%fieldset{id: "edit-your-account"}
.field.required
= f.label :first_name
= f.text_field :first_name, :autofocus => true
.field.required
= f.label :last_name
= f.text_field :last_name
.field.required
= f.label :company
= f.text_field :company
.field.required
= f.label :phone
= f.text_field :phone
.field.required
= f.label :email
= f.email_field :email
.field.required
= f.label :password
= f.password_field :password
%span.instructions
(leave blank if you don't want to change it)
- if devise_mapping.confirmable? && resource.pending_reconfirmation?
%br
Currently waiting confirmation for:
= resource.unconfirmed_email
.field.required
= f.label :password_confirmation
= f.password_field :password_confirmation
.field.required
= f.label :current_password
= f.password_field :current_password
%span.instructions
(we need your current password to confirm your changes)
.field
= f.submit "Update"
= link_to "Back", :back
/helpers/admins_helper.rb
module AdminsHelper
# Devise helpers for Admin::UsersController
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Looks like renaming your instance variable should do the trick. Your edit template passes the object resource to the form but the object you've loaded from the database is set to #user:
# Admins::UsersController
def edit
#user = User.find(params[:id])
end
# AdminsHelper
def resource
#resource ||= User.new
end
You could pass this instance variable to the form_for instead, or rename #user as #resource so the helper method will return the proper instance.
So far I have implemented a simple user with authentication ( user controller and session controller) and I want to go to a MyAccount page using a users#edit route and update, say the email adress of the current user. The problem is that the update function is updating the current view with the email I want to change, but not the database, so when I hit refresh the #user.email object would return to its initial value. Thank you!
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
UserMailer.registration_confirmation(#user).deliver
redirect_to log_in_path, :notice => "Signed up!"
else
render "new"
end
end
def edit
#user = current_user
end
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def set_user
#user = current_user
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
I have also added the sessions controller I have created.
class SessionsController < ApplicationController
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
redirect_to root_url, :notice => "Logged in"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out"
end
end
My routes are as follows:
get "log_in" => "sessions#new", :as => "log_in"
get "log_out" => "sessions#destroy", :as => "log_out"
get "sign_up" => "users#new", :as => "sign_up"
#get "my_account" => "users#show", :as => "my_account"
get "my_account" => "users#edit", :as => "my_account"
get "main/index"
resources :users
resources :sessions
Finally, my Application controller and aplication.html:
class ApplicationController < ActionController::Base
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
end
In application.html is where I used the current_user method:
<div id="user_nav">
<% if current_user %>
Logged in as <%= current_user.email %>
<%= link_to "Log out", log_out_path %>
<%= link_to "My Account", my_account_path %>
<% else %>
<%= link_to "Sign up", sign_up_path %>
<%= link_to "Log in", log_in_path %>
<% end %>
</div>
I am not sure why you are using
if #user.update(:current_user)
It should be something like:
if #user.update(user_params)
I know this is simple and maybe you already corrected this but...
instead of
if #user.update(user_paramas)
try
if #user.update(user_params)