Rails nested resources and path - ruby-on-rails

I've got a nested resource:
def workspace
has_many :instances
end
def instance
belongs_to :workspace
end
and some nested routes
resources :workspaces do
resources :instances do
end
end
resources :instances
That way, I can visit the following path and get the same result:
workspaces/1/instances
/instances
On my 'view/instances/index.html.erb' I have a custom pagination link, where I reload the page with additional params.
If I am in workspaces/1/instances, the link should be:
= link_to "← Previous", workspace_instances_path(:param => "data")
But, if I am in /instances:
= link_to "← Previous", instances_path(:param => "data")
How can I have a single link_to, that works for both routes? Preferably without listing all possible cases, just a single line

link_to lets you specify the controller and action in place of the named route. Assuming that the same controller action will handle the request you could specify the controller and action
link_to "previous", :controller => "instances", :action => "my_action", :data => "data"

Related

link_to update for a nested resource not working

The link in _applicant.html.erb looks like this in the browser: http://localhost:3000/needs/3/applicants.1
and when clicked on this shows up in the browser:
Routing Error
No route matches [PUT] "/needs/3/applicants.1"
I want it to update the acceptance column for this particular applicant row. Basically I want it to send data to the update method of the applicants controller. How can I modify the code to do this?
_applicant.html.erb
<%= link_to 'Accept Applicant', need_applicants_path(applicant.need_id, applicant.id), :method => :put, :action => "update", :applicant => {:acceptance => true} %>
got this from running rake routes:
PUT /needs/:need_id/applicants/:id(.:format) applicants#update
routes.rb:
resources :needs, except: [:new] do
resources :applicants
end
applicants_controller.rb
class ApplicantsController < ApplicationController
def update
#need = Need.find(params[:need_id])
#applicant = #need.applicants.find(params[:id])
if #applicant.update_attributes(params[:applicant])
flash[:success] = 'Your applicant has been accepted/rejected!'
redirect_to #need
else
#need = Need.find(params[:need_id])
render 'needs/show'
end
end
end
I think there are two possible fixes here:
First,
http://localhost:3000/needs/3/applicants.1
should probably read
http://localhost:3000/needs/3/applicants/1
The error is in this line:
<%= link_to 'Accept Applicant', need_applicants_path(applicant.need_id, applicant.id), :method => :put, :action => "update", :applicant => {:acceptance => true} %>
where...
need_applicants_path(applicant.need_id, applicant.id)
You can try passing in two instance objects like so:
need_applicants_path(Need.find(applicant.need_id), applicant)
Second, another possible solution is to explicitly set the PUT path in your routes.
In your config/routes.rb add the line
put 'need/:need_id/applicant/:id/update
then run
rake routes
and see what the PUT path is

url action is not working in my rails

I made a salaries controller inside the folder employee.
In my routes:
namespace :employee do
resources :salaries
end
Now in my salaries controller I added a new method action_list:
class Employee::SalariesController < ApplicationController
def action_list
end
end
From view inside index I want to call action_list like:
<%= form_for :form, :url => {:action => 'action_list'}, :method => :post,
:html => {:id => 'form1', :onsubmit => "return checkCheckBoxes();"} do |f| %>
When I submit the form I get the following error:
No route matches [POST] "/employee/salaries/action_list"
What could be the problem? It works fine for other controllers without using a namespace.
What am I doing wrong?
have you added action_list onto your routes
namespace :employee do
resources :salaries do
post :action_list, :on => :collection
end
end
Add a route for the action_list action:
namespace :employee do
resources :salaries do
post 'action_list'
end
end
Read more about adding restful routes here.

How to add a custom action to the controller in Rails 3

I want to add another action to my controller, and I can't figure out how.
I found this on RailsCasts, and on most StackOverflow topics:
# routes.rb
resources :items, :collection => {:schedule => :post, :save_scheduling => :put}
# items_controller.rb
...
def schedule
end
def save_scheduling
end
# items index view:
<%= link_to 'Schedule', schedule_item_path(item) %>
But it gives me the error:
undefined method `schedule_item_path' for #<#<Class:0x6287b50>:0x62730c0>
Not sure where I should go from here.
A nicer way to write
resources :items, :collection => {:schedule => :post, :save_scheduling => :put}
is
resources :items do
collection do
post :schedule
put :save_scheduling
end
end
This is going to create URLs like
/items/schedule
/items/save_scheduling
Because you're passing an item into your schedule_... route method, you likely want member routes instead of collection routes.
resources :items do
member do
post :schedule
put :save_scheduling
end
end
This is going to create URLs like
/items/:id/schedule
/items/:id/save_scheduling
Now a route method schedule_item_path accepting an Item instance will be available. The final issue is, your link_to as it stands is going to generate a GET request, not a POST request as your route requires. You need to specify this as a :method option.
link_to("Title here", schedule_item_path(item), method: :post, ...)
Recommended Reading: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
Ref Rails Routing from the Outside In
Following should work
resources :items do
collection do
post 'schedule'
put 'save_scheduling'
end
end
You can write routes.rb like this:
match "items/schedule" => "items#schedule", :via => :post, :as => :schedule_item
match "items/save_scheduling" => "items#save_scheduling", :via => :put, :as => :save_scheduling_item
And the link_to helper can not send post verb in Rails 3.
You can see the Rails Routing from the Outside In

Ruby on Rails: How to override the 'show' route of a resource?

Currently I have a route that looks like this:
resources :posts
I want to override the 'show' action so that I can display a url like this:
posts/:id/:slug
I am currently able to do this by adding a custom match route:
resources :posts
match 'posts/:id/:slug' => 'posts#show'
However, when I use the link_to helper, it does not use my custom show route.
<%= link_to 'show', post %> # renders /posts/123
How can I define my show route so that I can still use the link_to helper?
Update: As you can read in the following answers, you can override the route to the 'show' action, but it's probably more work than it's worth. It's easier to just create a custom route:
# config/routes.rb
match 'posts/:id/:slug' => 'posts#show', as: 'post_seo'
# app/views/posts/index.html.erb
<%= link_to post.title, post_seo_path(post.id, post.slug) %>
You have two routes which point to posts#show (you should be able to confirm this by running rake routes), and your link is using the wrong one.
When you call link_to('show', post) the URL of the link is generated by calling url_for(post) which (eventually, after passing through several other methods on the way) calls post_path(post). Since the route to posts#show that was created by your call to resources(:posts) is named post, that is the route that post_path generates.
You also currently have inconsistent routes for the show, update and destroy actions which will probably cause you problems later on.
You can fix this by changing your routes to the following:
resources :posts, :except => ['show', 'update', 'destroy']
get 'posts/:id/:slug' => 'posts#show', :as => 'post'
put 'posts/:id/:slug' => 'posts#update'
delete 'posts/:id/:slug' => 'posts#destroy'
Unfortunately you still can't use link_to('show', post) just yet, because it relies on being able to use post.to_param as the single argument needed to build a path to a post. Your custom route requires two arguments, an id and a slug. So now your link code will need to look like this:
link_to 'show', post_path(post.id, post.slug)
You can get around that problem by defining your own post_path and post_url helpers in app/helpers/posts_helper.rb:
module PostsHelper
def post_path(post, options={})
post_url(post, options.merge(:only_path => true))
end
def post_url(post, options={})
url_for(options.merge(:controller => 'posts', :action => 'show',
:id => post.id, :slug => post.slug))
end
end
Which means we're finally able to use:
link_to 'show', post
If that all seems like too much work, a common alternative is to use URLs that look more like posts/:id-:slug, in which case you can stick with the standard RESTful routes and just override the to_param method in your Post class:
def to_param
"#{id}-#{slug}"
end
You'll also need to do a little bit of work splitting up params[:id] into an ID and a slug before you can look up the relevant instance in your show, edit, update and destroy controller actions.
resources :posts, except: :show do
get ":slug" => :show, as: "", on: :member
end
and define helper
def post_path post
"/posts/#{post.id}/#{post.slug}"
end
db/migrate/add_slug_to_articles.rb
add_column :articles, :slug, :string
add_index :articles, :slug
models/article.rb
class Article < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
def should_generate_new_friendly_id?
new_record?
end
end
Or...
class Article < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :history
end
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid
https://github.com/norman/friendly_id

Rails restful namespaces, resources... newbie question

I'm attempting to use nested controllers that have restful pathing, so that I'm all organized and such. Here's a copy of my routes.rb so far:
map.root :controller => "dashboard"
map.namespace :tracking do |tracking|
tracking.resources :companies
end
map.namespace :status do |status|
status.resources :reports
end
Links to children controller paths work fine right now,
<%= link_to "New Report", new_status_report_path, :title => "Add New Report" %>
But my problem ensued when I tried to map to just the parent controller's index path.
<%= link_to "Status Home", status_path, :title => "Status Home" %>
I end up getting this when I load the page with the link:
undefined local variable or method `status_path'
Are my routes set correctly for this kind of link?
UPDATE: I should add that no data is associated with the parent "status" controller. It merely acts as the category placeholder for the rest of the controllers associated with statuses, eg: reports.
If you want /status to go to the status controller it should be a resource, not a namespace. You nest resources in much the same way:
map.resource :status do |status|
status.resources :reports
end
A namespace isn't a resource.
map.resources :statuses do |status|
status.resources :reports
end
Also, your call to status_path needs an ID.
status_path(:id => #status.id)
or
status_path(#status)

Resources