Routes: resources, use member or collection for a custom action? - ruby-on-rails

Hi everyone I am doing a application with rails 3.2. I am trying to use form_tag but I have problem with the route.
I try this in my form:
= form_tag('/companies/save_category', method: "post") do
and this:
= form_tag({:controller => "companies", :action=>"save_category"}, method: "post") do
In my config/routes.rb:
I am a little confused to put route like this
resources :companies do
post 'save_category'
end
or route like this:
resources :companies do
member do
post 'save_category'
end
end
But either way does not work. And when I execute rake routes, I obtain the same result
company_save_category POST /companies/:company_id/save_category(.:format) companies#save_category
The error was this
No route matches [POST] "/companies/save_category"
any idea?

Consider these routes:
resources :companies do
member do
post 'save_category'
end
end
This member block means that the route save_category in the /compagnies/ namespace will need a Company id to work:
/compagnies/12/save_category # where 12 is params[:company_id]
Now, with collection:
resources :companies do
collection do
post 'save_category'
end
end
This means that to get to the save_category route, you don't need the company id:
/compagnies/save_category # will work, is not needing a params[:company_id]
In your case, you should first use the url helpers (generated following the routes.rb). You need here:
if save_category is a *member route*
save_category_company_path(#company)
elsif save_category is a *collection route*
save_category_companies_path
I guess the category you want to save is related to a specific company, right? If yes, you need a member route:
form_tag(save_category_company_path(#company), method: "post") do
Hope this helps!

Related

making a delete request to URL rather than ID in a rails api

i'm wondering if anyone can give me any advice.
I'm currently writing a rails API and although it doesn't seem like a best practice, rather than performing a DELETE call to
localhost:3000/products/:id
id rather make it to
localhost:3000/products/:url
and pass in the URL to be deleted, however i've currently got this but I keep getting a routing error.
DELETE '/products/:url', to: 'products#destroy'
is my current route for this, it is also specified above my
resources :products
sections.
My whole routes file:
AppName::Application.routes.draw do
resources :features do
resources :feature_links
end
resources :wishlist_items
resources :data_feeds
get '/get_data_feeds', to: 'data_feeds#get_feed_url', as: 'feed_url'
resources :genders
resources :trends
resources :sub_categories
resources :color_tags
resources :colors
resources :categories
delete '/products/:url', to: 'products#destroy'
resources :products do
member do
get 'buy'
post 'wish'
end
end
end
Any ideas?
Thanks in advance
If the url i'm sending the delete request to is http://localhost:3000/products/www.test.com I get the error No route matches [DELETE] "/products/www.test.com" if the url I sent the delete request to is http://localhost:3000/products/:url I get the error Couldn't find Product with 'id'=:url
My Destroy method code:
def destroy
#product = Product.find(params[:url])
#product.destroy
respond_with(#product, status: 200)
end
I think Rails is considering your URL parameter as the specification of the format of the response. You can override the constraints of the parameter as follows:
constraints: { url: /[^\/]+/ }
This will make sure that the URL parameter can be anything except for /. The whole route should look like this:
delete "/products/:url", to: "products#destroy", constraints: { url: /[^\/]+/ }, as: :products_destroy_with_url
And use it like this:
link_to "Destroy", products_destroy_with_url_path("www.test.com"), method: :delete

How to force to pass a required url path via get method

I have a route
collection do
get :show_logs
end
And I want the user should request show_logs/[:id].
Forbid user to send show_logs request without required id
What's the better ways to get it ?
UPDATE
If now, I wrote my rule as following,
And trying to access without :id, http://localhost:3000/tool/mvaas/relay_queries/show_logs
I'll get the error ActiveRecord::RecordNotFound in xxx
routes
get '/tool/mvaas/relay_queries/show_logs/:id', to: 'tool/mvaas/relay_queries#show_logs', :via => :get, :as => 'show_logs_tool_mvaas_relay_queries'
namespace :tool do
namespace :mvaas do
resources :relay_queries do
collection do
end
end
end
end
You should put it into member instead of collection
resources :users do
member do
get :show_logs
end
end
It will be accessible with the url /users/:id/show_logs
If you absolutely want the url to be /users/show_logs/:id then you should go with
get '/users/show_logs/:id', to: 'users#show_logs'
before your resources :users do block
You can verify if params exist by following way:
if(params.has_key?(:one))
If exist- request will done.
If absent - redirect/render or show notice.
you could try:
get "show_logs/:id" => "controller#action"
with updates: just write something like:
namespace :tool do
namespace :mvaas do
resources :relay_queries do
collection do
get "show_logs/:id", action: "show_logs"
end
end
end
end

how to fill twice id from routes rails

i try to fill twice id in url, but when i send params twice id just one id fill the url id.
My route :
namespace :admin do
resources :stores
get "/:id/new_items"=> 'stores#new_items', as: :store_new_items
post "/:id/create_items"=> 'stores#create_items', as: :store_create_items
get "/:id/show_items/:id"=> 'stores#show_items', as: :store_show_items
get "/:id/items/:id/new_items_sub" => 'stores#new_items_sub', as: :store_new_items_sub
post "/:id/items/:id/create_items_sub" => 'stores#create_items_sub', as: :store_create_items_sub
get "/:id/items/:id/show_items_sub/:id" => 'stores#show_items_sub', as: :store_show_items_sub
end
my view :
<%= link_to "add new items", admin_store_new_items_sub_path(#store.id, #items.id), :class=> "btn" %>
i hope my url like this :
http://localhost:3000/admin/#{store.id}/items/#{items.id}/new_items_sub
but i get same id like this :
http://localhost:3000/admin/#{store.id}/items/#{store.id}/new_items_sub
please tell me when i'm wrong? thanks
you have to create neseted routes for that .have a look at
http://guides.rubyonrails.org/routing.html#nested-resources
for example
resources :publishers do
resources :magazines do
resources :photos
end
end
will accept routes /publishers/1/magazines/2/photos/3
Your params should be unique, so you can't pass more than one different :id params. Instead. you can do something like:
get '/:store_id/show_items/:id', as: :store_show_items
and in view:
<%= link_to 'show items', store_show_items_path(#store.id, #item.id) %>
Also, you should read more about Resources and Nested Resources in Rails, there's probably no need to complicate your life by creating each route independently.
You could refactor this to use nested routes like this (you may have to change controller method names):
namespace :admin do
resources :stores do
resources :items, :only => [:new, :create, :show] do
resources :subs, :only => [:new, :create, :show]
end
end
end
This would give you a few url helpers like this: new_store_item_sub_path(#store.id, #item.id) for the new action and store_item_sub_path(#store.id, #item.id, #sub.id) for the show action.
Run rake routes to see what helpers and routes you have access to.
Have a look here to find out more about nested routes.
Your code can be DRYed up significantly. Hopefully this works; might need some tweaking:
namespace :admin do
resources :stores do
member do
get :new_items, as: :store_new_items
post :create_items, as: :store_create_items
end
get "show_items/:id"=> 'stores#show_items', as: :store_show_items
resources :items do
get :new_items_stub => 'stores#new_items_sub', as: :store_new_items_sub
post :create_items_stub => 'stores#create_items_sub', as: :store_create_items_sub
get "show_items_sub/:id" => 'stores#show_items_sub', as: :store_show_items_sub
end
end
end
Uses Member Routes (see 2.10) & Nested Resources
Nested Resources
The crux of your issue is that you're trying to pass the :id param twice
Fortunately, Rails has a solution to this, in the form of Nested Resources. These work by taking the "parent" id and prepending a singular prefix, such as :store_id, allowing you to use the :id param for another set of methods

rails custom rest route with parameter

I have a questions controller and an associated model and a number of rest routes. Here is how it's set up in routes.rb:
resources :questions
I want to add a custom route that has the format /questions/widget/ID (where ID is the id of the question for which I want to generate a widget). I want this to be processed by the "widget" action in my questions controller. I've tried a number of things such as:
resources :questions do
member do
get 'widget/:id'
end
end
But nothing is working. I'm sure I'm missing something simple. Any ideas? Thanks in advance.
You do not have to specify the id since you are inside resources. It should look like:
resources :questions do
member do
get 'widget'
end
end
You can get more information from the Rails Guide. Look at section 2.9.1.
Edit: I just noticed that you are trying to match get /questions/widget/:id. This will set up a route for get /questions/:id/widget. This is more in line with Rails convention. If you really want it the other way, you need to set up a custom match statement:
match "/questions/widget/:id" => "questions#widget"
However, I would stick with convention.
I know it is old, but looking to fix another routing problem I ended here, it is possible, to do what you are asking for, here is an example
resources :articles do
get 'by_tag/:tag' => :by_tag, on: :collection
get 'by_author/:author' => :by_author, on: :collection
resources :comments, except: :show
end
now you have /artices/by_tag/:tag . The trick was to use on:collection.
Obviously don't forget to add the by_tag action and by_author.
class ArticlesController < ApplicationController
.....
def by_tag
...
end
end
Check this route works with
melardev#local~$ rails routes
Why don't you use this routes:
resources :questions do
resources :widgets
end
it will create path like questions/:question_id/widgets/new for you to create new widget for question with specific id of question.
This is what ended up working for me:
resources :post do
get "author/:author", to: "posts#author", on: :collection, as: "author"
end
Which outputs the following route:
author_posts GET /posts/author/:author(.:format) posts#author
Then in your controller, you need to create the author action:
class PostsController < ApplicationController
def author
#roles = Post.where(author: params[:author])
render :index # to reuse the index view
end
end
Then in your view:
<%= link_to post.author, author_posts_path(post.author), data: { turbo_frame: "_top" } %>

Rails routes for get request with query params

I need a route to accept a request reports#show with an attached :query parameter and I can't figure out how to write it. It needs to respond to this link in my view:
= link_to report_path(query: params[:query]) do
config/routes.rb
resources :reports do
resources :chapters
resources :pages
end
Tried variations of: get '/reports/:id/:query', :as => 'reports_query' but I keep getting:
Routing Error
No route matches {:action=>"show", :controller=>"reports", :query=>"europe"}
Project is mostly RESTful but I'll take anything that works at this point. Thanks for any help.
You should define your route to query with code like this
# routes.rb
resources :reports do
get ':query', to: 'reports#show', on: :member, as: :query
end
It will generate path helper you can use that way
= link_to 'Query Report', query_report_path(#report, query)
I went through the same problem here, and I solved it using the default param while defining my routes.
get :twitter_form, defaults: { form: "twitter" }, as: :twitter_form, to: "campaigns#show"

Resources