I am using Ruby's built in CSV functionality to export some tables as csv files. It all works fine if I am in the
def index
// code
end
However, I have a custom action in the controller called 'annual' with a 'respond_to block as follows:
respond_to do |format|
format.html # index.html.erb
format.json { render json: #surveys }
format.csv { send_data #surveys.to_csv, filename: "survey-annual-#{Date.today}.csv" }
end
The error is:
"status":404,"error":"Not Found","exception":"#\u003cActiveRecord::RecordNotFound: Couldn't find Survey with 'id'=annual\u003e","traces":{"Application Trace":[{"id":1,"trace":"app/controllers/surveys_controller.rb:34:in `show'"}]
I don't believe this is specific to .csv as .json produces the same error. I am wondering if defining a method '.to_csv' in the model is causing a problem because of Ruby class structure; I'm not good enough with Ruby and haven't been able to find an answer.
Thanks!
Its actually a very basic and common routing error and has nothing to do with CSV generation. Check the logs if you don't belive me.
Routes in Rails have priority in the order they are defined. So if you for example have declared your routes as:
resources :surveys
get 'surveys/annual', to: 'surveys#annual'
The request for surveys/annual will always be passed to SurveysController#show as it matches first.
Routes are just superpowered regexes. So the GET /surveys/:id route does not merely look for integer ids.
Rather the following will match:
/surveys/1
/surveys/foo
/surveys/foo%20bar%20baz
But not /surveys/foo/bar or POST /surveys/foo.
To add additional restful actions properly you should instead use a block and the collection option:
resources :surveys do
get :annual, on: :collection
end
This adds the route in the correct order as seen below:
Prefix Verb URI Pattern Controller#Action
annual_surveys GET /surveys/annual(.:format) surveys#annual
surveys GET /surveys(.:format) surveys#index
POST /surveys(.:format) surveys#create
new_survey GET /surveys/new(.:format) surveys#new
edit_survey GET /surveys/:id/edit(.:format) surveys#edit
survey GET /surveys/:id(.:format) surveys#show
PATCH /surveys/:id(.:format) surveys#update
PUT /surveys/:id(.:format) surveys#update
DELETE /surveys/:id(.:format) surveys#destroy
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
Related
I am trying to use ajax to get information from my controller. Basically I want to know if a data already exists in the DB or not, so my controller will return either true or false.
At the moment I am just trying to set the basic ajax call
in my js file I have the following ajax call, as you can see at the moment I am not really doing any logic because my data is just a placeholder. Later I will add the information I want to query
$.ajax({
type: "GET",
url: "/locations/exists",
dataType: "JSON",
data: { 'locition_exist': loc_exit },
success: function(data) {
console.log(data);
}
});
In my controller I have
def exists
location_exists = true
respond_to do |format|
format.html
format.json {render json: location_exists }
end
end
Later value will go into a method in the model that will query the DB and return true/false.
In my routes I have
resources :locations
get 'locations/exists', to: 'locations#exists'
This code results in the following error
The action 'show' could not be found for LocationsController
I am new to rails and ajax , and I based my code on different examples that I read here, so I am probably just doing a stupid noob mistake.
Thank you very much for your help
When using get or match in routes, you need to define the controller method mapped
get 'locations/value', to: 'locations#value'
update
You saw the same error after updating routes. There are two reasons of this error:
You defined resources :location at first. The url locations/exists itself matches "show" method within resources, with Routes taking 'exists' as the id in #show.
You have not defined show within LocationsController
So, Routes will firstly map the url to locations#show with the :id as 'exists', then hits the controller and found #show does not exist.
The solution after your updating
Of course you can put get 'exists'... before resources but that looks ugly.
Since 'exists' requires no id, it is a collection method. So you can use Routes built-in ways to do that.
resources :locations do
collection do
get 'exists'
end
end
By this all your resources and 'exists' can live.
The source of my information is section 2.9 here:
[http://guides.rubyonrails.org/routing.html#connecting-urls-to-code][1]
What I'm trying to do is add a custom action "search" and corresponding view.
So, as it says to do in the documentation, I've added this code in my config/routes.rb file:
resources :dimensions do
collection do
get "search"
end
end
I've also defined in the dimensions_controller file:
def search
#dimensions = Dimension.all
respond_to do |format|
format.html # search.html.erb
format.json { render json: #dimensions }
end
end
I then stopped and restarted the rails server, but when I navigate to /dimensions/home, I'm still getting this error message:
Couldn't find Dimension with id=search
Also showing that my parameter is:
{"id"=>"search"}
So am I just missing another bit of code that gives the instruction to interpret /dimension/search as a collection action as opposed to the show action?
I've already confirmed that search_dimensions_path exists, so I know that the resource block in the routes.rb file is actually adding paths. It's just interpreting them as a separate search action that's giving me trouble.
Thanks for your time.
This code should work fine. Can you show us your routes.rb file?
On a side note, you probably don't want to have a separate action for searching, using the index action is the preferred way.
Found the issue:
I had to make the resource declaration in my config/routes.db file for dimensions after creating the collection action, like so:
resources :dimensions do
collection do
get "search"
end
end
resources :dimensions
Then everything worked as expected.
I am using rails 3.0.14, and I am constructing routes.rb using the resourceful style. I'd like to have a wildcard route that catches all requests that do not match to any route stated.
What's the appropriate way to construct such a route?
put
match '*path' => 'your_controller#your_action'
at the end of the routes.rb file. This is important, since the routes are stepped through top down.
See also http://guides.rubyonrails.org/routing.html -> 3.10
For Rail 4, you need to specify the request type:
match "*path", to: "application#custom_action", via: :all
As others have said, put this at the very bottom of your routes file.
It is not mandatory to use exactly "path" in the match '*path' statement. You can set a whatever token there:
get "*string1"
or
get "*string2"
Rails will assign your real HTTP-query to the param named after your token, example:
get "*user" => "users#show"
in console:
Started GET "/john" ....
Processing by UsersController#show as HTML
Parameters: {"user"=>"john"}
You can use more than one asterisks, say get "*id*user". But in this case you will get some unpredictable result, because Rails processes 2 or more asterisks "in an intuitive way" - for more info see http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments
In addition to #steel and #awenkhh, I recommend adding the following to that route's controller action
respond_to do |format|
format.html
# other formats you already support
format.all { render text: '' }
end
Otherwise, you'll wind up with some ActionView::MissingTemplate: Missing template errors for formats that you weren't expecting.
[rant]Particularly helpful for those people trying erroneous attack vectors around /wp-admin/css/wp-admin.css and the like. I seem to get about 100 requests for /wp-admin/* a day, from super annoying people who apparently would like me to get a more expensive Rollbar account plan.[/rant]
I'm creating a custom view that is a slight modification of the index.html.erb. I'd like to be able to create a link on my web app that directs a user to this custom view called list.html.erb.
Here's what I've done:
1) Copied the default scaffold index view and renamed it to list.html.erb
2) Modified GalleriesController by copying the index method and renaming to list:
def list
#galleries = Gallery.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #galleries }
end
end
3) Modified routes.rb file like so:
match "galleries/list" => "galleries#list"
I keep getting the following error:
Couldn't find Gallery with ID=list
Rails.root: /Users/scervera/Sites/MDN
Application Trace | Framework Trace | Full Trace
app/controllers/galleries_controller.rb:28:in `show'
In my search on stackoverflow I was unable to find any similar questions.
I'm guessing you put the match outside of, and after, the gallery resources routing.
This means the list is being interpreted as the :id of the default RESTful mapping.
Options include:
Just using index unless you truly need them both (which seems weird).
Adding a list RESTful action as described here (see below).
Changing the order of your routing and/or using a constraint to avoid route overlap. IMO this is the most-fragile and least-preferable.
To add the list action (option 2):
resources :galleries do
get 'list', :on => :collection
end
You should put your galleries/list route before all other gallery routes.
Order matters. In your case, route "galleries/:id" gets matched first and causes this error.
You can get exhaustive information about Rails routing here: Rails Routing from the Outside In.
I'm not quite understanding how requests are handled in rails, in my controller, I have something like this:
def method_to_handle_request
# do stuff
end
Then in the view I have this JavaScript:
$.post("/", {method_to_handle_request: "value"}, function(data) {
// do something with data
});
This is wrong: data in the JavaScript ends up just being the page. Thus, my question is: how do I handle requests in rails? I've been reading "Agile Web Development With Rails", and the section there doesn't make too much sense to me.
Thanks
Rails uses configured routes to point to the appropriate controller action. You have to specify a route in your config/routes.rb file to send your request through the desired action. In your controller, you've defined the method_to_handle_request. You have to make sure that you define a route for that. There are many ways to do this within the routes.rb file and those are well documented in this guide.
Then in your method_to_handle_request you should render/format your output as JSON or XML or whatever you want your view to consume. If you don't do this you'll end up just getting the flat templated HTML back. Here's a good resource for rendering views that has a section on JSON in particular.
So here's a quick example of what I mean:
in config/routes.rb
resources :foos do
member do
post 'do_my_foo'
end
end
in foos_controller.rb
def do_my_foo
foo = Foo.find(params[:id])
# do some things to poor ole foo
some_cool_data_about_foo = ...
respond_to do |format|
format.json { render :json => some_cool_data_about_foo }
end
end
Then when you call it with ajax you'll get the JSONified data in your handler.
Geeze, I hope this is what you were asking...