Better routes in rails with params - ruby-on-rails

I've been working on a movie application in Rails. I have a controller/view for the actor. When passing params to the actors controller i want the URL to be pretty. Now it looks like this: http://localhost:3000/actors/show?actor=Hayley+Atwell and i want it to look like /actors/show/Hayley+Atwell or /actors/Hayley+Atwell.
How do i do this? My link in the movies view is:
<%= link_to a.name, {:controller => 'actors', :action => 'show', :actor => a.name}, :class => "label label-default" %>
My routes.rb is now like this:
get 'actors/show'

I recommend you use friendly_id gem. It perfectly satisfies your needs!
https://github.com/norman/friendly_id

You can use the following in your ./config/route.rb file:
get '/actors/:actor', to: 'actors#show'

I'll give a series of refactoring advice as follow:
Try to make use of the actor's id instead of the name
Change the route to: get '/actors/show/:id', to: 'actors#show'
Then, you can now change the link in your view to something like:
<%= link_to a.name, {:controller => 'actors', :action => 'show', :id => a.id}, :class => "label label-default" %>
Note: the : part in the :id of your route means that this could be interchanged to anything, and whatever comes in that place will be interpreted as the id. So, in /actors/show/7, the id of the actor is 7, you can now find the actor with this id in your controller action, and do anything you want with it.

If I'm right than you try to create RESTful routes anyway.
So I would recommend you to use the Rails' resources method in your routes:
Rails.application.routes.draw do
resources :actors # If you want only the :show action than add:
# , only: [:show]
end
This automatically creates the proper routes for you.
To get the names into the URL you should use the friendly_id gem. It has a great community and is very well tested.

Related

Rails nested routes with link_to

I'm trying to use a link_to from my view into a nested route and I am sure I just have my syntax incorrect. The basic flow of my app is there is a summary that has many feeds which then have many log lines. its a very basic report
My route is
resources :perfsums, :only => [:index] do
resources :perffeedresults, :only => [:index] do
resources :loglines, :only => [:index] do
end
end
end
Here is how the rake routes looks for that
perfsum_perffeedresult_loglines_path GET /perfsums/:perfsum_id/perffeedresults/:perffeedresult_id/loglines(.:format) loglines#index
In my view I have a link to I want to link from the feed class to log lines using the feed ID. Should be very simple. My link to looks like this
<td> <%= link_to c.id, perfsum_perffeedresult_loglines(c) %> </td>
Going directly to the page by hand works as the link below shows I just can't get there form that link to
http://localhost:3000/perfsums/19/perffeedresults/143/loglines
When I try to run with that link_to I get. I have tried a few different options here none have worked.
undefined method `perfsum_perffeedresult_loglines' for #<#<Class:0x007fad31b60dd8>:0x007fad386d86b0>
I do use a link_to to go from the summary to the feeds page fine its just that extra bit of nesting t hats throwing me off I think.
First of all, it's a perfsum_perffeedresult_loglines_path, you missed _path, which should be added to get a path. And you need to pass two params, look at the path:
/perfsums/:perfsum_id/perffeedresults/:perffeedresult_id/loglines
You need to pass a perfsum and a perffeedresult:
<td> <%= link_to c.id, perfsum_perffeedresult_loglines_path(perfsum, perffeedresult) %> </td>

Action Controller error. Url Generation error. No route matches

I'm working through the "Ruby on rails 3 essential training" on lynda.com and am having an issue while generating my server. So far I have a subjects_controller.rb, linked to my views folder, to the file list.html.erb. My error when trying to start the server is:
No route matches {:action=>"show", :controller="subjects", :id=>1}
In my list.html.erb file I have written the code:
<td class="actions">
<%= link_to("Show", {:action => 'show', :id => subject.id}, :class => 'action show') %>
<%= link_to("Edit", '#', :class => 'action edit') %>
<%= link_to("Delete", '#', :class => 'action delete') %>
</td>
My subjects_controller.rb looks like:
class SubjectsController < ApplicationController
def list
#subjects = Subject.order("subjects.position ASC")
end
end
I have double checked to make sure I have everything written the same as the instructor but there seems to be a missing link. Any ideas? If I totally cut out the action:
<%= link_to("Show", {:action => 'show', :id => subject.id}, :class => 'action show') %>
Then the server starts up. There must be a problem here but I'm not sure what it is. Also when the instructor inputs link_to on his text editor, the txt turns a different color and mine does not. Same thing with his "#" instance variable. Mine doesn't change color. Not sure if this means anything either. Thanks for any input!
Here is my config/routes.rb file:
Rails.application.routes.draw do
root :to => "demo#index"
get 'demo/index'
get 'demo/hello'
get 'demo/other_hello'
get 'subjects/list'
end
Short version: The error message is telling you exactly what is wrong. You have no route that matches, because while your action is named list, your link specifies :action => 'show'.
Longer version: The second argument to the link_to helper is supposed to tell Rails what URL to generate for the link, usually by specifying one of your routes by name, but sometimes (as in this case), by specifying the action (and optionally the controller). You're specifying the action show. The subjects controller is implied. Therefore, Rails is trying to find a route (in the ones defined in your routes.rb) that GETs the SubjectsController#show action. However, as you can see from your routes.rb, you only define one route on the SubjectsController, and that's list.
If you're ever confused about what routes you have or what their names are, you can use the rake routes task to list them all out in a nice readable format.
Edit to respond to followup question:
The instructor is telling me that when you generate a controller and
action that its supposed to add a route to the routes.rb folder. This
worked for me earlier but when creating these actions that I'm having
trouble with now, it didn't generate anything in the routes.rb folder.
Do you know why that is?
When your instructor says 'generate', they probably mean 'use the rails generate command'. When you use the generator to create a controller and specify the actions in it, the it will also add those actions to the routes file.
If, on the other hand, you write the action into an existing controller (including using the generator for the controller but not specifying actions), or create the controller file yourself, you'll have to update the routes file manually. If you are using the generator and specifying actions and aren't getting updated routes, I'm not sure what's going on.
Personally, I prefer to write my routes by hand anyway - the generator often doesn't get them exactly right.

How to create an arbitrary link in Rails?

link_to and helpers use the names of my models and their IDs while I want to have a couple of different, arbitrary, variables in my link. I have no problems to route them, I actually keep the default routing as well, but I suddenly stuck that I cannot easily generate an arbitrary link. For instance I want to have a link like ":name_of_board/:post_number", where :name_of_board and :post_number are variables set by me, and when I use link_to I get instead "posts/:id", where "posts" it's the name of the controller. While it's not hard to use an arbitrary id like
link_to 'Reply', :controller => "posts", :action => "show", :id => number
I cannot get how I can get rid of "posts". So, is there an easy way to generate a link by variables or to convert a string into link? Sure, I can add other queries to the line above, but it will make the link even more ugly, like "posts/:id?name_of_board=:name_of_board".
You can create additional routes for your posts resource in your routes.rb, or make standalone named routes:
resources :posts do
get ':name_of_board/:id' => 'posts#show', as: :with_name_of_board
end
get ':name_of_board/:id' => 'posts#show', as: :board
Now this
#name_of_board = "foo"
#post_id = 5
link_to 'Reply', posts_with_name_of_board_path(#name_of_board, #post_id)
link_to 'Reply', board_path(#name_of_board, #post_id)
would link to /posts/foo/5 and /foo/5 respectively.
You should first edit your route entry, for example a classic show route is the follow:
get "post/:id" => "post#show", :as => :post
# + patch, put, delete have the same link but with different method
And you can call it with the following helper
link_to "Show the post", post_path(:id => #post.id)
You can edit or create a new entry in the routes, applying the parameters you want to use, e.g.:
get "post/:id/:my_platform" => "post#show", :as => :post_custom
Then
link_to "Show the post with custom", post_custom_path(:id => #post.id, :my_platform => "var")
Finally, the link generated for this last entry is for example:
"/post/3/var"
Even in this situation, you can add some other params not defined in the routes, e.g.:
link_to "Show post with params", post_custom_path(:id => #post.id, :my_platform => "var", :params1 => "var1", :params2 => "var2")
=> "/post/3/var?params1=var1&params2=var2"
RoR match your variable defined in the routes when you render a link (remember that these variables are mandatory), but you can ever add other vars that come at the end of the url ("?...&..")

Rails hide controller name

i have match ":id" => "people#show" in my routes.rb
now i can access http://localhost:3000/1
but,in views <%= link_to 'Show', people %> it will generate http://localhost:3000/people/1 ,
i want to it to be http://localhost:3000/1
You could do something like this to ensure that only numeric ids are matched:
match '/:id' => 'people#show', :constraints => {:id => /\d+/}
A good alternative might be to use some kind of identifier, even if it's not the controller name: http://localhost:3000/p/1. This will at least ensure that if you add other controllers and actions you don't end up having to change your routing structure.
You could write a custom route to match that in config/routes.rb. At the bottom of your routes.rb file you will have a route like match ':controller(/:action(/:id(.:format)))'
or something like resources :people. You might have to write a route that matches the route type you want.
You have to create a named route.
match ':id' => 'people#show', :as => :person
And fix your views to use your new method person_path(user_id).

Adjust routes.rb for method call in Controller

I have an online portfolio created in Rails featuring different projects. I want to be able to filter the projects by keywords. My approach is to define a method for each keyword in the ProjectsController and link the keywords to call the methods.
For Example Keyword = graphic_design:
<%= link_to 'Graphic Design', :action => "filter_"+#project.keyword.to_s %>
That way I get the error:
Couldn't find Project with ID=filter_graphic_design
This is quite obvious to me. My question: Is there a way to tell the routes.rb to behave differently only for 'filter_' methods? Any other suggestions?
Your approach is wrong. Why do you need a filter_ method for each keyword in the first place? Its pretty simple a solution. First define a named route in your routes.rb:
map.filter '/projects/:filter_this_for_me', :controller => 'projects', :action => 'filter'
In your views,
<%= link_to 'Graphic Design', filter_path("filter_" + #project.keyword.to_s) %>
In your filter action,
def filter
logger.info("Parameters that is being received: #{params}")
filter_what = params[:filter_this_for_me]
if(!filter_what.nil? && !filter_what.blank?)
# Here filter_what will have "filter_graphic_design" or "filter_something"
# With which you can filter any data that you want.
# Filter your projects here.
end
end
I think something like this could work
map.connect "/projects/filter_{filter}", :controller => 'projects', :action => 'filter'
Haven't tried it though

Resources