I am trying to implement a forgotten password solution in rails. I have a form for the user to enter the email address for their registered account, and I intend to have a mailer email them a unique URL that will link them to a password reset page.
My config/routes.rb file has the following routes:
resources :users do
collection do
get :lost_password #the account-email submisison form url
get :reset_password #a url for the function that sends the response email
end
end
When I run rake routes from the console, I get the paths I want:
lost_password_users GET /users/lost_password(.:format) {:action=>"lost_password", :controller=>"users"}
reset_password_users GET /users/reset_password(.:format) {:action=>"reset_password", :controller=>"users"}
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
BUT! When the user hits the submit button on the form outlined in the code below:
<h3>Reset Password</h3>
<%= form_for(:user, :url => reset_password_users_path) do |f| %>
<p>Enter the email address you used to register for this site.</p></br>
<div class="field">
<%= f.label :email %> </br>
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit "Send Email" %>
</div>
<% end %>
I get a
No route matches
"/users/reset_password"
error through the ActionController.
I do, in fact, have views and controller functions defined for both the lost_password_users_path and the reset_password_users_path, so I'm puzzled as to why I would run into this routing error.
I have two questions:
Why would the ActionController raise this error, when I clearly have the path, methods, and views defined?
Has anyone else implemented a password reset in RoR, and can you lend any insight as to whether or not this approach is good practice?
Thanks in advance!
Try changing get :reset_password to post :reset_password in routes.rb
function of reset password: I hope,it will be work, use in controller update function
if params[:user][:password].present?
puts "present"
puts params[:current_password]
if (params[:user][:password] == "")
params[:user].delete(:password)
else
if #user.valid_password?(params[:current_password])
#updated = true
puts #updated.to_s
#user.update_attributes(user_params)
sign_in(#user,:bypass => true)
flash[:notice] = "Password Updated Successfully"
redirect_back fallback_location: user_url
else
#updated = false
puts #updated.to_s
flash[:danger] = "Current Password does not matched"
redirect_back fallback_location: user_url
end
end
Related
I'm new to rails and am working on a simple reddit-type app for practice. I'm trying to let users update the link they have posted. This is the links_controller:-
class LinksController < ApplicationController
before_action :logged_in_user, only: [:new, :create, :edit, :update]
#before_action :correct_user, only: [:edit, :update]
def new
#link = Link.new
end
def create
#user = current_user
#link = #user.links.build(params)
if #link.save
flash[:success]= "Link submittd successfully"
redirect_to root_path
else
flash[:danger]= "Link submission failed"
render 'new'
end
end
def edit
#user = current_user
#link = #user.links.find_by(id: params[:id])
end
def update
#user = current_user
#link = #user.links.find_by(id: params[:id])
if #link.update_attributes(params)
flash[:success] = "Link successfully edited"
redirect_to current_user
else
flash[:danger] = "Link edit failed"
render 'edit'
end
end
private
# def link_params
# params.permit(:title, :url)
# end
def logged_in_user
redirect_to login_path unless logged_in
end
def correct_user
#link = current_user.links.find_by(id: params[:id])
redirect_to root_path if #link.nil?
end
end
Currently I'm facing this error:-
Log:-
Started GET "/edit_link" for ::1 at 2017-05-23 13:20:56 +0530
Processing by LinksController#edit as HTML
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Link Load (0.2ms) SELECT "links".* FROM "links" WHERE "links"."user_id" = ? AND "links"."id" IS NULL ORDER BY "links"."created_at" DESC LIMIT ? [["user_id", 1], ["LIMIT", 1]]
Rendering links/edit.html.erb within layouts/application
Rendered links/edit.html.erb within layouts/application (4.6ms)
Completed 500 Internal Server Error in 70ms (ActiveRecord: 1.6ms)
ActionView::Template::Error (First argument in form cannot contain nil or be empty):
4: <div class="row">
5: <div class="col-md-6 col-md-offset-3">
6:
7: <%= form_for(#link, url: edit_link_path) do |f| %>
8:
9: <%= f.label :title %>
10: <%= f.text_field :title, class: 'form-control' %>
This is the edit form for the link:-
<% provide(:title, 'Edit Link') %>
<h1>Edit Link</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#link, url: edit_link_path) do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
<%= f.label :url %>
<%= f.text_field :url, class: 'form-control' %>
<%= f.submit "Save Changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
The routes file:-
Rails.application.routes.draw do
root 'static_pages#home'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/submit_link', to: 'links#new'
post '/submit_link', to: 'links#create'
get '/edit_link', to: 'links#edit'
patch '/edit_link', to: 'links#update'
get '/contact', to: 'static_pages#contact'
resources :users
resources :links
end
As it stands it is really messy. There are many different things that could be wrong and I don't have enough grasp over the various factors to find out the best way to do this.
I'm especially struggling with the params, strong params.
Basically this is what I'm trying to implement:-
Only logged in user who is the owner of the link can access the edit
and update actions for the link. I'm using the before_action filters
to ensure this.
I'm using strong params as defined in the link_params method in
private
I'm not 100% sure on the code in the edit and update actions. What I've listed up there is just what I think should be the logical code.
If you could show me how to get this to work and also the best practice to be followed while doing this, it would be great.
Update:-
I tried to use link_params earlier but that seemed to generate the error of the required link not being present, so I have muted it for now and am trying to work out how to get it to work through params first.
As it stands it seems that the edit and update actions are not receiving the params[:id] that is required for them to proceed with the action. I don't know how to get the params to be accessible in the actions. I've used the custom route get "edit_link_path" for the links#edit and patch "edit_link_path" for the links#update. Don't know if this is a problem.
Most recent update:-
updated routes.rb (with the link.id appendage to edit and update routes):-
Rails.application.routes.draw do
root 'static_pages#home'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/edit_link/link.id', to: 'links#edit'
patch '/edit_link/link.id', to: 'links#update'
get '/submit_link', to: 'links#new'
post '/submit_link', to: 'links#create'
get '/contact', to: 'static_pages#contact'
resources :users
resources :links
end
A list of all available routes:-
$ rails routes
Prefix Verb URI Pattern Controller#Action
root GET / static_pages#home
login GET /login(.:format) sessions#new
POST /login(.:format) sessions#create
logout DELETE /logout(.:format) sessions#destroy
signup GET /signup(.:format) users#new
POST /signup(.:format) users#create
GET /edit_link/link.id(.:format) links#edit
PATCH /edit_link/link.id(.:format) links#update
submit_link GET /submit_link(.:format) links#new
POST /submit_link(.:format) links#create
contact GET /contact(.:format) static_pages#contact
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
links GET /links(.:format) links#index
POST /links(.:format) links#create
new_link GET /links/new(.:format) links#new
edit_link GET /links/:id/edit(.:format) links#edit
link GET /links/:id(.:format) links#show
PATCH /links/:id(.:format) links#update
PUT /links/:id(.:format) links#update
DELETE /links/:id(.:format) links#destroy links#update
PUT /links/:id(.:format) links#update
DELETE /links/:id(.:format) links#destroy
Currently the error is No route matches [PATCH] "/links/2/edit"
As you can see above in the list of available routes, there is a "edit_link GET /links/:id/edit(.:format) links#edit" but there is no equivalent for the update action even though the routes.rb file has the listing for that. Don't understand why.
Ok, finally figured it out and fixed everything. The problem was with the routing. I had to route the link id in the routes for edit and update and it had to be patch '/link.:id'. Everything else including strong params and correct_user works after that. Great!
im trying create backend under password from database and i cant go through login page :P
My AdminController
class Backend::AdminController < ApplicationController
layout :layout
before_filter :authorize, :except => :login
def authorize
if session[:backend] != true
redirect_to backend_login_path
end
end
private
def layout
if session[:backend] == true
"admin"
else
"login"
end
end
def login
employee = Employee.authenticate(params[:name], params[:password])
if employee
session[:backend] = true
redirect_to backend_root_path, :notice => "Logged in!"
else
flash.now.alert = "Invalid login"
end
end
def logout
session[:backend] = nil
redirect_to backend_login_path, :notice => "Logged out!"
end
end
My Routes
match "backend/login" => "backend/admin#login"
match "backend/logout" => "backend/admin#logout"
My Login page
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %>
<h1>Log in</h1>
<%= form_tag backend_login_path do %>
<p>
<%= label_tag :name %><br />
<%= text_field_tag :name, params[:name] %>
</p>
<p>
<%= label_tag :password %><br />
<%= password_field_tag :password %>
</p>
<p class="button"><%= submit_tag "Log in" %></p>
<% end %>
when i go on url /backend im redirected to /backend/login, thats right
when i enter good login or bad login nothing happened and NO flashes appears thats strange ?
from webserver console output, i see the POST informations go through login method.. i dont know what is wrong ? thank you
edit: when i try go to URL /backend/logout im getting
Unknown action
The action 'logout' could not be found for Backend::AdminController
i really dont understand this :( im begginer
one of the conventions in rails is, that public methods in a controller are considered to be actions.
if you want to write methods for before_filter etc, make them private or protected so that rails will not expose them as actions.
on the flipside, you are not able to define actions as private.
I'd like to display an "Add to Favourites" button to users that are not logged in so that they can see that logged in users can add posts (in this case) to their favourites.
Here's the current code:
routes.rb
resources :users do
resources :favourites
end
resources :favourites, only: [:create, :destroy]
posts_helper.rb (I'll move this application_helper once I get it working)
PostsHelper
def new_favourite
if signed_in?
return current_user.favourites.build
else
return Favourite.new
end
end
end
show.html.erb
<%= render :partial => 'shared/favourites/favourite_form', :locals => { :object => #post } %>
_favourite_form.html.erb
<% if signed_in? && current_user.favourited?(object) %>
<%= render partial: 'shared/favourites/unfavourite', locals: { object: object } %>
<% else %>
<%= render partial: 'shared/favourites/favourite', locals: { object: object } %>
<% end %>
_favourite.html.erb
<%= form_for(new_favourite, remote: signed_in?) do |f| %>
<div>
<%= f.hidden_field :object_id, :value => object.id %>
<%= f.hidden_field :object_type, :value => object.class.name.demodulize %>
</div>
<%= button_tag(:type => 'submit', :id => 'add_favourite') do %>
Add to Favourites
<% end %>
<% end %>
I want it to not do an ajax call (ie submit the add favourite form using a page reload) if the user is not signed in so that it will see the user is trying to access a protected page, will redirect them to login and upon success [when it redirects them back to where they were originally trying to go] it will add the favourite.
Can someone advise what I would need to change to make this possible.
EDIT:
Code updated to reflect current state.
After signing in it redirects back to No route matches [GET] "/favourites" because favourites are a nested resource under users.
EDIT 2:
The redirect works pretty much the same as in Rails Tutorial:
Redirect user to sign in page (signed_in_user):
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-correct_user_before_filter
Store location to redirect user back to:
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-friendly_forwarding_code
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-friendly_session_create
The only difference is that on my signin page I use a facebook omniauth link for the user to login but the redirection after logging in still works as expected.
Use a helper method instead of current_user.favourites.build?
<%= form_for(new_favourite, remote: true) do |f| %>
Helper:
PostsHelper
def new_favourite
if signed_in?
return current_user.favourites.build
else
return Favourite.new
end
end
end
I am following a tutorial and I am trying to invoke a delete method like this:
in users/index.html.erb I got:
<!-- View for index action in user's controleer -->
<h1>All users - Administration Page</h1>
<%= will_paginate %>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= link_to user.name, user %>
<!-- if the current user is admin -->
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete, confirm: "You sure?" %>
<% end %>
</li>
<% end %>
</ul>
<%= will_paginate %>
in my users controller I got this:
#destroying users!
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
instead of getting a confirm box, I am being redirected into the user's profile?!
It seems that rails server cannot read the delete method I am sending to it!
Edit:
rake routes:
rake routes
intergration_test_authentication_pages GET /intergration_test/authentication_pages(.:format) intergration_test#authentication_pages
root / static_pages#home
user_profile /user_profile(.:format) users#show_user
all_videos /all_videos(.:format) static_pages#allvideos
show_interface /show_interface(.:format) static_pages#interface
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
session DELETE /sessions/:id(.:format) sessions#destroy
signup /signup(.:format) users#new
signin /signin(.:format) sessions#new
signout /signout(.:format) sessions#destroy
More than likely you are not including the necessary jQuery UJS Javascript on your page. This is what allows the :method parameter to work properly.
I saw a few problems in the syntax on your link_to. Try updating this part:
:method => :delete, :confirm => "You sure?"
This question is a follow up to this previous question: Ruby on Rails: Custom actions
As a follow up, what would be the syntax to use a custom action in a form_for? For my app, I have a partial called _invite_form.html.erb, and set the form to have a :url specification that I thought would link the form to the invite action on the Users controller:
<div id = "invite_form">
<h1>Invite</h1>
<%= form_for(invited, :url => invite_user_path) do |f| %>
<div class="field">
<%= f.text_field :email, :class => "inputform round", :placeholder => "email" %>
</div>
<div class="actions">
<%= f.submit "Invite", :class => "submit_button round" %>
</div>
<% end %>
</div>
This partial is called on certain pages, and this error is given:
"No route matches {:action=>"invite", :controller=>"users"}"
In my routes.rb file I have included the appropriate lines:
resources :users do
member do
get :invite
post :invite
end
end
Why is it that the route doesn't work? How do I change these files to make the form use the action "Invite" on the Users controller?
** Forgot to mention earlier: I defined invited in the Users helper: users_helper.rb:
module UsersHelper
def invited
#invited = User.new(params[:user])
end
end
As you don't have a persistent User just yet, make this a collection operation by:
Changing invite_user_path to invite_users_path in your controller
Changing member do to collection do in your routes
invite_user_path expects a user as an argument. Try invite_user_path(invited). You will also need to save the user before you can compute a path to it.
To experiment, go into rails console and see the difference between the following:
app.invite_user_path
app.invite_user_path(User.first)
app.invite_user_path(User.new)