No action respond to id in rails routing problem - ruby-on-rails

I am adding a functionality of resetting password in my rails application
In my users page , i have all the users listing
If i am logging in as a admin below the users a link to reset password to users are available which will set a default password to them
<%= link_to "Reset Password",reset_password_user_path %>
In my controller users
def reset_password
#user = params[:user]
puts "which user #{#user}"
#user.password = "12345"
if #user.save
flash[:notice] = "Password successfully reseted"
redirect_to user_path
else
flash[:error]= "Password not reste!"
redirect_to user_path
end
end
In my routes
map.resources :users, :member => {:reset_password => :post}
When i run my users page , i am getting the error as below
reset_password_user_url failed to generate from {:action=>"reset_password", :controller=>"users"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["users", :id, "reset_password"] - are they all satisfied?
WHen i gave the link as
<%= link_to "Reset Password",reset_password_user_path(user) %>
then i am getting the error as No action respond to 2
Processing UsersController#2 (for 127.0.0.1 at 2011-03-14 11:38:33) [GET]
Parameters: {"action"=>"2", "id"=>"reset_password", "controller"=>"users"}
How to resolve this..

Alternatively <%= link_to "Reset Password", reset_password_user_path(user), :method => "post" %> assuming you have Prototype or jQuery.
This way you are still posting to the action as it makes changes to the user.

Try with get method instead of post in routes.

Related

Rspec not testing passing tests in regards to redirect

I am in a bootcamp and I cannot seem to pass this test. The project is creating your bootleg version of twitter and the test is:
it 'signup directs user to twitter index' do
params = {
:username => "skittles123",
:email => "skittles#aol.com",
:password => "rainbows"
}
post '/signup', params
expect(last_response.location).to include("/tweets")
end
My controller that handles this test is below:
post '/users' do
#user = User.create(params[:user])
#error = #user.errors.full_messages
unless #error == []
redirect to '/signup'
else
session[:user_id] = #user.id
redirect to '/tweets'
end
end
Basically what happens is that when I register a user and the data persists into the database my test should pass cause the expected last_response.location is to include '/tweets' and that is where
it redirects to. I don't understand why it's not passing.
Because the test was asking for post /signup and instead of using /signup as the route method name after the user posted the information to create the account I used /users. This caused the error.

Browser URL changes after http post fail

I have a login page on which the authentication can be successful or not. Here is the page new.html.erb:
<%=form_with scope: :session, url: sessions_path, local: true, html: {class: "login-form"} do |f| %>
<%= f.label :email, t("session.new.email") %>
<%= f.email_field :email %>
<%= f.label :password, t("session.new.password") %>
<%= f.password_field :password %>
<%= f.submit t('session.new.login'), class: "submit" %>
<% end %>
It is associated to a sessions_controller.rb, which is the following:
class SessionsController < ApplicationController
def create
# Find the user with the matching email
user = User.find_by(email: params[:session][:email].downcase)
# Check the user exists in DB and that the provided password matches
if user && user.authenticate(params[:session][:password])
# Log the user through the session helper
log_in user
# Redirect to the hive
redirect_to ideas_path
else
# The authentication failed. Display an error message
flash.now[:error] = I18n.t('session.new.invalid_credentials')
# The render is done to reinitiate the page
render :new
end
end
end
In my routes.rb, I just have for this purpose:
resources :sessions
When executing rails routes, I have the following declared routes:
Now my problem is on the login fail. In my controller, in this case, I add a message in the flash messages and then re-render the same page new.html.erb. But in the browser, the login request POST has been sent on the url /sessions. The problem is the current URL on my browser becomes /sessions instead of staying on /sessions/new. This is as if the POST request changed the URL in my browser. But this is in fact just an AJAX request, isn't it?
I have found this blog post that wonders the same about this phenomenon (I'm not the author)
I have found a workaround, but I'd prefer avoid using it and understand the bevahior. If i replace my routes by the following, this works:
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
I can understand why this works: the get and post url are the same, so the browser doesn't change its URL.
Have you any idea?
EDIT:
I finally found a solution. I'm not sure this is the "rails way", but this works as expected. I have just changed the controller to do a redirection to the same page, with a flash request to transmit the login fail information:
def create
# Find the user with the matching email
user = User.find_by(email: params[:session][:email].downcase)
# Check the user exists in DB and that the provided password matches
if user && user.authenticate(params[:session][:password])
# Log the user through the session helper
log_in user
# Redirect to the hive
redirect_to ideas_path
else
# The authentication failed. Display an error message through a flash
# message after redirect to the same page
redirect_to new_session_path, alert: I18n.t('session.new.invalid_credentials')
end
end
When the form gets submitted the browser performs a regular HTTP POST requsest to the /sessions endpoint. No AJAX there.
The way your routes are configured this POST request will be handled by your sessions#create action.
Notice the code there. You'll see that the happy path (successful login) calls redirect_to. In case of login errors though, the controller calls render.
The difference is that in the first case the response is a 302 Redirect which the browser follows. That's why you see the URL changing in the browser. In the second case the response is just 200 OK with a bunch of HTML for the browser to render. The URL won't change because the browser wasn't instructed to navigate elsewhere.
Here's an extensive explanation of how redirects work in the browser in case you're interested.

How to use custom view to update user via devise? (rails gem)

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'

Can't confirm account for subdomain. Using Devise confirmable and Rails 4

I'm using Rails 4, subdomains with Apartment gem, and Devise (3.4.1). I have a problem with the email confirmation link generated by Devise Confirmable. When a user creates an account, they get an email:
You can confirm your account email through the link below:
http://lvh.me:3000/users/confirmation?confirmation_token=xsTNUw5oQYTPf_CBwZXD
However, it doesn't work since the user's subdomain is not on the link, it should be e.g.
http://mysubdomain.lvh.me:3000/users/confirmation?confirmation_token=xsTNUw5oQYTPf_CBwZXD
If I manually add the subdomain link on the browser, it does confirm the account.
How could I change the confirmation_instructions.html.erb link_to to generate a confirmation_url with the subdomain in front of it? For example:
<p>Welcome <%= #email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token, :subdomain => #resource.subdomain) %></p>
I tried e.g. https://github.com/plataformatec/devise/wiki/How-To:-Send-emails-from-subdomains and https://github.com/fortuity/rails3-subdomain-devise/wiki/Tutorial-%28Walkthrough%29 But neither worked for me, I got an error:
"NoMethodError in Accounts#create, undefined method `subdomain' for #<User:0x...>"
Here is the create action in my AccountsController:
def create
#account = Account.new(account_params)
if #account.valid? && verify_recaptcha
Apartment::Tenant.create(#account.subdomain)
Apartment::Tenant.switch(#account.subdomain)
#account.save
#account.create_default_lists
redirect_to new_user_session_url(subdomain: #account.subdomain)
else
render action: 'new'
end
end
Here are my routes:
user_confirmation POST /users/confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new
GET /users/confirmation(.:format) devise/confirmations#show
In development.rb I have set:
config.action_mailer.default_url_options = { host: "lvh.me:3000" }
In ApplicationController I have:
protect_from_forgery
before_filter :authenticate_user!, :set_mailer_host
private
def current_account
#current_account ||= Account.find_by(subdomain: request.subdomain)
end
helper_method :current_account
def set_mailer_host
subdomain = current_account ? "#{current_account.subdomain}." : ""
ActionMailer::Base.default_url_options[:host] = "#{subdomain}lvh.me:3000"
end
end
And here is the error on the console:
ActionView::Template::Error (undefined method `subdomain' for #<User:0x007fbfcc27e5a0>):
2:
3: <p>You can confirm your account email through the link below:</p>
4:
5: <p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token, **:subdomain => #resource.subdomain**) %></p>
app/views/devise/mailer/confirmation_instructions.html.erb:5:in `_app_views_devise_mailer_confirmation_instructions_html_erb___2999600516167812245_702'
app/controllers/accounts_controller.rb:14:in `create'
I managed to solve this by using the following in confirmation_instructions.html.erb. This works for my setup, since I'm using the Apartment gem:
<%= link_to 'Confirm my account', user_confirmation_url(confirmation_token: #token, subdomain: Apartment::Tenant.current) %>
Did you confirm that in your link_to, the :subdomain => #resource.subdomain part actually has a legit value? In other words, that your "resource" (probably User model) has a subdomain method?

RESTful way of updating a model from different view

My application has a User model.
In the home#index view, I present a form for the current User to update their email address, using form_for.
Now if my application is to remain RESTful, as I understand it the Haml in app/views/home/index.html.haml should look something like:
- form_for current_user, :url => { :action => "update", :controller => "user" } do |f|
= f.text_field :email
= f.submit "Update email address"
My question is as follows: what is the correct way to get the User model to redirect to the home#index view after the update?
You can give redirect to your format.html on your controller def update, like
format.html { redirect to :back }
this will redirect to the page that send request before.
That's the simplest way..!
In this case I actually reverted to using resourceful routes... far cleaner.
Thanks for the other suggestions.

Resources