ruby on rails redirecting to old param - ruby-on-rails

I have an option for a user to update their username in their profile. However, when the url for their profile has been set as localhost/user/username and when they submit their changes, they are redirected to their old username (not the new updated one).
Here is my update from users_controller.rb
Any suggestions?
def update
#user = User.find_by_username(params[:id])
#page_title = "Edit Profile"
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(user_url,
:notice => "Your profile has been saved.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors,
:status => :unprocessable_entity }
end
end
end
also, I'm using
def to_param
username
end

Doesn't user_url take #user as an argument? How have you defined your route for that?
One thing I can think of immediately is #user.reload!.

Related

Rails getting No route matches [PUT] "/manage_users"

I have a rails app with a page for a user to edit their own profile
app/views/manage_users/edit.html.erb and app/views/manage_users/new.html.erb contain:
<%= render 'form' %>
app/views/manage_users/_formt.html.erb contains:
<%= form_for(#user, :as => :user, :url => {:action => #form_action, :id => #user.id}) do |f| %>
When I fire up the page http://localhost:3000/manage_users/2/edit it shows me a typical form to edit a user object's data. If i blank out the email address http://snag.gy/atnmV.jpg and submit the form, I get an error that I would expect http://snag.gy/NRfwn.jpg and the url is now http://localhost:3000/manage_users/2:
Started PUT "/manage_users/2" for 127.0.0.1 at 2014-01-25 21:01:45 -0600
Processing by ManageUsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"B44/1b5m8usyAfe0hzLHNyjk/7Fpn5iEu3u6wGJMGL0=", "user"=>{"user_details_attributes"=>{"first_name"=>"Jeff", "last_name"=>"Smith", "id"=>"2"}, "email"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "button"=>"", "id"=>"2"}
If i put the email address back in and submit the form, the url now points to http://localhost:3000/manage_users?id=2 and I get the error No route matches [PUT] "/manage_users"
Why is it doing this and how can I fix it. If i just go to the initial page to edit a user and save it right away (instead of blanking out the email), everything works just fine.
app/controllers/manage_users_controller.rb
class ManageUsersController < ApplicationController
before_filter :admin_only, :except => [:edit, :update]
# GET /manage_users
# GET /manage_users.json
def index
#users = User.active
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /manage_users/new
# GET /manage_users/new.json
def new
#user = User.new
#user.build_user_details
#form_action = 'create'
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /manage_users/1/edit
def edit
#user = User.find(params[:id])
#permissions_disabled = params[:id].to_i == current_user.id.to_i
#p #permissions_disabled
able_to_edit_profile?
session[:return_to] ||= request.referer
#form_action = 'update'
end
# POST /manage_users
# POST /manage_users.json
def create
#user = User.new(params[:user])
#p "in create"
respond_to do |format|
if #user.save
format.html {
flash[:notice] = 'User was successfully created.'
redirect_to(:action => :index)
}
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new", notice: 'Error creating user.' }
format.json { render json: #user, status: :unprocessable_entity }
end
end
end
# PUT /manage_users/1
def update
#user = User.find(params[:id])
able_to_edit_profile?
# required for settings form to submit when password is left blank
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])
#user.save
# sign the user in with their new password so it doesn't redirect to the login screen
if current_user == #user
sign_in #user, :bypass => true
end
format.html {
p "in success format.html"
flash[:notice] = 'User was successfully updated.'
redirect_to session.delete(:return_to)
}
else
p "in else"
format.html { render action: "edit", notice: 'Error updating user.' }
#format.html {
#flash[:notice] = #user.errors
# redirect_to edit_manage_user_path(#user)
#}
end
end
end
private
# If the user is not an admin and trying to edit someone else's profile, redirect them
def able_to_edit_profile?
if !current_user.try(:admin?) && current_user.id != #user.id
flash[:alert] = "That area is for administrators only."
redirect_to :root
end
end
end
EDIT
So by changing this:
format.html { render action: "edit", notice: 'Error updating user.' }
to:
format.html {
flash[:notice] = #user.errors.full_messages.to_sentence
redirect_to edit_manage_user_path(#user)
}
I'm able to circumvent the issue. I'm still curious as to why rendering 'edit' doesn't work after a failed update.
When you render the edit action from the update method (in the failure path), it doesn't run the edit method, so #form_action is nil when you render the form. You'll need to address that.
I usually don't need to set the url, only in rare cases do I. You may be able to leave that out and let rails take care of the url and HTTP method.

How do I display error messages in the same URL as the form URL in Rails forms?

(I've broken out the 2nd question that originally was part of this post into a separate post)
I am creating a product landing page with Rails in which users can enter their email address to be notified when the product launches. (Yes, there are services/gems etc that could do this for me, but I am new to programming and want to build it myself to learn rails.)
On submit of the form, if there are errors, the app currently redirects to '/invites' I would like to instead display error messages on the same page/URL as the original form? (In my case, the form is located at root while the error messages are displaying at '/invites')
I have read the Rails Guide on Routes and numerous stackoverflow posts on handling form errors nothing I've found seems to answer the question I have.
Update: Based on the reply from #rovermicrover I would like to clarify that, while I'm open to an Ajax solution, I'm fine with a page refresh that displays the error message. (I was not able to get the recommendation by #rovermicrover to function as desired - see my response to that solution below for more details.)
What I did:
Invite model:
class Invite < ActiveRecord::Base
attr_accessible :email
validates :email, :presence => {:message => "Please enter an email address."}
end
My routes file:
SuggestionBoxApp::Application.routes.draw do
root to: 'invites#new'
resources :invites
end
This is what I have in the Invites controller (I've only included the actions I'm referencing: new, create, show - it's basically the default of what Rails might generate):
class InvitesController < ApplicationController
def show
#invite = Invite.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #invite }
end
end
def new
#invite = Invite.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end
end
Please let me know if there is any additional info I can provide in helping to answer this question. Thanks!
Make the form 'remote'
form_for #invite, :remote => true
....
Then in the controller
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
format.html { redirect_to #invite }
format.js { render :action => 'create_suc'}
else
format.html { render action: "new" }
format.js { render :action => 'create_fail' }
end
end
end
/invites/create_suc.js.erb
$('#errors').remove()
$('#new_invite').prepend("<div class='Thanks'>Thanks for signing up</div>")
$('#new_invite').hide("")
/invites/create_fail.js.erb
$('#new_invite').html('<%= escape_javascript render("form", :invite => #invite) %>');
Forms is a partial with your.... form in it, and also the handling of all errors on #invite.
There is a way to do this without resorting the making the form submit "remote", from a pure Ruby on Rails perspective. However, you can do this only if the browser has enabled cookies.
The idea is to save the form data in the session information in case of an error.
Just remember to delete the session data in case of success.
def new
#invite = Invite.new(session[:invite])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #invite }
end
end
def create
#invite = Invite.new(params[:invite])
respond_to do |format|
if #invite.save
session.delete(:invite)
format.html { redirect_to #invite }
format.json { render json: #invite, status: :created, location: #invite }
else
session[:invite] = params[:invite]
format.html { render action: "new" }
format.json { render json: #invite.errors, status: :unprocessable_entity }
end
end
end

rails devise sign_in doesn't work on redirect

I have this method:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if params[:mypmnode]
session[:return_to] = projects_pmnode_path(params[:mypmnode])
sign_in(#user)
end
format.html { redirect_to(session[:return_to], :notice => 'User was successfully updated.') }
format.xml { head :ok }
else
#create_company = true if params[:user][:company_id].blank? and params[:user][:company_attributes].length > 0
#create_department = true if params[:user][:department_id].blank? and params[:user][:department_attributes].length > 0
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
The idea is that if the user is updated, He is automatically signed-in and redirected to a page where authentication is required.
In this page, I have: before_filter :authenticate_user!
This doesn't work on redirect.
If I then go to another page making use of this sign_in function, then the user logs-in correctly.
Any idea why redirect doesn't work? Thx!
UPDATE:
to make it clearer, I insert the second page code (controller):
class PmnodesController < Projects::BaseController
before_filter authenticate_user!
def index
#pmnodes = Pmnode.all
respond_to do |format|
format.html
end
end
If the password is updated on #user, devise will invalidate the session. After the update_attributes, you could try calling sign_out first.
sign_out(#user)
sign_in(#user)
Are you sure that your progam goes inside this blog
if params[:mypmnode]
session[:return_to] = projects_pmnode_path(params[:mypmnode])
sign_in(#user)
end
if not this should sign in your use automatically.
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if params[:mypmnode]
session[:return_to] = projects_pmnode_path(params[:mypmnode])
end
sign_in(#user)
format.html { redirect_to(session[:return_to], :notice => 'User was successfully updated.') }
format.xml { head :ok }
else
#create_company = true if params[:user][:company_id].blank? and params[:user][:company_attributes].length > 0
#create_department = true if params[:user][:department_id].blank? and params[:user][:department_attributes].length > 0
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
I had a similar problem:
I had a controller method that created and signed in a user
def new
#user = User.create!
sign_in #user
redirect_to some_nondefault_path
end
where some_nondefault_path required authentication. The new action did not require authentication. The user was getting created and signed in, but the user session wasn't persisting and the user was getting 401-unauthorized and redirected to the signin page instead of some_nondefault_path.
I ended up solving it by adding
skip_before_filter :verify_authenticity_token, :only => :new
to the first controller. It seemed to be trying to verify the CSRF token before creating the user session, which was failing and blocking the creation of a normal user session (even though it wasn't trying to authenticate_user!).
Hope this helps!

Difference between these two create methods in a users controller

Is there a difference between
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render :new
end
end
and
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to(:users, :notice => 'Registration successfull. Check your email for activation instructions.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
Ignore the error and notice issues, my main question is the difference between using xml format and not using it, they seem to do the exact thing.
Using respond_to with different format than html give you the ability to have the response in the specified format (useful for web-service).
In that case (User creation) I don't think it is really useful, but it's all up to you!
Not using respond_to like your first exemple will simply render html.
More infos about respond_to here:
http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to

Authenticating a User In a Separate Controller with Restful_authentication

I am trying to make it possible for users to login as quick as possible, so I want users to be able to login and create records in the same form.
Is it possible to authenticate a user with the restful_authentication plugin from any controller by somehow calling the create method in the session controller, and return the authenticated user? It seems like this could be done easily somehow, but I just can't figure out how to do it in Rails.
Maybe something like:
#Records Controller
def create
if params[:login] && params[:password]
#This method would call /session/ and pass the login/password params
user = authenticate_user(params[:login'], params[:password])
end
#record = Record.new(params[:record])
#record.user = user
if #question.save && user
flash[:notice] = 'Record was successfully created.'
redirect_to(#record)
end
end
Any ideas on how to do this would be appreciated!
I've tested this code on Rails 2.3.4 and it works; the user remains logged in. Bear in mind that you should try to refactor so that the authentication code lives in a single place, rather than having it duplicated in several controllers.
Note also that the authentication code in this snippet is a simplified version of that in the Sessions controller, & so doesn't handle any of the 'remember me' functionality.
# POST /stacks
# POST /stacks.xml
def create
#stack = Stack.new(params[:stack])
if params[:login] && params[:password]
logout_keeping_session!
user = User.authenticate(params[:login], params[:password])
self.current_user = user
end
respond_to do |format|
if !user
flash[:error] = 'Login details incorrect.'
format.html { render :action => "new" }
format.xml { render :xml => #stack.errors, :status => :unprocessable_entity }
elsif #stack.save
flash[:notice] = 'Stack was successfully created.'
format.html { redirect_to(#stack) }
format.xml { render :xml => #stack, :status => :created, :location => #stack }
else
format.html { render :action => "new" }
format.xml { render :xml => #stack.errors, :status => :unprocessable_entity }
end
end
end

Resources