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'
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'm building a newsletter management form and I want to use simple_form. The email parameter should be sent to the email_subscriber#manage controller/action via POST method.
routes.rb
get 'email/login' => 'email_subscribers#login', as: 'email_login'
get 'email/manage' => 'email_subscribers#manage', as: 'email_manage'
email_subscribers_controller.rb
def login
end
def manage
#subscriber = EmailSubscriber.find_by_email(safe_params(:email))
unless #subscriber
# redirect_to email_login_path, notice: 'That email does not exist.'
end
end
email/login form
<%= render :layout => 'application/container' do %>
<%= simple_form_for(#subscriber, path: :email_manage_path, method: :get) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email, as: :email %>
</div>
<div class="form-actions">
<%= f.button :submit, value: 'Manage Subscription' %>
</div>
<% end %>
The login route is where the form is. It allows the user to enter their email in order to unsubscribe from the newsletter.
The form should redirect to the manage action, passing the email parameter for which there is no corresponding model.
The current form doesn't work. For some reason it redirects to the EmailSubscribers index page.
Changing the email_manage route to POST causes missing route POST email/login which makes no sense because the form is posting to email_manage_path, not the email_login_path
Thanks
EDIT:
rake routes output (opens in this same tab)
http://pastebin.com/eFGdvxid
You can actually model this as a conventional RESTful resource instead:
resources :subscriptions
namespace :subscriptions do
resources :logins
get '/login', to: 'logins/create'
end
The advantage is that you get a much simpler setup that follows the canonical crud verbs and you also use the correct HTTP verbs.
The only unconventional part here is that we add an additional route to create via GET:
# app/controllers/subscriptions/logins_controller.rb
class Subscriptions::LoginsController < ApplicationController
rescue_from ActionController::ParameterMissing, with: :subscription_not_found
# GET /subscriptions/logins/new
def new
#subscription = Subscription.new
end
# POST /subscriptions/logins
# GET /subscriptions/login
def create
#subscription = Subscription.find_by_email(email_param)
if #subscription
redirect_to edit_subscription_path(#subscription)
else
subscription_not_found
end
end
private
def subscription_not_found
render :new, error: 'Email could not be found.'
end
def email_param
if request.post?
params.require(:subscription).fetch(:email)
else
params.fetch(:email)
end
end
end
Since we actually are binding to a resource you can set the form up in a very straight forward way. We also add a GET route which lets the user log in directly from a link.
The form is very straight forward.
<%= simple_form_for(#subscription, path: subscriptions_sessions_path) do %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email, as: :email %>
</div>
<div class="form-actions">
<%= f.button :submit, value: 'Manage Subscription' %>
</div>
<% end %>
You can then create a pretty run of the mill CRUD controller that lets the user edit or unsubscribe:
# app/controllers/subscriptions_controller.rb
class SubscriptionsController < ApplicationController
before_action :set_subscription, only: [:edit, :update, :destroy]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_email
def new
#subscription = Subscription.new
end
def create
#subscription = Subscription.new(subscription_params)
if #subscription.save(subscription_params)
redirect_to root_path, success: 'Your subscription settings have been creates'
else
render :new
end
end
def edit
end
def update
if #subscription.update(subscription_params)
redirect_to root_path, success: 'Your subscription settings have been updated'
else
render :edit
end
end
def destroy
#subscription.destroy
redirect_to root_path
end
private
def set_subscription
#subscription = Subscription.find(params[:id])
end
def subscription_params
params.require(:subscription).permit(:foo, :bar, :baz)
end
end
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.
I'm following a rails tutorial and need some help to proceed further. Problem is, once I fill out the form which has a title,body fields and hit submit, it has to redirect to the show.html.erb page instead it throws an error.
Error: The action 'create' could not be found for PostsController
routes.rb
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
get "/posts" => "posts#index"
post "/posts" => "posts#create"
get "/posts/show" => "posts#show", as: :show
get "/posts/new" => "posts#new"
end
posts_controller_tests.rb
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
new.html.erb
<h1>Create a new blog post</h1>
<div class="form">
<%= form_for Post.new do |f| %>
<%= f.label :title %>: <br>
<%= f.text_field :title %> <br> <br>
<%= f.label :body %>: <br>
<%= f.text_area :body %> <br> <br>
<%= f.submit %>
<% end %>
</div>
Any help on this would be appreciated.
Note: You are using posts_controller_tests.rb not posts_controller.rb. You are putting your controller code in test controller.
Try to move the code in app/controllers/posts_controller.rb:
class PostsController < ApplicationController
def index
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
redirect_to show_path
end
def show
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
Your create action always redirects you to the show action. It doesn't matter if your model was saved or not.
You have to check if the model was saved or not:
def create
#post = Post.new(post_params)
if #post.save
flash[:success] = 'Successfully saved'
redirect_to #post
else
render 'new'
end
end
If it wasn't saved, it renders the new action again.
Change your routes.rb to this:
Rails.application.routes.draw do
get "/pages/about" => "pages#about"
get "/pages/contact" => "pages#contact"
resources :posts
end
Moreover you should inherit your controller from ActionController::Base
so change first line of your controller to
class PostsController < ActionController::Base
and move the controller to app/controllers/posts_controller.rb
I've spent several days on it, but couldn't carry out. I wonder how can I make logging in as admin using a Bootstrap Modal either when clicking on a link or visiting /admin page.
I made an admin namespace
namespace :admin do
resources :users
resources :shops
match '/index' => 'shops#index', :via => :get, :as => 'index'
get '', to: 'sessions#new', as: '/'
end
and also Users & Shop controllers and views in /admin folder.
Different solutions on the web couldn't work and that's why I decided to make it from the very beginning.
Just say if any other information about application is needed. Relying on your knowledge, I will be grateful for any help!
PS: Authentication method in application is taken from Hartl's tutorial (there's no authentication libraries).
Login page (/admin), views/admin/sessions/new.html.erb:
<% provide(:title, "Sign in") %>
<h1>Sign in as admin</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
And also, if non-admin tries to access /admin page, he will be redirected ro the 'login as admin' page. controllers/admin/users_controller.rb has admin_user for show action:
class Admin::UsersController < ApplicationController
before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:show, :destroy]
def index
#users = User.paginate(page: params[:page])
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] = "Welcome to the Hotels Advisor!"
redirect_to root_url
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to [:admin, #user]
else
render 'edit'
end
end
def destroy
user = User.find(params[:id])
unless current_user?(user)
user.destroy
flash[:success] = "User deleted."
end
redirect_to admin_users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
def creating_forbidden
if signed_in?
redirect_to root_url, notice: "You are already regsitered."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end