Rails Routes - link_to singular resource with params - ruby-on-rails

so this is stumping me im not the best when it comes to routes at all, but what i am trying to achieve seems simple. what i have is a feature that is currently only accessible by a superuser and now i would like to extend that functionality to a portal_administrator. now to access the page you need a link_to that looks like this
= link_to('Data', portal_datum_path(current_portal.id), :id => :super_user_data_link)
which is routed with a match
match '/portal_data/:id', :controller => 'portal_data', :action => 'show', :as => 'portal_datum'
now this works just fine you end up with a url that has a id params. which is used in the page that it routes to. in fact there is a before filter that makes sure there is a id.
def load_portal
#portal = Portal.find(params[:id])
end
this would enable the susperuser to see what portal he was in just by looking at the url. now that i am extending this to the users i dont want them to see what portal id they are in, so i thought i would use a singular resource something along the following.
= link_to('Data', portal_data_path, :id => :super_user_data_link)
with a
match '/portal_data' => "portal_data#show"
so it routes to the same place but keeps the url clean. but obviously this dosent work. even if i hard code the before filer to accept the first portal it jsut throws a error
No route matches {:controller=>"portal_data", :action=>"show"}
but if i rake my routes its there?
i am sure what i am doing wrong is obvious any ideas?

All i had to do was make the :id an optional parameter like so...
match '/portal_data(/:id)'
And it works :) then in the controller look for...
def load_portal
#portal = Portal.find(params[:id] || current_portal.id)
end
...an portal id on the account if there wasn't one in the params.

Related

route is redirecting to wrong path

This is what my routes currently look like:
which gives
On my homepage I have a create vacancy button
<%= link_to "plaats", new_employer_vacancy_path(:employer_id)%>
Which should be linked to the line from the first image
get '/employers/:employer_id/vacancies/new', to: 'vacancies#new', as: 'new_employer_vacancy'
In the vacancies_controller#new - create I have:
def new
#vacancy = Vacancy.new
#employervacancy = Employervacancy.new
end
def create
#vacancy = Vacancy.create(vacancy_params)
createEmployervacancy
redirect_to employer_vacancy_path(current_employer, #vacancy)
end
def createEmployervacancy
#employer = current_employer
Employervacancy.create(vacancy_id: #vacancy.id, employer_id: #employer.id)
end
But whenever I click the button I get redirected to some other method in my vacancies_controller that is totally irrelevant.
How is this even possible? Don't I clearly define that when that path is clicked he should go to vacancies#new? and not to vacancies#show_specific_employer_vacancies?
EDIT
After following the answers I am indeed being linked to the correct route.
First, it gave me this error.
After trying to pass the current_employer.id instead of #employer like suggested I got following error:
For your routes, you'd better to change into nested route for easily maintaining routes.
Remove these codes:
get '/employers/:employer_id/vacancies/:id', to:"vacancies#show_specific_employer_vacancies", as: "employer_vacancy"
get '/employers/:employer_id/vacancies/edit/:id' ...
get '/employers/:employer_id/vacancies/index' ...
get '/employers/:employer_id/vacancies/new' ...
path '/employers/:employer_id/vacancies/:id' ...
change into:
resources :employers do
resources :vacancies
end
Try to use basic routes here because you use standard simple form url. For example:
<%= simple_form_for(#employee, #vacancy) %>
The simple_form_for will generate url well if you use nested routes above.
Finally, in your link you have to add #employer_id
<%= link_to "plaats", new_employer_vacancy_path(:employer_id => #employer_id)%>
I hope this help you
Your router cannot tell the difference between your employer_vacancy and new_emplyer_vacancy routes because the :id parameter accepts anything. Because of this, when you point your browser to "/employers/5/vacancies/new", the route is taking your employer_vacancy route and assigning {:employer_id => 5, :id => "new"} instead of going to your new_employer_vacancy route (because routes are first-come-first-serve).
To correct this, add a constraint to your first route to ensure that only numbers (and not the string "new") is accepted into the employer_vacancy route:
get '/employers/:employer_id/vacancies/:id',
to: 'vacancies#show_specific_emplyer_vacancies',
as: 'employer_vacancy',
constraints: { id: /\d+/ } # <- This line
As Wes Foster said rails router is trying to find a first match.
It means that given a path /employers/999/vacancies/new your router looks through the routes and when it sees get '/employers/:employer_id/vacancies/:id he thinks that this route matches. So :employer_id is 999 and :id is new.
I'd suggest to put the route with :id at the end of employers routes:
...
get '/employers/:employer_id/vacancies/new'
...
get '/employers/:employer_id/vacancies/:id'
Btw this is better than adding a constraint because:
It is easier
It doesn't pollute routes file
Later you may want to change ids to be hashed or alphabetic and then you'd have to change the constraint

Rails routing URL folders for product categories on show actions

I'm trying to formulate some better urls for a "product" model I have, only on the show action. I'm currently using friend_id to generate pretty slugs, which is fine, but I'm trying to improve the URL flow if I can.
Current my paths work like this
example.com/products/pretty-url-slug
When saving a parictular product (to the Product Model), I also save a type_of attribute. Which could be android, iphone, windows
So I am trying to ultimately have robust URLS like this
example.com/products/iphone/pretty-url-slug
The problem is, that I don't have or believe I want an actual "iphone", "android", etc controller. But I'd rather just update a combination of the routes and show action to handle this properly.
So far I've attempted to solve this by using a catch all on the routes, but is not working correctly. Any suggestions or different ways to handle this elegantly?
routes
resources :products
# at the bottom of my routes a catch all
match '*products' => 'products#show'
# match routes for later time to do something with to act like a
# normal category page.
match 'products/iphone' => 'products#iphone_index'
match 'products/android' => 'products#android_index'
match 'products/windows' => 'products#windows_index'
show action in the products controller
def show
# try to locate the product
if params[:product].present?
slug_to_lookup = params[:product].split("/").last
type_of = params[:product].split("/").second
#product = Product.find_by_slug(slug_to_lookup)
else
#product = Product.find_by_slug(params[:id])
end
# redirect if url is not the slug value
if #product.blank?
redirect_to dashboard_path
elsif request.path != product_path(#product)
redirect_to product_path(#product)
end
end
This way to handle the problem sort of works, but I can't fiqure out how to append the type_of attribute and generate a valid URL.
What about defining your routes like this:
get ':controller/:action/:id/:user_id'
Here, Anything other than :controller or :action will be available to the action as part of params.
Thanks for the suggestion. I was actually able to solve this and pretty simple when I thought it over. This might be helpful for others.
In my routes I just created a route for every type of category I have. so every time a new category, I would need to add an additional route, example:
# match for each product category
match 'shop/iphone/:slug' => 'products#show', :as => :product_iphone
match 'shop/android/:slug' => 'products#show', :as => :product_android
match 'shop/windows/:slug' => 'products#show', :as => :product_windows
Then in the show action for products instead of directing, you would just render the products/show if the slug matches an existing product
#product = Product.find_by_slug(params[:slug])
Then in your views, you could link to a particular category like this
link_to "product", product_android_path(#product)

Routing error Rails 3.2.1

I'm trying to create a very simple site the sends and receives parameters from the URL (or link), the app should support any number of parameters, i.e. http://localhost:3000/action=receive&controller=pages&email=mail%40site.com&name=Vinny, and then be able to receive/print them.
I think I have located the problem to my route. It currently looks like this:
match 'pages/*params' => 'pages#receive'
I create the link that sends the params like this:
<%= link_to "Send Params", :action => "receive", :name => "Vinny", :email => "mail#site.com" %>
When I click the link I get the following error.
No route matches [GET] "/assets"
And the URL looks like this:
http://localhost:3000/assets?action=receive&controller=pages&email=mail%40site.com&name=Vinny
Note asset?.
If my route instead looks like this:
match 'pages/:name/:email' => 'pages#receive'
It works, but then I'm limited to the specified params.
Any tips on how to solve this would be great.
Okay, I think I see what is happening. Specifying parameters in the routes is not necessary to get the values into the controller's action. So, replace the map you specified earlier in the routes.rb with
resources :pages
If you add to your link
:controller => "pages"
It should go to the correct controller + action. (this may not be necessary in your case)
In that action, you can grab all of the params from the hash
email = params[:email]
account = params[:name]
Etc.
Info on routing
Info on params

Set Up Route for Accessing Private S3 Content

I've been following
https://github.com/thoughtbot/paperclip/wiki/Restricting-Access-to-Objects-Stored-on-Amazon-S3
and
Rails 3, paperclip + S3 - Howto Store for an Instance and Protect Access to try and get Paperclip's expiring links to work. I believe most of what I'm running into is one of the routing variety.
In my pieces_controller I put a method in like this
def download
redirect_to #asset.asset.expiring_url(1000)
end
And then in my routes, I put this:
match "pieces/download"
Then in my view I have:
<%= link_to download_asset_path(piece)%>
It would seem to be far from working, and I'm not sure what is messed up. I know I'm getting routing errors for one, but it's also telling me that my download_asset_path is undefined, which is likely also routing related... I feel like I'm doing everything all wrong.
Tearing my hair out. Thanks!
Try modifying your routes file to:
match 'pieces/download' => 'pieces#download', :as => 'download_asset'
Your match needs to tell which controller#action to go to, and the as option will allow you to name the route download_asset_path.
If your pieces controller is for a Piece resource it could be cleaner like:
resources :pieces do
member do
get :download
end
end
But then you would want to change the link to:
link_to 'Link text', download_piece_path(piece)
For further reading: http://guides.rubyonrails.org/routing.html

New Action Not Working

I have a standard User controller with the normal set of actions (index, show, new, edit, etc) and I'm trying to add a new action named 'profile'. I added the following code:
def profile
#user = User.find(session[:user_id])
end
I also created a new view for the action (app/views/users/profile.html.erb), but whenever I try to view that page I get an error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with ID=profile
...
Apparently it's hitting the show action. I'm guessing that means I need to add something to my routes to make this work, but I don't know what. So far I just have the two default routes and the map.root line which I uncommented:
map.root :controller => "home"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
So really I have two questions:
What do I have to do in order to enable my new action?
Why don't the existing routes cover this situation? Other urls consisting of just the controller and action work just fine (e.g. http://localhost:3000/users/new). Why not this one? Shouldn't it just evaluate to :controller = users, :action = profile, :id = nil?
Try putting something like this in your routes.rb file:
map.user_profile '/users/:id/profile', :controller => "users", :action => 'profile', :conditions => {:method => :get}
I think possibly the reason it's doing this is because you are not matching either of the defaults, because you are not setting :id (even though it is detecting your action as the id). I don't know what your URL looks like, but I have a feeling that if you tried http://localhost:3000/users/123124124/profile, it MIGHT work, even without the new line in routes.
Are you intentionally trying to get the id from session[:user_id] instead of params[:id]? Is this supposed to be displaying a public profile?
Are you sure, that the session contains the user_id the first time you load the page?
Hard to say without seeing all the code, but my guess is there may be some strangeness because your model and controller have the same name. I'd try renaming the controller before changing anything else (remember to change the name of the views/users directory too).
See also this other stack overflow post: Rails cannot find model with same name as Ruby class
Long shot maybe.
Solution for your problem configure your routes.rb in such a way that id should be passed as the parameter .
configure in routes.rb as below
map.profile '/profile/:id',:controller=>'users',:action=>'profile'
when you want to access your profile page use it with the following URL
http://localhost:3000/profile
Make sure once you login , u handle the session and store the userid in the session variable .
Good luck !

Resources