I'm using Capybara to test a Rails app using RSpec. Calling visit "/bars" correctly takes me to the index page for the bars resource. But calling visit "/bars/1" (where a bar has been saved with id 1) mysteriously takes me to the index page as well, even though typing in the URL by hand works just fine.
The index page even has links to specific bars pages (like "/bars/1"), and while those links work perfectly in the browser, Capybara's click_link on those links takes me instead back to—you guessed it—the index page.
In both of these cases, the show method in the bars controller never even gets called when using Capybara, though it is called when I'm clicking around in the browser.
Does anyone have any idea what's going on?
If you have "saved it to db' and can view it in browser, it is development db. Capybara deals with test db which you probably don't have record there.
While you don't have such record and you may set 404 redirect to home, such result in Capybara is expected.
Another note, it's not good to use named id say 1 in test. There is no guarantee your last inserted record must be id 1. Better to use bars_path #bar or bars_path Bar.last
Related
I have searched around the web and there are answers that have helped me abit, however I am still stuck, so here goes.
I a Rails 4 app that allows users to create a biography/blog and then access it using their own domain.
Users can choose from several pre-made website templates (main page, about me page, my hobbies page, etc...), and then they load up their content using a CMS. The content will then be displayed using their chosen template when visitors visit their domain.
Eg:
User 1:
Domain: www.user1.com
Template: Template A
User 2:
Domain: www.user2.com
Template: Template B
Desired Results
When a visitor visits www.user1.com, they will see the main page. When they click on "About Me", they will be redirect to www.user1.com/about-me. If a visitor visits the "About Me" page for user 2, they will see www.user2.com/about-me.
My question here is, how do I set this up?
Based on this answer: Rails routing to handle multiple domains on single application
class Domain
def self.matches?(request)
request.domain.present? && request.domain != "mydomain.com"
end
end
------in routes.rb------
require 'subdomain'
constraints(Domain) do
match '/' => 'blogs#show'
end
I know I can route a different domain compared to mine to a separate controller, however, I need to route it to different template controllers which can change at any moment (users can change templates at will).
I know I can set up a general controller that can read incoming requests, then based on the hostname, I can extract the appropriate template and then redirect the request to that template's controller (eg: Template1Controller), however the url gets messed up, becoming something like "/template/template1/index" or "/template/template1/about-me" which is very bad and ugly. Furthermore, it will be extremely tricky to handle paths specific to only some templates (Template A might have a "My Resume" page while template B might have a "Family History" page instead).
Is there a way to do this?
I have thought about a method where I have a single controller that will handle everything (without redirects) and then just calls render template1/index, but I think it is a bad way of doing it (different template might need different data in each page).
Btw, this will be hosted on EC2.
EDIT
What I am looking to implement is quite similar to this question Mapping multiple domain names to different resources in a Rails app , but unfortunately no answers then. Im hoping 5 years later, someone might know how to get this done.
Thanks!
I do this pretty simple with Heroku. It's probably not hard anywhere.
Once you have DNS set up.. the Rails layer can look like...
Create a before_filter in ApplicationController. before_filter :domain_check
In my domain_check method I just have if request.host ~= /whatever/ do this elsif ... elsif ... end
"do this" can be a redirect or a render or whatever.
In a 3.2.16 Rails app using Devise, we allow users to stay logged in for a number of days. This means, of course, that if they click a link to our page (say in their bookmarks) they come right back into the app (assuming their session is still active).
For our main screen, we have a yielding layout
...
<body>
...
<%= yield %>
...
</body>
The layout surrounding the yield includes a display of the username among other things.
And now I have a new controller:
class AccountSelectionsController < ApplicationController
def new
if user_signed_in?
sign_out current_user
current_user = nil
end
...
render :layout => "external"
end
...
end
When the new action is invoked, I want the user signed out completely, the session cleared, and the user taken to a completely different layout. The use-case assumes the user is reaching this controller from a link in, say, an email or a page outside my app (IOW, not from a spot inside my app).
I first thought I merely had do a sign_out current_user(as above), but that didn't do anything obvious: the user seems to stay signed in.
The above was just my starting point. I've tried just sign_out (without a resource, implying all scopes), reset session, and redirect_to destroy_user_session_path (which is what our standard logout button does, a button positioned on the surrounding layout).
What I got though was my new external view (or the normal new session sign in screen, depending on the permutation of what I tried) trying to render inside the old layout (as if it was part of the yield).
I could try the Devise after_sign_out_path_for to help with redirect, but then I'd only want it if it was tied to this particular controller and action and I'm not quite sure how to safely accomplish that. And now I'm not convinced it wouldn't just keep me wrapped in the surrounding layout anyway.
So, (1) is there a reason the main layout stays intact even upon a full redirect_to (even using :status => 301) that I should be able to defeat (for instance, is the yield interfering?), or (2) am I on the right track with Devise after_sign_out_path_for and what do I need to do to limit that behavior to just respond to this one controller action?
Thank you!
Richard
UPDATE: the served page (via view source) shows the intended screen body is wrapped within the layout of the origin screen
UPDATE 2: I've also tried returning a head :reset_content from a before filter along with various other things in a before_filter. Still the old layout keeps rendering before it attempts to render the new page. This is although I'm using different Chrome tabs in the test (i.e., the session stays in memory); I've tried it in Firefox too. Same result. The output of rails s shows the redirects and gives no indication that it's attempting to go through another controller first, something is triggering the layout. Is there away to force a layout in a redirect?
Try this instead,
sign_out current_user, :bypass => true
So this is my penance for posting the question.
I just figured out that a before_filter was intercepting the call to the controller and redirecting it to the wrong layout before a sign-in was ever checked for. Normally this is desired for this particular application, but I didn't realize that the filter actually was catching the redirect ahead of my controller (the logs suggested it happened at a later point). Once I set that filter to be skipped in my controller, all was well.
Moral of the story, I need to better consider the side effects of before_filters in the ApplicationController.
Thank you to RSB and Jasdeep Singh and everyone else who spent time considering an answer for this.
Check edit at bottom of page
My boss has a sitemap up- it's basically just every route as a link, with a button to click that says "valid?" or "ignore" which will mark it valid or ignore it on the page.
He asked me to manually go through and click each link, test that page isn't a 500 or 404, and then mark it valid if it isn't.
This seems silly to me, as it is basically just a user facing test for working routes.
I could, in the same time, write out routing specs in Rspec for all those, but I guess he wants some sort of documentation that this is happening on the front end for himself and users.
I was thinking a fun way to work around this boring clicking would be to do it with some programming WHILE writing the specs. Makes him happy, and also adds actual value and test to the app that can be reused.
Is there a way to, in a spec, write something like:
links = page.all('a.routing-links)
link.each do |link|
link.click
if page status != 404 || 500
Link.find(id).update_attribute("verified", true)
end
end
I tried putting that in my spec, but when link.click hits an incorrect route, it stops the test (which makes sense, as that route is broken and this is a test.
What I'd like is to be able to take that error and use it to update the attribute of my model.
Am I going about this completely wrong? Any better ideas or inspiration?
Thanks
Edit
I agree with the poster who said this is better left to a script or rake task.
I'm a bit lost on how to write a script that will go to a page, find every link, record its status_code, and then find and update a model. Any suggestions or tips? Ideally it would be run within in the application, so that I could have access to my models and controllers.
Thanks
Personally I wouldn't actually put this in a spec since you're not actually expecting anything to fail.
Instead I'd create a quick script, or even rake task to run through the links as you described.
That being said, this article: http://agileleague.com/2012/12/rails-3-2-custom-error-pages-the-exceptions_app-and-testing-with-capybara/ details how to bypass the normal fail in these circumstances, namely:
In your config/environments/test.rb
config.consider_all_requests_local = false
config.action_dispatch.show_exceptions = true
Though this would affect all tests, which is quite possibly not what you want.
Also, a minor thing that you'd probably figure out in no time when testing this - you'll either need to revisit the list page after clicking the link, or rather relying on link clicks, you could visit the href instead which would be a bit quicker.
links = page.all('a.routing-links')
link.each do |link|
visit link[:href]
if page.status != 404 || 500
Link.find(id).update_attribute("verified", true)
end
end
I haven't tested that, so not sure if it would work like that, but you should be able to get the idea.
I want to write tests for destroying objects on ruby on rails with cucumber and capybara and rack_test.
I think that I should write a scenario like:
When I try to delete X object
Then I should be on the index page for ...
And I should see "Object deleted successfully"
I don't want to test it by clicking on a link on the index page or the show/edit page because I think I should be testing something different than purely the delete action.
Also, clicking on a link means that the interface is ok, but what happens if someone send a request to delete an object he can't and the interface doesn't show the link?
Given this, I need to send a delete request in the first step and then inspect the response to that request.
I've find troubles trying to do that because when I implement the first step as delete url then when I try page.should have_contain(text) I get the error No response yet. Request a page first. (Rack::Test::Error)
What do you think about it?
check out how-do-you-post-to-a-url-in-capybara (answering another question) but there a several examples of how to use visit in a capybara test like
visit "item/:id/delete"
This will probably be easiest if I explain what I'm trying to do. I have three actions in my Rails app controller, each rendering a different page. The page-render is done with a single partial which uses variables that were set in the controller action code. For example, each page has a list on it, but on one page the list is sortable. Up to now I've been handling this by setting a #sortable flag to true or false in the code for my actions.
This works fine when an action is initially run. The problem is that I have AJAX stuff going on (e.g. adding a new element to the list) and when this happens, I need to know the value of the #sortable variable again. It seems to have gone, even though I'm still technically on the same page. What I want is a variable store that is linked to the page you are on.
What are your recommendations for doing this? (Storing it in the Rails session hash seems like overkill - too much chance that the wrong value will get left in there by some yet-to-be-implemented action.)
Ben
In rails I've only managed to set page scoped variables for initial setup too.
I think the only solution would be to pass the sortable flag from the page on the ajax request. You can store it either with a javascript variable, in a hidden field, custom attribute on your list or anyway you wish and then in the ajax you simply add that to the request so you can treat that on the server side persistently.
Why do you don't want use session? As for me before_filter works fine for such tasks
in ApplicationController
before_filter :init_actions
def init_actions
session[:action] = action_name
session[:controller] = controller_name
end