Rails restful namespaces, resources... newbie question - ruby-on-rails

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)

Related

Rails nested resources and path

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"

Calling a custom action within a nested resource (Rails 3)

I'm trying to call a custom controller action shuffle for a resource that is nested within another resource. I can't seem to get the method call right.
routes.rb
resources :templates do
resources :items
end
match "/templates/:template_id/items/shuffle" => "items#shuffle"
I have a link in my items#index view:
<%= link_to 'Shuffle', shuffle_template_items_path(#template) %>
When I click on the link, I get the following error:
undefined method `shuffle_template_items_path' for #<#<Class:0x42577c8>:0x3e77578>
I have also tried <%= link_to 'Shuffle', template_items_shuffle_path(#template) %> and that did not work.
How do I correctly call this custom action?
You probably want this:
resources :templates do
resources :items do
get :shuffle, :on => :collection
end
end
If you want your custom action to have a name, you need to provide it:
match "/templates/:template_id/items/shuffle" => "items#shuffle", :as => :suffle_template_items
I think the best way to write shuffle is in collection as per the documentation of Rails Routes:
So it would looks like this:
resources :templates do
resources :items do
collection do
get :shuffle
end
end
end
when you try rake routes you will find shuffle_template_items GET /templates/:template_id/items/shuffle(.:format) items#shuffle.

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

Rails - custom action in controller - how to reference in view?

I'm using a custom action to get the id of a project into the session, so that only relevant info for that project is shown in other areas. I've made a custom action in the projects controller, and am having trouble getting a link to work in the view to call that action. I just get an error saying "Couldn't find project without ID". I'm new to rails - I know it's probably an easy question, but help would be much appreciated, thanks!
View Code:
<%= link_to 'Select Project', :action => :select_project %>
Controller Code:
def select_project
#project = Project.find(params[:id])
session[:project_id] = #project.id
end
Routes:
resources :projects do
collection do
get :select_project
end
end
Alternative routes code:
resources :projects do
put 'select_project', on: :member
end
This is untested but I believe it is what you are looking for:
Routes:
resources :projects do
member do
post :set_current
end
end
this should create the following:
Endpoint: /projects/:id/set_current POST
Helper: set_current_project_path
Controller
def set_current
project = Project.find(params[:id])
session[:project_id] = project.id
redirect_to projects_path, :notice => "Current project set to #{project.name}"
end
Views
# index / erb tags excluded for simplicity
#projects.each do |project|
link_to 'Select Project', set_current_project_path(project), :method => :post
end
# show
<%= link_to 'Select Project', set_current_project_path(#project), :method => :post %>
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Note also the use of 'post' instead of 'get', since we are changing the state of an object (session)
it is preferred to use a post not a get, otherwise users might pull up an old get request in the address bar
of their browser and set their session to a project unknowingly.
like varatis said - use rake routes or CONTROLLER=projects rake routes to help with determining what your route/path helpers look like and what http verbs they are expecting
And is there a reason why it's project not #project in the controller
The #project creates an instance variable; in a rails controller instance variables are made available to the views. This set_current action will never render a view, so no reason to make an instance variable out of it.
How come you have to set it to member and not collection in the routes
any action where you want to reference params[:id] should be a member route, an alternative would be to leave it as a collection route and pass params[:project_id] and pass that in all of your link_to calls, but in this case member makes more sense.
I believe resources :projects is a short cut for this break down
member do
get :show
get :edit
put :update
delete :destroy
end
collection do
get :index
get :new
post :create
end
hopefully that clarifies your questions some?
I think the route generated would be select_project_projects_path.
Link:
<%= link_to 'Select Project', select_project_projects_path %>
For future reference, run rake routes to see the automatic route helpers generated by Rails.

Rails 3 Routing: non-CRUD controller

I need a bit of help with converting routing from Rails 2 to Rails 3.
In app/views/layouts/application.html.erb, I have:
<%= link_to "Reports", reports_path %><br>
There is a ReportsController, and in app/views/reports/index.html.erb, I have this:
<%= link_to "Clients With Animals", :action => "getAnimals", :controller => "clients" %>
Then, in config/routes.rb, I have this (Rails 3)
match '/reports' => "reports#index"
match '/clients/getAnimals', to: "clients#getAnimals"
I get this error when I click on the "getAnimals" link on the reports page:
ActiveRecord::RecordNotFound in ClientsController#show
Couldn't find Client with id=getAnimals
I don't want "getAnimals" to be the ID - I want it to be the action, instead.
How do I do that?
Assuming you also have a resources :clients entry, you want to make sure match '/clients/getAnimals', to: "clients#getAnimals" is above it (Rails will match whatever it hits first).
However, the better way may be to put it in the resource:
resources :clients do
get 'getAnimals', :on => :collection
end

Resources