I'm trying to learn RoR by developing my own custom CMS (yeah, yeah...) and I'm wanting to do a simple thing, but am unable to come up with a clean solution.
My routes file has the following match:
match '/login' => "sessions#new"
What it does is, upon hitting "http://localhost:3000/login", is let me login to create a new session. It works perfectly...
However, this is what my Sessions controller looks like:
class SessionsController < ApplicationController
def create
#username = params[:session][:username]
#password = params[:session][:password]
#rUser = User.find_by_username(params[:session][:username])
#if user && user.authenticate(params[:session][:password])
if #rUser && Digest::SHA2.hexdigest(#password) == #rUser.password
# Sign the user in and redirect to the user's show page.
redirect_to users_path, :flash => { :notice => "Logged in as #{#username}." }
else
# Create an error message and re-render the signin form.
redirect_to '/login', :flash => { :error => "Login failed. Either the username or password was incorrect." }
end
end
end
If you take a look at the "else" statement in my if-else conditional, you'll see that I'm using redirect_to '/login' to display the same form on login fail. Is there any better way to create a permanent link to '/login' rather than having to use a string, because if I decide to change the URL in the future, I'd prefer not to have to make the change in multiple places.
Sorry if it's not clear! Feel free to ask for further code (not showing in fear of pathetic-ness of it).
match '/login' => "sessions#new", :as => :login
Then you can use login_path in your controllers.
You can do like this
match '/login' => "sessions#new", :as => :login
#if want to call like localhost:3000/login
match '/sign_in' => "sessions#new", :as => :sign_in
#if want to call like localhost:3000/sign_in
Related
I have 2 custom views I built for devise, 1 changes the password the other updates other custom information. The password update worked, so I copied the method for the second view, however I am getting an error when submitting the data
No route matches [PATCH] "/users/discovery_settings/update"
which does not make sense because my route is
devise_for :users, controllers: {registrations: 'users/registrations'}
as :user do
end
get 'users/discovery_settings' => 'users#discovery_settings'
post 'users/discovery_settings/update' => 'users#update_discovery'
in my controller i user the same method that works for password updates
def update_discovery
#user = User.find(current_user.id)
if #user.update(user_params)
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
then i call it in my form_for view
<%= form_for(#user, :url => { :action => "update_discovery" }, html: {class: "form floating-label"}) do |f| %>
Any ideas how to fix the routing error?
I am at a lost as to why it is looking for "patch" when i have already specified "post"
The error's telling you. You have a POST route and the update is asking for a PATCH route.
try with patch instead of post:
patch 'users/discovery_settings/update' => 'users#update_discovery'
In a view I call upon a controller method. This however seems to call a different method than I want to do.
The view includes:
<%= link_to("Upgrade account", upgrade_path)
With routes:
get 'signup/organization' => 'organizations#new', as: 'register'
get 'signup/register' => 'organizations#new_premium', as: 'register_premium'
post 'signup/register' => 'organizations#checkout', as: 'signup_checkout'
post 'signup/register' => 'organizations#upgrade', as: 'upgrade'
get 'signup/confirmation' => 'organizations#confirmation'
'Upgrade' does not occur anywhere else in my routes file.
The path in the view should thus call upon the following controller method:
def upgrade
#organization = current_organization
#actioncode = Actioncode.new
#amount = DEFAULT_PRICE
#currency = "EUR"
#description = #organization.id
#transaction_description = "MyDescription"
#transaction_type = "S"
#hash = hash(#description, #amount, #currency, #transaction_type)
render 'checkout'
end
This should render a view (checkout.html.erb) which has two forms. However, instead it re-routes to the root with the message You're already logged in. As it turns out this message originates from the following controller method:
def new_premium
if (logged_in_user?)
flash[:danger] = "You're already logged in"
redirect_to root_url
end
#organization = Organization.new
#member = #organization.members.build
end
I don't see how that method can come into play and why my code isn't working. Does anyone have an idea?
The controller also contains a def checkout but I don't see how that might be of effect. The line render 'checkout' I would expect to render checkout.html.erb and have no relationship with either def checkout or def new_premium... right...?
Look at your routes:
post 'signup/register' => 'organizations#checkout', as: 'signup_checkout'
post 'signup/register' => 'organizations#upgrade', as: 'upgrade'
The same url with the same verb is used twice.
The rule in routing is "first match first served", so I guess they are all handled by checkout.
Fix is simple, change the url for one of them.
I am using Clearance 1.1.0 gem with Ruby on Rails 4.0.1. I am trying to override the sessions controller to provide my own custom method. I have not been able to successfully get rails to use my controller.
/app/controllers/sessions_controller.rb
class SessionsController < Clearance::SessionsController
private
def flash_failure_after_create
flash.now[:notice] = translate(:bad_email_or_password,
:scope => [:clearance, :controllers, :sessions],
:default => t('flashes.failure_after_create', :new_password_path => new_password_path).html_safe)
end
end
I have tried a few different things inside my routes.rb file, and have been unsuccessful. I want to change the route sign_in.
get '/sign_in' => 'sessions#new', :as => 'sign_in'
Yields the following error.
You may have defined two routes with the same name using the :as
option, or you may be overriding a route already defined by a resource
with the same naming.
Any ideas? Thank you!
Edit: I made a mistake. I actually need sessions#create to use my controller. I'm trying to pass a different variable to the yaml file for the flash when the session login fails.
Edit 2: I the appropriate session#create line to to my routes. In my session controller, I copied and edited for testing the flash_failure_after_create method. It is not being called. So I then copy the create method over. Now, my create method is being called, but not my flash_failure_after_create method. To get it to be called, I had to have the create method copied from gem, and changed status.failure_message to directly call the flash_failure_after_create method. Is this some sort of bug with clearance?
routes.rb
post 'session' => 'sessions#create', :as => nil
sessions_controller.rb
class SessionsController < Clearance::SessionsController
def create
#user = authenticate(params)
sign_in(#user) do |status|
if status.success?
redirect_back_or url_after_create
else
#flash.now.notice = status.failure_message
flash.now.notice = flash_failure_after_create
render :template => 'sessions/new', :status => :unauthorized
end
end
end
private
def flash_failure_after_create
# Changed flash for easy testing
flash.now[:notice] = 'Ballz.'
#flash.now[:notice] = translate(:bad_email_or_password,
# :scope => [:clearance, :controllers, :sessions],
# :default => t('flashes.failure_after_create', :sign_up_path => sign_up_path).html_safe)
end
end
I believe this will work:
get '/sign_in' => 'sessions#new', :as => nil
Rails 4 no longer supports overriding route names, so don't name your override. The mapping is still the same so sign_in_path should still work.
I have a Ruby On Rails 3.x application using device.
My goal is to add a Yubikey input field to the login screen.
I have generated the views, adjusted the screen (i.e. the extra field shows up) and updated the routes as follows:
devise_for :users, :controllers => { :sessions=>"sessions", :registrations => "registrations" }, :path => "users", :path_names => { :sign_in => "login", :sign_out => "logout", :sign_up => "register" }
Not to forget, I created a session controller:
class SessionsController < Devise::SessionsController
def create
begin
if do_some_other_checks
super
else
build_resource
clean_up_passwords(resource)
flash[:alert] = "Login error"
render :new
end
rescue => e
build_resource
clean_up_passwords(resource)
flash[:alert] = "Login error"
render :new
end
end
end
Unfortunately the code doesn't quite work, it gets called after Devise has the user logged on, i.e. even if the additional check fails, the user still gets logged in.
There is a simple way to do this in your user model by adding in the following, no need to create any devise controllers or change default routes ...
class User < ActiveRecord::Base
# check to see if a user is active or not and deny login if not
def active_for_authentication?
super && do_some_other_checks
end
end
What is the rails way, to create seperate actions for get or post?
Is it possible to have the same name but decorate the action to only run if its a get or post?
e.g.
'get only'
def forgot_password
end
'post only'
def forgot_passord
end
Rails way is to have a resource -- Each method should have a responsibility.
resources :password_resets
And then you'll let a user reset their password by visiting the form:
link_to 'Lost your Password?', new_password_reset_path
And then the form will post to create a new password_reset... That will send an email with a link to show the password_reset.
form_tag(password_resets_path, :method=>:post) do
When the use enters their updated password, it will update the password_reset.
# in routes.rb
resources :password_resets
# in app/controllers/password_resets.rb
class PasswordResets < ApplicationController
def new
#user = current_user
# render new reset form
end
def create
#user = current_user
#new_password = User.generate_random_password
if #user.update_attributes(:password => #new_password)
UserMailer.password_reset(#new_password).deliver
flash[:notice] = 'Successfully reset your password, check your email!'
else
flash[:error] = 'Could not reset password'
end
redirect_to login_path
end
end
Name them differently and create two routes in config/routes.rb. If you really really want one action doing different things, which is not a great idea, check request.method or request.get?, request.post?, etc.
you can rename the actions in your controller
#get only
def get_forgot_password
end
#post only
def post_forgot_passord
end
and then on your routes.rb
match '/forgot_password' => 'pass_reset#get_forgot_password', :via => 'get'
match '/forgot_password' => 'pass_reset#post_forgot_password', :via => 'post'
the :via option do the trick.