how to hit a put route - ruby-on-rails

I have an additional method in one of my otherwise restfull controllers called 'importdata'. As I'm actually changing the data (importing csv in the database), I understood that it should be a put route instead of get.
Initially I had
resource data_set do
put 'importdata', on: :method
end
what I also tried is:
put 'data_sets/:id/importdata', "data_sets#importdata'
rake routes shows the route I want in both cases.
What I did when I had the method on (1st example) route in the controller was
redirect_to import_data_sets_path id: dataset.id
And with the second example:
redirect_to controller: "data_sets", action: "importdata", id: dataset.id
The message I get in both cases is:
No route matches [GET] "/data_sets/28/importdata"
Which is correct, because it's a put route. The only way I get this to work is to change the put for a get:
get 'data_sets/:id/importdata', "data_sets#importdata'
How can I get that to work on a put route? Should it be a put route in the first place?
Thanks for your time.

Simply put you can't 'upgrade' a HTTP request issued by an user. redirects only work over GET. If the user is changing something do it through a form and make sure it's a PUT request as you're modifying an existing resource.
If the PUT is conditional there's several options, either figure out how to solve this in the UI, use an HTTP client to issue the PUT(which doesn't make sense for an local call) or extract the editing of the resource in some other kind of class and use it in the controller.
However, even if the edit is optional it makes more sense to let the user fire a PUT in the first place.
Hope that helps.

Related

Rails routes and querystring

I am having troubles trying to define the correct route for a query coming from ember. The request appears like this:
GET "/users?id=1011
No matter what I try I always have the request forwarded to the index action, while it is intended for the show action.
I have tried many things, like
get "/users?id=", to: redirect('/users')
but nothing seems to work.
Can anyone explain to me what can I do and most important the reason behind it?
Thank you very much for your time!
GET /users?id=1011 always goes to index because Rails just sees the route as GET /users. The question mark denotes a parameter, which isn't part of any of your defined routes.
You can modify your index method to interpret the param, something like:
def index
if params[:id]
# call show, do something, whatever
else
# regular index action
end
end
In the case of retrieving just one user, it would be more common to route this to your show action as you originally intended. To accomplish this, do not pass the id as a query param, but instead as a slug segment /users/1011, which you can accomplish by declaring the following in your routes.rb:
get '/users/:id', to: 'users#show'
If you want to go full tilt then you might as well just declare users as a resource like so:
resources :users
Which will automatically wire up your index, show, update, destroy, etc. Throw Active Model Serializers in the mix and you can have Ember Data start talking to your API nearly "out of the box".

How to write two different routes but calling same controller function in rails 4?

There two different routes but it calling the same controller function.
two possible routes:
1) ios-mobile-developer-india
2) salesforce-consultant-india
we are technology and location dynamically.
routes.rb:
get ':tech-mobile-developer-:loc' => application#tech_location
get ':tech-consultant-:loc' => application#tech_location
If i search ios-consultant-india, it 'll show the output. But, I want to redirect to ios-consultant-india. can anyone tell how to redirect based on technology?
Have you tried like this get '/stories', to: redirect('/articles')
routing redirect
If you want to perform a redirect at route level, you may want to use the router redirect feature.
get '/:tech-mobile-developer-:loc', to: redirect('/%{tech}-consultant-%{loc}')
In this way you don't need to inject the redirect code in the action itself, and the action will only contain the code responsible to render the action content.

rails_3_question :as => why is my /posts/new routing to posts/show after setting up a slug

I'm using Rails 3 and after setting up slugs, I found that posts/new no longer works.
posts/:id, posts/:id/edit and all the other CRUD operations work.
However /posts/new gives me a routing error
No route matches {:action=>"show", :controller=>"posts"}
Now for some reason posts/new is routing to posts#show. In my routes, its just
resources :posts
My theory is that since /posts/:slug now matches against things other than numbers ids, the show verb is being routed to first. However it doesn't make sense since posts/grr a nonexistent entry gives a different error than posts/new and posts/first comes out just fine with all its associated paths working fine as well.
Anyone know what might be going on?
I've uploaded the repo to https://github.com/cultofmetatron/cassowary/tree/photogallary
I know my code sucks, I'm still learning the ins and outs of the system and I'd appreciate any insight into whats going on.
In your comment the first part seems fine: add a column to the Post column called slug and so on, and the contents of that will become some or all of the URL used to display a specific post. (I'll assume the other CRUD operations should work as normal)
To find the URL, the router has to know how to know which controller and action will handle this URL (as compared to others). A normal resources :posts route will match all of the RESTful methods, e.g. mapping a GET request onto a path starting with the controller name, and if an id is specified (/posts/1) map to the posts#show controller method, if not, it will map to posts#index method. If the request is a PUT, or DELETE or POST, different actions around a standardized URL format will occur.
Two changes are needed:
URL with the post slug format needs to map to the posts#show method (which is modified accordingly), and
Any links to the show page that are generated on your site need to use the post slug instead of the id
I'll assume you're OK with URLs start with /posts (if not, you'll need to identify some other unique pattern).
The first change requires that you override the specific case of the show method using route globbing, my adding something like match 'posts/*slug before the standard resource route. Here's a link to the guide on route globbing: http://guides.rubyonrails.org/routing.html#route-globbing
The next change, modify the existing posts#show method so that it looks for slug instead of id, e.g.
def show
#post = Post.where("slug = ?", params[:slug])
...
end
Finally, change the way Rails handles the URL helper posts_path. Do this by overriding to_param in your Post model, e.g.
def to_param
"/posts/#{slug}"
end
And then you're done. Maybe.
After that, see how the friendly_id gem does the same thing :-) https://github.com/norman/friendly_id

Routing without the model name

Using this question and railscast 63 I've got my articles routed to articles/article_permalink.
I'd like them to be accessible without the model name in the url so my-domain.com/article_permalink routes directly to the article. I'd only want this to happen on the show action. Is this possible?
I think you need something like ...
(in routes.rb)
match '/:id' => 'articles#show', :via => 'get'
(needs to be last, or towards the end of the routes as it can match requests intended for other routes)
To change the article_path(...) helpers, "as" might help: http://guides.rubyonrails.org/routing.html#overriding-the-named-helpers
Or you can add a helper for that specific path.
If I understand your question, you want the model tied to the route "articles/article_permalink" to be dynamic based upon which is article is selected from a list?
Would you be open to appending a model ID to the end of the URL as a query string? A more complicated approach would be to have your links POST, with the model ID as a hidden input field. Your controller could determine if it was accessed via get/post, and handle it accordingly, but that doesn't feel right.
Regardless, when the controller action is fired up based upon a request to "articles/article_permalink", it has to know which model to fetch. With HTTP being stateless, something has to be passed in. You could get fancy and write JavaScript to fire one AJAX call, set a session var, and then fire the GET, but that's messy.
I hope I understood the question...

What is the difference between a restful route method for getting an index vs. creating a new object?

According to rake routes, there's the same path for getting an index of objects as there is for creating a new object:
cars GET /cars(.:format) {:controller=>"plugs", :what=>"car", :action=>"index"}
POST /cars(.:format) {:controller=>"plugs", :what=>"car", :action=>"create"}
Obviously, the HTTP verb is what distinguishes between them. I want the "create" version of the cars_path method, not the "index" version. My question is what route method do you invoke to choose the one you want? I'm telling cucumber what path to generate with this:
when /the car plug preview page for "(.+)"/
cars_path(:action => :create, :method => :post)
...but it always chooses the "index" action, not "create". I've tried lots of combinations for the hash argument following cars_path and nothing changes it from choosing "index" instead of "create".
I'll get an error like this:
cars_url failed to generate from {:controller=>"plugs", :method=>:post,
:what=>"car", :action=>"create"}, expected: {:controller=>"plugs", :what=>"car",
:action=>"index"}, diff: {:method=>:post, :action=>"index"}
(ActionController::RoutingError)
This seems like a very simple question but I've had no luck googling for it, so could use some advice. Thanks.
Since the URL is the same for both actions, you can use cars_path (without arguments) in both cases. You just simply have to make sure that the form's method-parameter is set to :post. You can not set the method via the URL, you need to set it for the form (and you can't reach the create action by using a link, you need to use a form).
The difference is that one is accessed when a POST is performed, the other is accessed when a GET is performed. Typing a URL into the browser or (typically) clicking a link is the equivalent of a GET action. POST actions are typically performed by form submissions.

Resources