Rails 3 Nested Routing - ruby-on-rails

I have very interesting scenario:
I've specified two controllers, one for global events and another another once for company specific events. In routes, it is specified like this:
resources :companies do
resources :events
end
resources: events
Running rake routes I can see the routes being generated:
events GET /events(.:format) events#index
company_events GET /companies/:company_id/events(.:format) events#index
Both paths seem to route to the same controller (the global one)...
I have the second controller under controller/companies that goes something like this:
class Companies::EventsController < ApplicationController
# stuff
end
It never routes in that controller above, no matter whether I use company_evens_path(#company). always goes to the other one.
It used to work in rails 2.3 for me, I'm currently using 3.2

Ok as stated above, I would recommend doing something like this:
def index
if params[:company_id]
#events = Company.find(params[:company_id]).events
else
#events = Events.all
end
end
although if you need to you can specify a controller:
resources :companies do
resources :events, :controller => "companies/events"
end
resources: events
and just create a companies folder inside your controllers folder to put your Companies::EventsController inside

Related

Create views in resource in Rails

I am a beginner working with Rails: I have this routes.rb:
Rails.application.routes.draw do
resources :requirements
root "department#index"
get "department/about"
end
How can I create a view that has a path like requirements/major?
Thank you so much!
You can extend resources and add custom actions, like this:
resources :requirements do
collection do
get :major
end
end
You'll need an action in the RequirementsController that matches, e.g.
class RequirementsController < ApplicationController
def major
# set up whatever resource 'major' corresponds to
end
...
end
That's at least one way of doing it. You could also have a controller that directly supports the nested 'major' resource, which would be similar to above - just with a controller: 'name of controller' directive inline..
It'd probably pay to get your head around the "Rails Routing from the Outside In" guide: https://guides.rubyonrails.org/routing.html

New action not being reached in my Ruby app

I'm just learning Ruby on Rails and building a fairly simple app that stores info to a rake generated db. I'm trying to add a new action to the controller but I can't trigger it. There's a before_action getting triggered which shouldn't be.
class GamesController < ApplicationController
before_action :set_entry, only: %i[ show edit update destroy ]
before_action :authenticate_user!
def index
end
def analyse
#The function here doesnt matter, its not reaching it because its hitting the set_entry instead
puts 'howdy'
end
private
def set_entry
#entry = Entry.find(params[:id])
end
end
The error I'm hitting is Couldn't find Game with 'id'=analyse", highlighting the set_entry action, which to my understanding should only be running with the show, edit, update, and destroy actions (which are also in the full controller and running fine). There are other actions in the controller (such as create and new) which don't seem to trigger that set_entry and are running just fine as expected. For example, linking to the new path takes me to /entry/new, while linking to an edit path takes me to /entry/:id/edit, which is all fine. But it keeps linking my new analyse action trying for entry/:id/analyse when I want it to go to entry/analyse.
My button to trigger it is simply:
<%= link_to "Analyse", analyse_path %>
Which is in a navbar in my application.html.erb
And here's my routes.rb:
Rails.application.routes.draw do
resources :entry
devise_for :users
resources :users
root to: "entry#index"
get 'entry/index'
get 'entry/analyse', as: 'analyse'
end
The path /entry/analyse is matched two routes:
entry#show action in resources :entry
entry#analyse action in get 'entry/analyse', as: 'analyse'
Because the route matching is interpreted through config/routes.rb in order, and resources :entry is the first route the path is matched. At the result, entry#show action will handle the requests from /entry/analyse.
The solution is simple, just switch the order of resources :entry and get 'entry/analyse', as: 'analyse' in config/routes.rb. For example:
Rails.application.routes.draw do
get 'entry/analyse', as: 'analyse' # <- to here
resources :entry
devise_for :users
resources :users
root to: "entry#index"
get 'entry/index'
# from here ...
end
Move all of your resources to the end of your route configuration. I am not sure why its getting tripped up but it seems something within your routes is matching analyse to your entry resource and routes within rails are matched in order. All custom routes really should come first to prevent something like a generic route catching your expected action.
Best practices also state your root to: should be at the top of the configuration since it is your most popular route generally in an application.

Getting 'Unknown action in controller'

I'm getting this error :
"The action 'create' could not be found for ObjectController"
I know it should be obvious but I'm missing something, that's my controller :
class ObjectController < ApplicationController
def index
end
def create
end
end
And that is my routes :
Rails.application.routes.draw do
get 'object/index'
get 'object/create'
match ':controller(/:action(/:id))', :via => :get
resources :objets
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'object#index'
You probably want to scrap those routes and try something simpler like
resources :objects, only: [:get, :create, :show]
Then use
$ rake routes
To make sure your routes are as the should be. You will want a POST route to /objects to create a new object etc..
Ok that one was dumb, actually I had two directories and I wasn't modifying the right one, sorry about that...
Your routes could be greatly improved:
#config/routes.rb
Rails.application.routes.draw do
root 'objects#index'
resources :objects
--
Next, the "standard" way to achieve what you're looking for is to use the new action; IE not the "create" action. If you wanted to use the create path name (instead of new), you'll be able to define it in the path_names argument:
#config/routes
resources :objects, path_names: { new: "create", create: "create" } #-> url.com/objects/create
To understand why you should be using new instead of create, you should look up resourceful routing, and how it pertains to object orientated programming.
Finally, your controller should be named in the plural:
#app/controllers/objects_controller.rb
class ObjectsController < ApplicationController
...
end
Whilst you can call it whatever you like, Rails defaults to plural controller names, singular model names.

How can i create the following route

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

Basic Nested Routes (how to have nested routes and not nested routes simultaneously)

I have routes like this:
resources :users do
resources :projects
end
I would like to be able to access routes like this:
/users/1/projects/1
and
/projects/1
Is this possible? How would I set this up? I'm having and issue in my app where we would like to have users able to see both their own projects via /users/:id/projects/:id but also on other pages we'd like to just see all the projects created, like this /projects or a project and an id, like this /projects/:id. I feel like I'm missing something, should I just get rid of the nested routes? Or can I have both.
You can have both. Just add resources :projects to your routes.rb.
Then, in your ProjectsController you will have to do:
def index
if params[:user_id]
#projects = User.find(params[:user_id]).projects
else
#projects = current_user.projects
end
end
I'm assuming your authentication system provides with current_user method for your controllers (as most of them do)
You can surely have both ways depending on your needs.
resources :users do
resources :projects
end
resources :projects
Will give you your url in /users/:user_id/projects/:id and in /projects/:id as well.
You can check in your projects controller whether the params[:user_id] exists or not and take necessary action.

Resources