I'm trying to get a simple route working
/agenda_items/5/feed
To do this, I have the following route setup
resources :agenda_items do
member do
get "/feed", to: "comments#feed"
end
end
In each of my controllers, I'm using CanCan to handle the authentication and it works fine, however on this one action I'm having an issue, which I'm pretty sure is down to railsnaming generation. When I runrake routes`, the route above is produced as
feed_agenda_item /agenda_items/:id/feed(.:format) agenda_items/:id#feed
As far as I can tell, CanCan is expecting the :id parameter, to actually be :agenda_item_id so as a result, my parent resource isn't being loaded.
Is there any way I can get rails to change this so that CanCan will work without me having to manually load and authorize the resource, or is there a way I can get CanCan to change what it's looking for on certain actions?
The problem is that your routes are wrong. You try to create a member action for agenda items which routes to the comments controller. If you want a feed of all the commments from a single agenda item you should do something like this:
resources :agenda_items do
resources :comments do
collection do
get :feed
end
end
end
You should now get the following when running rake routes:
feed_agenda_item_comments /agenda_items/:agenda_item_id/feed(.:format) comments#feed
Related
Issue: When a user (when signed in) creates an order, they are sent to the OrderControllers show page which can only be accessed if signed in by both the buyer and seller. From here they can edit/update their order, etc.
We also have guest_user, someone who isn't signed in, and for them I need a order confirmation in the browser (I'm using Devise gem)
I have created a method:
def order_confirmation
In the OrdersController.
Although, how can I nest this within orders so the page knows which order to show.
Is this possible to nest methods under its' own controllers, or should i just create a small controller only for order confirmations?
For example: example.com/orders/1/order-confirmation
Maybe there are better ways to go about this other than just nesting and creating a controller?
I Tried:
resources :orders do
collection do
get 'order_confirmation'
end
end
With:
def order_confirmation
#order = Order.all.find(params[:id])
end
But it won't work how i want i t seems.
The rake routes gives me:
order_confirmation_orders GET /orders/order_confirmation(.:format)
How can i get?:
order_order_confirmation_orders GET /orders/id/order_confirmation(.:format)
I was able to figure this out from the help of this SO post:
Rails: Custom nested controller actions
By using:
resources :orders do
get 'order_confirmation', :on => :member
end
This creates:
order_confirmation_order GET /orders/:id/order_confirmation(.:format) orders#order_confirmation
I created a CRUD using the scaffold .
rails g scaffold intermediate_level/memory_game
And then I created the method Play, but when I call the method play an error is returned.
http://localhost:3000/intermediate_level/memory_game/play?id=1
Couldn't find IntermediateLevel::MemoryGame with 'id'=play
# Use callbacks to share common setup or constraints between actions.
def set_intermediate_level_memory_game
#intermediate_level_memory_game = IntermediateLevel::MemoryGame.find(params[:id])
end
def play {
#intermediate_level_memory_game = IntermediateLevel::MemoryGame.find(params[:id])
}
My routes.file
namespace :intermediate_level do
resources :memory_game
get 'memory_game/play'
end
Your custom get 'memory_game/play should come before resources :memory_game. Rails evaluates routes in the order in which they are listed in the routes.rb file, with the routes closest to the top of the file receiving the highest priority.
With your given routes information:
namespace :intermediate_level do
resources :memory_game
get 'memory_game/play'
end
You have these two routes:
GET /intermediate_level/memory_game/:id(.:format) intermediate_level/memory_game#show
and
GET /intermediate_level/memory_game/play(.:format) intermediate_level/memory_game#play
When you make this request:
http://localhost:3000/intermediate_level/memory_game/play?id=1
it is matched by both of those routes and as you defined: resources :memory_game before get 'memory_game/play' in your routes.rb file, so the first one (GET /intermediate_level/memory_game/:id) comes into action as that has higher priority, (because Routes have priority defined by the order of appearance of the routes in the config/routes.rb file) and then it tries to find the memory game with id param which in that case is play but fails to do so (as you don't have any memory game where id=play) and fails with the error message:
Couldn't find IntermediateLevel::MemoryGame with 'id'=play
One quick way to get around this issue is to reorder your routes like this:
namespace :intermediate_level do
get 'memory_game/play'
resources :memory_game
end
Then, your request url http://localhost:3000/intermediate_level/memory_game/play?id=1 will be served by GET /intermediate_level/memory_game/play(.:format) intermediate_level/memory_game#play route which is what you want.
I receive an error when my route is listed as such:
resources :coupons
get 'coupons/redeem_coupon', to: 'coupons#redeem_coupon', as: 'redeem_coupon'
The error is:
ActiveRecord::RecordNotFound - Couldn't find Coupon with 'id'=redeem_coupon:
When I reverse the order to:
get 'coupons/redeem_coupon', to: 'coupons#redeem_coupon', as: 'redeem_coupon'
resources :coupons
It works fine. I understand that resources creates these routes
GET /coupons
GET /coupons/new
POST /coupons
GET /coupons/:id
GET /coupons/:id/edit
PATCH/PUT /coupons/:id
DELETE /coupons/:id
Is listing my custom route first, more specific or overriding the other route? Why does the order matter?
The error you're getting is because rails tries to match routes starting from the top down. If you're trying to add a custom route to an existing resource, the easier way is to do this. collection is if you want to use it on the group, member is if you want to add a custom route to an individual resource.
resources :coupons do
collection do
get 'redeem_coupon'
end
end
By listing your custom route first, you are overriding the other route. When rails gets a request, it simply starts from the top of your routes.rb file and goes with whichever route matches first.
I am using rails 4.1 with Casein CMS: https://github.com/russellquinn/casein
I have setup a Post Model, view and controllers within casein, but I would like to access the Posts outside of casein, possibly under another route called blog
I have tried and tried reworking my routes and controllers, and have an array of errors to list. Someone here might know just the trick to get this working, and was hoping some could help me, or at least explain to me what should be happening or what I might be doing wrong.
What Casein adds to the routes is this:
#Casein routes
namespace :casein do
resources :posts
end
And I'd like to match the index and show actions to => /blog. How might I write this correctly in my routes.rb.
My controller, I have basically extracted the actions from the Casein's PostsController, and along with including the Casein Module have tried to simple list all the posts.
Here is what my blogs_controller's index action looks like:
class BlogsController < ApplicationController
module Casein
def index
#casein_page_title = 'Posts'
#posts = Post.order(sort_order(:title)).paginate :page => params[:page]
end
end
end
By the end I'd also like to take blogs to blog, but I think can take it from there, but if anyone has any suggestions, that would be much appreciated.
You might be asking for this, but your question is not very clear.
If you want to have the following routes and use the same controller for each.
Prefix Verb URI Pattern Controller#Action
casein_posts GET /casein/posts(.:format) casein/posts#index
POST /casein/posts(.:format) casein/posts#create
new_casein_post GET /casein/posts/new(.:format) casein/posts#new
edit_casein_post GET /casein/posts/:id/edit(.:format) casein/posts#edit
casein_post GET /casein/posts/:id(.:format) casein/posts#show
PATCH /casein/posts/:id(.:format) casein/posts#update
PUT /casein/posts/:id(.:format) casein/posts#update
DELETE /casein/posts/:id(.:format) casein/posts#destroy
blog GET /blog(.:format) casein/posts#index
GET /blog/:id(.:format) casein/posts#show
then your config/routes.rb file should contain
namespace :casein do
resources :posts
end
get '/blog', to: 'casein/posts#index'
get '/blog/:id', to: 'casein/posts#show'
And you need your controller to be app/controllers/casein/posts_controller.rb
But I'd really strongly encourage you to use 2 different controllers, and a concern for the shared methods
I have the following routes in my config/routes.rb file:
resources :employees do
get 'dashboard'
get 'orientation'
end
employees refers to a regular resource handling the standard RESTful actions. dashboard and orientation are what I currently refer to "custom actions" which act on Employee instances. I apologize if I have my terminology mixed up and dashboard and orientation are really something else. These custom actions respond to URLs as follows:
http://myhost/employees/1/dashboard
i.e. They're "member" actions much like show, edit etc.
Anyway, this all works well enough. Regular actions such as show on EmployeesController obtain the ID of the associated Employee through params[:id]. However, with this current structure, dashboard and orientation have to use params[:employee_id] instead. This is not too difficult to deal with, but does lead to some additional code complexity as my regular before_filters which expect params[:id] don't work for these two actions.
How do I have the routing system populate params[:id] with the ID for these custom actions in the same way as show etc.? I've tried various approaches with member instead of get for these actions but haven't got anything to work the way I would like yet. This app is built using Ruby on Rails 3.2.
This might help you:
resources :employees do
member do
get 'dashboard'
get 'orientation'
end
end
and the above will generate routes like below, and then you will be able to use params[:id] in your EmployeesController.
dashboard_employee GET /employees/:id/dashboard(.:format) employees#dashboard
orientation_employee GET /employees/:id/orientation(.:format) employees#orientation
I haven't tested this example, but you can set the resourceful paths explicitly.
Something like this might work:
resources :employees, path: '/employees/:id' do
get 'dashboard', path: '/dashboard'
get 'orientation', path: '/orientation'
end