Rails Controller Action Doesn't Respond to Changes - ruby-on-rails

I have a subscriptions controller that at the end redirects to :root and a line on my routes file that points a url to that action. At first I was testing the action without any trouble. But yesterday I tried to change something and the server didn't respond to the changes, no matter what I put in the action it always ignores everything and redirects to :root.
This is how my action looks like:
def fail
test = Subscription.new
p test
binding.pry
redirect_to :account
end
This is my routes line:
match 'subscriptions/failed' => 'subscriptions#fail'
And whenever I try to go to subscriptions/failed it ignores the print instruction, the binding instruction and redirects to :root instead of :account. If I comment everything on the action it will still do the same, the only different reaction it is when I delete the action. Probably obvious but I can't see it.

From your problem description, I would go and check if there is a before_filter or around_filter for fail action that redirects to :root. They would exactly do what you describe if the action is called and wont do anything and wont do anything if the action is not called.
May be you can post more code for the related controllers, just to be sure.

Related

How to skip_before_filter for a redirect in a action method?

I have a controller which has several methods and one of them has a redirect at the end.
def launch
do_something
params[:hey] = "heyo"
redirect_to("/tasks")
end
All actions has a before_filter which sets some access control headers.
What i want is;
I want to have this before filter for "launch" method, but not for the redirect in it.
How can i achieve this ?
When i set this below, it removes filter for both launch method and "/tasks" redirect, but i only want to remove it for the redirect.
skip_filter :set_access_control_headers, :only => :launch
Thanks in advance!
Update:
This method lives in an engine, that's why I have different access control headers than main application. I do not want to mess with main applications code since i create specific engine and routes for each customer.
And the redirect in the end goes to main application.
You can set param in your redirect and in filter check if param is not exist than skip
Example: redirect_to edit_multiple_items_path, :notice => 'items updated', {:page => ##, :method => 'GET'}
It might be because I focused too much on doing it the "Rails" way.
I fixed the issue by simply removing the headers manually just before the redirect and it all worked fine now.
headers.delete('Access-Control-Allow-Origin')
headers.delete('Access-Control-Request-Method')
headers.delete('Access-Control-Allow-Methods')
redirect(/tasks?#{options.to_query})
Thanks for the answers though!

Stay on the same page after edit

I'm trying to follow the RailsTutorial guide, but by doing my own application instead. I have trouble with section 7, with the forms.
My controller :
def update
d = Deck.find(params[:id])
d.title = params[:deck][:title]
d.slug = params[:deck][:slug]
d.category = params[:deck][:category]
if d.save
redirect_to deck_path(d), notice: "Deck saved successfully"
else
render :edit
end
end
I know it's very, very far from good code, but I will refactor it later (if you have a suggestion I'm all ears, but I use Rails 3, so I guess the strong parameters of Rails 4 are out).
The problem is when the d.save does not work (due to validation), with the render :edit.
Right now, when I enter invalid data, it tries to redirect to the show action, and crashes because it does not have any data to display.
If I add #deck = d above the render, it works, but the url still is the show action.
If my validation fail, how can I stay on the same URL and display my error messages ? Is the "change URL but render the same page" behavior accepted as valid ?
Thanks !
If you're interested in looking at the rest of the code, it's here : https://github.com/cosmo0/TeachMTG/tree/remodel-decks
Actually when it fails your url is not the 'show' it is the 'update' url.
Your code works.
When you submit your form, your browser sends a POST request to controller#update.
When the update fails, you tell your update action to "render :edit". What it does is it renders the :edit action inside the :update route.
The update route uses the same url as your show action :
you can check this when running 'rake routes', the only difference is that the method is POST for 'update' vs GET for 'show'
That's why you think it is the show url in the browser but actually everything works: you are on the update action that renders :edit.
(Telling your update action to 'render :edit' doesn't mean you are redirected to :edit back from :update)
Is that clear enough ?
I believe that you're looking for respond_with method.
I think you are misunderstanding what is happening in the restful world. When you do an update the URL is changing because your form is performing a HTTP POST.
If d.save works it redirects to your deck_path with d as the object. If it fails it does not change the URL in the browser, but renders the same page as the edit action.
I'm guessing in the call for the edit action you have something like:
#deck = Deck.find(id)
Your render is failing because you don't have a #deck variable assigned in your update. So you can either change all of your instances of d to #deck or use your solution of setting #deck = d.

In Rspec, how test a controller action that does not have a route?

In a few of my controllers I have an action that does not have a corresponding route because it is accessed only via a render ... and return in other controller actions.
For example, I have an action
def no_such_page
# displays a generic error screen
end
In my RSpec controller test, how do I 'get' that method and look at the response body?
If I try:
get :no_such_page
response.status.should be(200)
it of course gives the error
No route matches {:controller=>"foo", :action=>"{:action=>:no_such_page}"}
Update
Looking back over your question, it doesn't make sense to me now since you say that you are only accessing this action via render ... and return, but render renders a view, not an action. Are you sure that you even need this action? I think a view spec is the place for this test.
Original answer
It doesn't make sense to test the response code of an action which will never be called via an HTTP request. Likewise get :no_such_page doesn't make sense as you can't "get" the action (there is no route to it), you can only call the method.
In that sense, the best way to test it would be to treat it just like any other method on a class, in this case the class being your controller, e.g. PostsController. So you could do something like this:
describe PostsController do
... other actions ...
describe "no_such_page" do
it "displays a generic error screen" do
p = PostsController.new
p.should_receive(:some_method).with(...)
p.no_such_page
end
end
end
But in fact, judging from what you've written, it sounds to me like your action has nothing in it, and you're just testing the HTML output generated by the corresponding view. If that's the case, then you really shouldn't be testing this in controller specs at all, just test it using a view spec, which is more appropriate for testing the content of the response body.
before :all do
Rails.application.routes.draw do
get '/no_such_page', to: "foo#no_such_page"
end
end
after :all do
Rails.application.reload_routes!
end

How to setup routes when the controller only has edit and update?

I can't seem to figure out how to get my routes setup properly.
In my app, I have a view that lets site owners update their address information. The new and create actions are part of the signup process and are located in the signups_controller. The edit and update actions are in the settings_controller.
When the user goes into the settings area, he/she sees only the edit form. When filled out, the user is then returned to the same form with a flash message, or error message. Here is what the controller looks like:
class SettingsController < ApplicationController
def edit
#account = current_account
#account.companies.first
#account.companies.first.addresses.first
#account.companies.first.phones.first
end
def update
#account = current_account
if #account.update_attributes(params[:account])
redirect_to edit_setting_path
flash[:notice] = "Success!"
else
render :edit
end
end
end
In my routes, I simply have:
resources :settings
The link to this area of the site is a basic RESTful named linke, with the parameter options:
edit_setting_path(:id => current_account.id)
When the user arrives to this page, they see the following URL:
http://domainname.com/settings/1/edit
When they submit the form and get errors, the URL changes to:
http://domainname.com/settings/1
Why is the URL changing -- I'd rather it not? Is there a way to make it stay the same as the initial edit view? I've tried doing a redirect on a failed update, but then I don't get the error messages.
Any ideas?
To answer your "why" question: The URL is changing because it's reflecting the URL of the failed request - which in this case is a PUT request to that URL (/settings/1). You've submitted the form and the submission of that form (correctly) points to that URL. This is a result of the RESTful routes that the helper gives you. Since the logic in your action, falls through to the render :action, there is no redirect and the form simply re-renders on the page using the same data available in this action (which is why you can see the errors).
If you want to redirect back to the edit page, yes, you will lose the errors that have been set in the #account instance variable since the redirect will reset (re-query for) the account.
You could add a route that matches a PUT to /settings/1/edit and point it to your update action and change your form etc. In short, I wouldn't recommend this, but it should work.
completely untested but attemptable:
routes.rb
put "/settings/:id/edit", :to=>"settings#update", :as=>"update_setting"
resources :settings, :except=>:update
your form would also have to submit to the update_setting_path (which also means it's not reusable for a new object... ew)
First you should read up on The Rails Guides for Routing. They will help a lot to understand why its working like that.
Secondly, to accomplish what you are trying to do, you will need to add manual routes via the match call. You'll need something like this.
match '/settings/:id/edit' => "settings#edit"

How to do an almost-postback in rails

I don't know what to call this, except that it is almost-a-postback. I'd like my rails app to be able to receive a request independently from somewhere else on the interweb in the form of:
myapp.com/count?id=45&sex=y
And to be able to perform some calculations (update some table etc) and not bother to respond back.
The key here is - I just want to perform the action and nothing else, not display any view or redirect to any other page.
I set up a "count" controller, but it wants some view or web page to go to. Then I thought, maybe routes could do it? But that seems like a bad idea to have code in routes.
Any ideas appreciated.
In your method controller do this:
def method_count
#do calculation stuff
render :nothing => true
end
This will return status 200 (if everything was ok) and nothing will be rendered.
Don't forget to setup your route in config/routes.rb
For API calls it is a good idea to return only an HTTP status code if no content has been requested. You can do this using the head method in ActionController::Base.
def count
# do work
head :success
end
You have to create a controller and put your action into it !
In config/routes.rb :
get "yourcontroller/count"
In yourcontroller.rb :
def count
#some code treating params
end

Resources