I have a Rails 3.2 app that uses session store in the controllers to get the user back to the screen they were previously on.
It's been working fine for over a year. All of a sudden, the production version on Heroku, has started having issues. The user is looking at a worequest and clicks on the following in order to add a comment.
<%= link_to 'New Comment', new_comment_path(:worequest_id => #worequest.id), :class => 'btn btn-primary' %>
This is the code I use:
def new
#comment = Comment.new
#comment.build_attachment
#worequest = params[:worequest_id]
session[:return_to] ||= request.referer
respond_to do |format|
format.html # new.html.erb
format.json { render json: #comment }
end
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(params[:comment])
respond_to do |format|
if #comment.save
if session[:return_to] != nil
format.html { redirect_to session.delete(:return_to), notice: 'Comment was successfully created.' }
format.json { render json: #comment, comment: :created, location: #comment }
else
format.html { redirect_to :back, notice: 'Comment was successfully created.' }
format.json { render json: #comment, comment: :created, location: #comment }
end
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
In development and staging (on Heroku), the user goes back to the worequest after entering a new comment.
Now in Production, the url looks like this:
mywebsite/comments instead of mywebsite/worequests/639
I'm not even sure where the session[:return_to] gets stored. Therefore, I'm having trouble debugging the issue.
Thanks for your help!!
Are you able to replicate this behavior 100% of the time, or just seeing it sometimes in your log?
It looks like someone is getting to comments#new from /comments (comments#index). Is there a route to /comments?
Run rake routes to see all your routes.
If there is a route to comments#index, and there's no reason for it to be exposed because you only intend for people to post comments from within the context of a specific article, consider removing it the comments#index route.
Also, one thing to consider, request.referrer is not always available. It's sent by the client who may choose not to send it (e.g. certain privacy extensions remove this header).
Related
I am using Rails 5 and I am trying to use this redirect_back method.
However, my issue is that I am using it for a Comment#Create which can be called for both a Question & Answer object. So depending on which it is, I want it to redirect back to that respective object (which have two different routing paths ofcourse).
So, what I have done is created a concern, added a custom method and then attempted to call that method in the redirect_back call but it doesn't seem to be working.
The concern looks like this:
module CommentRedirect
extend ActiveSupport::Concern
def question_or_answer(comment)
if comment.commentable_type.eql? "Question"
question_path(comment.commentable)
elsif comment.commentable_type.eql "Answer"
question_path(comment.commentable.question)
end
end
end
Then my Comment#Create looks like this:
format.html { redirect_back(fallback_location: question_or_answer(#comment)), notice: 'Comment was successfully created.' }
The error I get is this:
SyntaxError at /comments
syntax error, unexpected ',', expecting '}'
... question_or_answer(#comment)), notice: 'Comment was success...
...
Given that this is the redirect_back code in Rails:
def redirect_back(fallback_location:, **args)
if referer = request.headers["Referer"]
redirect_to referer, **args
else
redirect_to fallback_location, **args
end
end
Can I use the helper method in the way I am attempting?
If not, how else can I achieve what I want to do?
Edit 1
This is the entire Comment#Create method:
def create
#comment = Comment.new(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.save
format.html { redirect_back(fallback_location: question_or_answer(#comment)), notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
I didn't notice right away either, but your line is not valid syntax:
format.html { redirect_back(fallback_location: question_or_answer(#comment)), notice: 'Comment was successfully created.' }
It should be this:
format.html { redirect_back(fallback_location: question_or_answer(#comment), notice: 'Comment was successfully created.') }
from the default scaffold generator I have the following create action in my blogs controller:
# POST /blogs
# POST /blogs.json
def create
#blog = Blog.new(params[:blog])
respond_to do |format|
if #blog.save
format.html { redirect_to #blog, notice: 'Blog was successfully created.' }
format.json { render json: #blog, status: :created, location: #blog }
else
format.html { render action: "new" }
format.json { render json: #blog.errors, status: :unprocessable_entity }
end
end
end
When the sent form contains errors, my browser is redirected to /blogs URL but in the page the new action is rendered.
This is really ugly in my opinion and (also to simplify my javascript) I would like the browser to remain in the same blogs/new URL.
I tried with changing redirect_to :new instead of render action: "new", but this of course loses the #blog data.
any clue on how to do this?
thanks,
If you want to keep new in your path you could redirect with params like so:
redirect_to new_blog_path(blog: params[:blog])
and then check for these params in blog#new
(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
I want my page to refresh once a record has been created, at the moment it directs it to the page before. here is the code from my controller:
def create
#license = License.new(params[:license])
respond_to do |format|
if #license.save
format.html { redirect_to :controller => 'customers', :action => 'index' }
format.json { render json: #customer, status: :created, location: #customer }
else
format.html { render action: "new" }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
where it says redirect_to i need that to refresh, or link to the current page, with the current id, which would be :controller => 'customers', :action => 'show' but with the id of the current page's record.
Try
redirect_to customer_path(#license.id)
instead.
Depending on what your routes.rb file says, it should work.
But if it doesn't, try:
redirect_to show_customer_path(#license.id)
However, here I have to assume that somehow, your customers_controller.rb is somehow showing records from the License model. If License and Customer are separate models, you will have to find the customer_id in some other way.
Perhaps, it is:
redirect_to customer_path(#license.customer_id)
If License is not connected to Customer in any way, you will need to pass it in as part of the post request.
Try,
I think you are passing customer_id to on params(Licensee belongs to customer), if so then
redirect_to customer_path(#license.customer) or redirect_to customer_path(params[:customer_id])
What's the difference between respond_to and respond_with ?
What do they do?
Can anyone post example with the screenshot of output?
Thanks.
There is a pretty complete answer here. Essentially respond_with does the same thing as respond_to but makes your code a bit cleaner. It is only available in rails 3 I think
Both respond_to and respond_with does the same work, but respond_with tends to make code a bit simple,
Here in this example,
def create
#task = Task.new(task_params)
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render :show, status: :created, location: #task }
else
format.html { render :new }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
The same code using respond_with ,
def create
#task = Task.new(task_params)
flash[:notice] = "Task was successfully created." if #task.save
respond_with(#task)
end
also you need to mention the formats in your controller as:
respond_to :html,:json,:xml
When we pass #taskto respond_with, it will actually check if the object is valid? first. If the object is not valid, then it will call render :new when in a create or render :edit when in an update.
If the object is valid, it will automatically redirect to the show action for that object.
Maybe you would rather redirect to the index after successful creation. You can override the redirect by adding the :location option to respond_with:
def create
#task = Task.new(task_params)
flash[:notice] = #task.save ? "Your task was created." : "Task failed to save."
respond_with #task, location: task_path
end
For more information visit this Blog