Rails beginner, so please don't bite. I've taken over the maintenance/development of a rails an app, but still learning the ropes
I'd like to generate the following route :
/events/1/Project/2/Pledge
Where 1 is the eventId and 2 is the Project Id.
I have a project controller and and events controller. The pledge action is on the Project controller
EDIT: In answer to #wacko's comment below.
a)Ignore the casing and pluralization of the url i asked for (I realise that invalidates the original question somewhat...)
An event has multiple projects, The pledge action will take the user to a page where they can enter multiple pledges for a particular project.
Perhaps instead the Pledge action should be on the Events Controller instead?
and the URL something like 'events/1/pledge/2' (Where 2 is the projectId)
What you are looking for is called a nested resource, that is to say that there is a parent child relationship between two resources.
resource :events do
resource :projects do
get :pledge, :on => :member
end
end
For this to work, your models would look something like this
class Event < ActiveRecord::Base
has_many :projects
end
And
class Project < ActiveRecord::Base
belongs_to :event
end
The following should work
get '/events/:event_id/projects/:id/pledge' => 'projects#pledge'
In your controller action you can get the event_id and project_id from the params hash as params[:event_id] and params[:id] respectively
resources :events do
resource :projects do
resources :pledge
end
end
this will give you the ability to set the scope in your controllers and have access to all 7 REST verbs
resources :events do
resources :projects do
member do
get :pledge
end
end
end
You can change get to the http method you want.
You can use collections if you need a route like /events/1/projects/pledge
collection do
get :pledge
end
run rake routes from the project root folder to see a list of routes generated
jsut use this way
resources :events do
resource :projects do
get '/pledge'
end
end
Related
I have the models Dad, Mom and Kid. I'm already using the kid's index action for Dad and made another action in the Kids controller called mom_index for Mom's since a kid belongs to a mom and a dad.
Right now the Dad's route goes to:
dad_kids GET /dads/:dad_id/kids(.:format) kids#index
Because of:
resources :dads do
resources :kids
end
I need my Mom's route to go to:
mom_kids GET /moms/:mom_id/kids(.:format) kids#mom_index
But doing this:
resources :moms do
resources :kids
end
Uses the kid's index action which is already being used by the dad. How can I get it to do this using the Kids mom_index action instead?
You could just use an if statement to check whether the request is for dads or moms etc:
#app/controllers/kids_controller.rb
Class KidsController < ApplicationController
def index
if params[:mom_id].present?
# mom logic
elsif params[:dad_id].present?
#dad logic
end
end
end
An alternative would be to set different controllers (however this is not recommended as it's not DRY):
#config/routes.rb
resources :moms do
resources :moms_kids, as: "kids" #-> domain.com/moms/:mom_id/kids
end
You are better off either having the kids controller know how to deal with being used by either the dads or moms namespace or making two separate resources called dads_kids and moms_kids.
So for the first option you would leave what you have as far as routes but make the kids controller action smarter/overloaded.
For the second option you would do:
resources :dads do
resources :dads_kids
end
resources :moms do
resources :moms_kids
end
Then you would have 2 controllers dads_kids_controller.rb and moms_kids_controller.rb.
I am playing with Rails 4 in a test application. I have an arbitrary URL that isn't standard like a resources :foo type URL. Ideally the end result I'd like is to be able to go to:
/contests/:id/enter
In views, it would be great if I can then set a link using a named helper such as:
edit_contests_enter(:id)?
What would be the best way to define the route above so I can use the helper path with an arbitrary URL like the one above? It doesn't necessarily have to be edit_contests_enter(:id) but as long as the helper path leads to the URL as suggested above, that would be fantastic.
I assume that your contest is a resource, and when your visitor goes to /contests/:id/enter you want them to create an object user <=> contest. Let's call it participation.
Now participation is exactly like any other resource in your Rails app, so you'd have a routes.rb file looking like
resources :contests do
resources :participations
end
You don't want people to do anything other than create a participation, like edit or destroy them. And perhaps you want a nice URI like /contests/:id/enter. All you have to do is
resources :contests do
resources :participations, :only => [:new, :create]
get "enter" => "participations#new"
end
Doing such will give you a routes helper named contest_enter. In your participations#new form, you'll POST as usual to /contests/:id/participations.
If you have a resources block for :contests, you could just define a new "member" route on the ContestsController using:
resources :contests do
member do
get :enter
end
end
And that would automatically generate you a named member route, the name of which you could find by running rake routes.
Before devise, I had a model called Participant which contained info for users. It had a controller and set of views to go with it. I added devise, and asked that it used Participant for the user records. That seemed to work just fine.
Now in my world, the route to create a participant looked like this: ./program/2/participant/new because any participant other than the singular "administrator" is created and used always within a single program. The participant model already has a belongs_to :program.
My Routes look like this:
devise_for :participants
root to: 'programs#index'
resources :programs do
resources :participants do
resources :rounds do
get 'survey' => 'rounds#present_survey'
put 'survey' => 'rounds#store_survey'
end
end
resources :questions
resources :rounds
member do
get 'report' => 'reports#report'
end
end
I am a little confused about the structure of things. When I bring all the views from devises engine into my app, I get views/devise/registrations/edit and new. I want them to be /view/participants/edit and new.
And I want the routes and all that to behave accordingly. When I create a new Participant, I will know from the route what Program it is in, and be able to set up the program_id correctly. When the user logs in, unless they are "admin" I want them to be redirected to the route like ./program/3.
I am not sure how to approach this. Can you give me some tips, that would be appreciated!!
-- Pito
you have to do something as follow
class ParticipantsController < Devise::RegistrationsController
def new
... # your code of new
end
def update
... # your code of update
end
end
and in routes
devise_for :users, :controllers => { :registrations => "participants" }
hope it would help
I need some help with routes for nested controllers. I can't figure out from the Rails guide docs by myself.
I have the following controllers in a rails 3.2 app:
/app/controllers/organizations_controller.rb (class OrganizationsController)
/app/controllers/organization/events_controller.rb (class Organization::EventsController)
then, in routes.rb
resources :organizations, path: 'org' do
resources :events
member do
get 'confirm'
end
end
end
running rake routes shows (only the relevant part for my issue):
organization_event GET /org/:organization_id/events/:id(.:format) events#show
The URL is ok, the route name is also ok, but the mapping to the "controller/action" is not right. Not as I want it to be. It should be organization/events#show.
What am I missing? How can I point this route to the correct controller. I chose to put the events_controller in the organization folder, because I already have another events_controller placed in the root of the controllers folder, and they have different purposes.
Thank you
namespace :organization do
resources :events
member do
get "confirm"
end
end
end
More info here.
EDIT
Sorry, didn't understand you correctly.
resources :organizations, path: 'org' do
resources :events, :module => "organization"
member do
get 'confirm'
end
end
end
Does that fit your needs?
I have a 2 level nesting objects that i need help with
My routes look like this to normalise the url abit. instead of having a url that looks like this /projects/1/tasks/3/comments/3.
resources :projects do
resources :tasks
end
resources :tasks do
resources :comments
end
Model has the 'has_many', belongs_to methods.
I can create comments under each task and display them under the tasks, but on the 'show' template of the comments i would like to display a link back to the tasks, which i get an error because the tasks controller is asking for a project_id?
How would this normally done when dealing with 2 level nesting?
I would do
resources :projects, :shallow => true do
resources :tasks do
resources :comments
end
end
Which is basically what you're doing except you can't generate a projects_task member path(ie projects/1/tasks/1) anymore they'd all just be task member paths(ie '/tasks/1').
Member paths include show, update, delete, edit
But the project_tasks collection paths(ie projects/1/tasks) would still be available.
Collection paths include index, create, new
comment paths wouldn't change. All comment paths would still include the task/:task_id prefix.
Checkout the resources documentation for more info on that (also more info on member and collection also on that page.)
But to actually solve your problem
You need to look up the project_id when you link back to the project_tasks index. So you would need to do
<%= link_to "Project Tasks Index", project_tasks_path(#task.project) %>
That way the Task#index knows where the parent project is. This is the solution for both implementations.
Check out the UrlFor documentation for more info on that.
If you want access to a #project variable in a Comment view
Then you just need to look up the project in the controller instead of at a view level. So basically
class CommentsController < ApplicationController
def show
#task = Task.find(params[:task_id])
#comment = #task.comments.find([:id])
#project = #task.project
end
end