Is it possible in Rails to check whether a redirect or render had already been issued?
You can call performed?
in your controller to check if render
or redirect_to
has been called already:
performed? # => false
redirect_to(login_path)
performed? # => true
Read more about performed?
in the Rails docs.
How can I determine whether a controller action has rendered (rather than redirected?)
Look at @performed_render
. :) You don't explain why you need to detect this, so I am unable to suggest alternative solutions.
How do I check if a controller action is already redirecting?
I am assuming that the login_required method performs a redirect if the user is not logged in. In which case:
Your before filter should return false after calling redirect. This will prevent the new action from ever being called. Later versions of rails automatically do this if you call render or redirect in a before_filter, so maybe you are using an older version.
Also you should return after the call to redirect in the new handler, unless you want to always create a new Payment object.
Detect in Rails after_filter whether we're rendering or redirecting
You could look at the status
code. 200 is a render, 302 is a redirect.
after_filter :what_happened
protected
def what_happened
was_redirect = self.status == 302
was_render = self.status == 200
end
Testing requests that have redirects in RSpec
You can check that a post was created and that a user was redirected, if params are valid. And if you have any validation in the Post model, it is good idea to test invalid params:
RSpec.describe 'PostsController', type: :request do
describe 'POST #create' do
context 'with valid params' do
it 'creates a new post' do
expect { post posts_path, params: { post: valid_attributes } }.to change(Post, :count).by(1)
expect(response).to redirect_to post_path(Post.last)
end
end
context 'with invalid params' do
it 'does not create a new post' do
expect { post posts_path, params: { post: invalid_attributes } }.not_to change(Post, :count)
expect(response).to have_http_status 200
end
end
end
end
how to check whether newly entering value is already present in database or not in rails
You can simply do it as,
image_present? = MImage.where(image_name: params[:image_name]).present?
Mostly Rails-uniqueness validation is used in model to add error if attribute already present for another object
Ruby on Rails 5 - Resource gives error when checking if it already exists - whether it does or not
Your conditional is checking the wrong thing. This:
if @product.product_code.present?
only checks if product_code
is present in the @product
you just made, it does't check if there's anything already in the database with that product code.
I think you want something more like this:
@existing_product = Product.find_by(product_code: @product.product_code)
if @existing_product
flash.now[:error] = ...
render 'new'
elsif @product.save
redirect_to @product
else
render 'new'
end
You can use find_by
to find the thing you're looking for, that will either give you the product or nil
if there isn't a matching product.
You might want to look into a couple other things:
- Using the URL helper rather than manually building a link would be better.
- Your model should be checking the uniqueness of the product codes rather than the controller.
- As Dorian mentions in the comments, HTML in the flash messages isn't the best idea. You'd be better off checking
@existing_product
in the view and then putting up the link and whatever "complex" error message you need entirely within the view.
How do I check to see if a user will be redirected to his/her profile after login (Rails Tutorial Ch. 9)?
I'm way late in answering this question, so it might be a moot point now, but I'm working on this exercise in the tutorial right now myself and had to struggle to come up with the correct answer, but I finally did. So I thought I'd share what I did to get the tests to pass in case you're still seeking an answer. First I'll point out where the flaw in your current logic is (because I made the same mistake initially and had to process the logic flow of the code to figure out what went wrong).
In your test, you're testing for equality between with assert_equal session[:forwarding_url], user_path(@user)
. The problem is, the user's user_path
is never set as the forwarding url. In the sessions_helper.rb
file, the redirect_back_or()
method has this line: redirect_to(session[:forwarding_url] || default)
(the default
argument passed to this method is user
when it's called in the create action of the sessions controller). So this line in the redirect_back_or()
method can be read in plain English as
Redirect to the forwarding url if one has been set by the
store_session
method. If the forwarding url is nil, redirect to the default page, which in this case is the user page.
In order to test for equality as you're trying to do (and as I initially tried), it requires that at some point user_path(@user)
or user
would have to be set as the session's forwarding url. store_session
takes no parameters to do this, so the only way user_path(@user) could be set as the forwarding url is if an unauthorized user were attempting to access that page and were first forced to log in then be redirected there (as best I can tell, this text does not require a person to be logged in to view a single user's page). So, user_path(@user)
would never conceivably be set as the forwarding url in the store_session
method, and thusly, assert_equal session[:forwarding_url], user_path(@user)
would never evaluate to true.
At this point, the error message you cited in your original question is extremely helpful in solving your problem.
Expected: nil
Actual: "/users/762146111"
If you recall from the early chapters of Hartl's text (or from the Rails API) assert_equal tests take two required parameters: the expected value and the actual value and then compare the two. This is reflected in your error message: session[:forwarding_url]
evaluates to nil
while user_path(@user)
evaluates to a specific user's url. Since, like I stated earlier, the user's profile page should never conceivably be set as the forwarding url, we can eliminate user_path(@user)
entirely from our test.
Fortunately for us, the exercise in the textbook doesn't require that we user assert_equal
to get the correct result. We just need to test that session[:forwarding_url]
has the right value. That should be pretty easy. Let me walk through it step by step:
- User is not logged in and trying to access a page served via the index, edit, update, or destroy controller actions.
- Before filter catches this and runs the
logged_in_user
method.unless logged_in?
evaluates to false, so the code in this method is run. - store_location is called inside
logged_in_user
and the unauthorized user'sget
request is stored as the forwarding url. Simultaneously, the user is redirected to the log in page. - Assuming the user enters valid credentials to successfully log in, this calls the session controller's
create
method, to create a new session. This action logs the user in and callsredirect_back_or()
. redirect_back_or()
checks to see ifsession[:forwarding_url]
has a value associated with it -- we know it was becausestore_location
assigned a value to this key in step #3. So the first half ofredirect_back_or()
's || statement is executed and the now-authenticated user gets redirected to the page they were initially trying to access before they logged in.redirect_back_or()
then deletes the value associated with the forwarding url, since the user has been redirected there already.- Now we try to log in again, this time by directly accessing the log-in page. This happens successfully, and the session controller's create action is called again.
- This time, we weren't trying to access a page we didn't have authorization to access, so the store_session method never gets called. Therefore, the forwarding_url is currently nil.
- When the session is created and
redirect_back_or()
gets called,session[:forwarding_url]
evaluates to nil, so the second half of the || statement gets executed, namelyredirect_to user
(sinceuser
is the parameter passed to the method as its default).
To summarize, the correct value of session[:forwarding_url]
for subsequent login attempts should be nil. You can write this test one of two ways:
- You can still use
assert_equal
to test for equality:assert_equal session[:forwarding_url], nil
- You can refactor your test to be more succinct and direct:
assert_nil session[:forwarding_url]
I prefer test #2, but I tested them both and it worked just fine both ways.
Though not explicitly required in the original exercise, I also added a test after this one to ensure all subsequent redirects are sent to the user_path(@user)
:
assert_nil session[:forwarding_url]
assert_redirected_to @user
TL;DR: session[:forwarding_url]
will never equal user_path(@user)
. If it hasn't been stored with store_location
(which is the case with all subsequent login attempts), it will evaluate to nil
, so a passing test for this exercise must be written one of two ways:
assert_nil session[:forwarding_url]
OR
assert_equal session[:forwarding_url], nil
How to use Rails instance public method performed? in if-else
In a controller action, when we type render
or redirect_to
those are not immediately executed, but they are queued and will be executed after the completion of the method. So this allows to have double renders or redirect_to in a controller action, and this will generate an error (because then rails has no idea which to execute). So that is why in rails they have added a method performed?
which will indicate if a render
or redirect_to
has already been called (queued) or not.
In most cases this is not really needed because normally your controller code is pretty simple.
To clarify: performed?
does not actually test the redirect_to
has been done, it just tests a render or redirect-to was called/queued. Furthermore the redirect_to
does not return a boolean indicating whether it was done or not.
So your code should be like this:
if condition
does something
else
redirect_to(records_path)
end
if performed?
# the redirect-to was executed
does another thing # but not a render or redirect
else
yet another thing
# and could be a render or redirect
# if not the normal view will be rendered
end
Please not that in this simple example the performed?
is just the negative of condition
so you could easily squash those together.
Related Topics
Use Sudo for Gem Install Cocoapods
Why Can't I Install SASS on MAC Os Sierra
Ruby on Rails: /Bin/Sh: Rspec: Command Not Found
Ruby Symbols VS Strings in Hashes
How to Find a Devise User by It's Session Id
How to Assert Certain Method Is Called with Ruby Minitest Framework
Change Default Capybara Browser Window Size
Is It Possible in Rails to Check Whether a Redirect or Render Had Already Been Issued
What Is the Activemodel Method Attribute "_Was" Used For
How to Route Controllers Without Crud Actions
Getting the Full Rspec Test Name from Within a Before(:Each) Block
Ruby Regex - Gsub Only Captured Group
What's the Difference Between Bundle.Setup and Bundle.Require