Selecting model based off of route in Rails - ruby-on-rails

I have a polymorphic model Discussion. It can be applied to Specialty model and Program model. My routes are set up as:
resources :programs, :only => :show do
resources :discussions, :only => [:show, :create, :destroy, :new]
end
resources :specialties do
resources :discussions, :only => [:show, :create, :destroy, :new]
end
So, new discussions are made either like:
/specialties/yyyyy/discussions/new
/programs/yyyyyy/discussions/new
The problem is in my discussions_controller.rb file. I have the function:
def new
#object = xxxxx.find(params[:id])
end
How do I choose the appropriate model for the form (eg. to replace 'xxxxx') and for determining the discussionable_type. I would assume I could parse the URL, but it doesn't seem clean. Any ideas?

Given your routes, you should either have params[:program_id] or params[:specialty_id] (or alike).
This will tell you what to use.

Related

How to name nested routes parameters in Rails?

I've the following nested route:
resources :carts, only: [:show, :update, :create], param: :token do
resources :items, :controller => :cartitems, except: [:new, :edit], param: :product_id
end
This generates
GET /api/merchants/:merchant_id/carts/:cart_token/items(.:format) cartitems#index
POST /api/merchants/:merchant_id/carts/:cart_token/items(.:format) cartitems#create
GET /api/merchants/:merchant_id/carts/:cart_token/items/:product_id(.:format) cartitems#show
PATCH /api/merchants/:merchant_id/carts/:cart_token/items/:product_id(.:format) cartitems#update
PUT /api/merchants/:merchant_id/carts/:cart_token/items/:product_id(.:format) cartitems#update
DELETE /api/merchants/:merchant_id/carts/:cart_token/items/:product_id(.:format) cartitems#destroy
...
I want to remove the controller part in the resources :items parameters. That means: I want to rename the :cart_token parameter to :token. Just like:
GET /api/merchants/:merchant_id/carts/:token/items(.:format) cartitems#index
POST /api/merchants/:merchant_id/carts/:token/items(.:format) cartitems#create
GET /api/merchants/:merchant_id/carts/:token/items/:product_id(.:format) cartitems#show
PATCH /api/merchants/:merchant_id/carts/:token/items/:product_id(.:format) cartitems#update
PUT /api/merchants/:merchant_id/carts/:token/items/:product_id(.:format) cartitems#update
DELETE /api/merchants/:merchant_id/carts/:token/items/:product_id(.:format) cartitems#destroy
...
How can this be achieved?
Don't know if it's the best way to do that, but I got the routes you expected there by:
scope 'api/mechantes/:merchant_id/carts/:token' do
resources :items, :controller => :cartitems, except: [:new, :edit], param: :product_id
end
Hope this can helps. Good luck!

How to create a custom route inside resource without overwrite path

I’ve this on routes.rb
resources :questions, except: [:show] do
get '/resource/:subject/:id', to: 'resource#show', as: "resource", param: [:name, :id]
It says that:
Invalid route name, already in use: ‘resource' You may have defined two routes with the same name using the :as option, or you may be overriding a route already defined by a resource with the same naming
I know that resources create two routes with the same path, show and destroy both uses resource_path, how does it is being created internally? and how i can generate my route for show wihtout overwrite the one in destroy?
A good way to eliminate routes unneeded is by specifying the :only option
resources :user, :only => [:edit]
instead of
resources :user, :except => [:new, :create, :edit, :update, :show, :destroy]
It seems to me that you could take out show and then define the route that you want separately. See if this works:
resources :questions, except: :show
get '/resource/:subject/:id',
to: 'resource#show',
as: "resource", # This is where the error is.
param: [:name, :id]
EDIT: Ah, yes. The :as parameter needs a different name. This will work:
resources :questions, except: :show
get '/resource/:subject/:id',
to: 'resource#show',
as: "resource_show",
param: [:name, :id]

Prettier routes for Wicked Wizard

I'm using Wicked to build an object in steps, and would like to clean up my routes a little bit.
Currently, my router looks like this:
resources :surveys, only: [:new, :create], path: 'feedback' do
resources :steps, only: [:show, :update], controller: 'survey/steps'
end
So my routes end up being:
GET '/feedback/new' => 'surveys#new'
POST '/feedback/create' => 'surveys#create'
GET '/feedback/:id/steps/step1' => 'survey/steps#show'
PUT '/feedback/:id/steps/step1' => 'survey/steps#update'
Ideally, I'd like to remove both the survey id and the 'steps' name from my routes, so that they look like this:
GET /feedback => 'surveys#new'
POST /feedback => 'surveys#create'
GET /feedback/step1 => 'survey/steps#show'
PUT /feedback/step1 => 'survey/steps#update'
...
Any simple way to do this?
resource :steps #as singular
resources :surveys, only: [:new, :create], path: 'feedback' do
resource :steps, only: [:show, :update], controller: 'survey/steps'
end

Polymorphic Comments in both nested resource and simple resource ruby on rails 4

I have following relationship routes:
resources :courses, only: [:index, :show] do
resources :enrols, only: [:new, :create]
resources :lectures, only: [:show]
end
resources :code_casts, :path => 'casts', :as => 'casts', only: [:index, :show]
resources :blogs, :path => 'blog', :as => 'blog', only: [:index, :show] do
resources :blog_votes, only: [:create, :destroy]
end
I want polymorphic comments in courses, lectures, code_casts and blog.
Problem is lecture has a parent of course so route will be course/course_id/lecture/id and blog path will blog/id where comments will have different show pages.
If I understand the problem correctly, there is nothing special about deeply nested resources. So you might need something like this
# routes.rb
concern :commentable do
resources :comments
end
resources :courses, only: [:index, :show] do
resources :enrols, only: [:new, :create]
resources :lectures, only: [:show], concerns: [:commentable]
end
resources :code_casts, :path => 'casts', :as => 'casts', only: [:index, :show]
resources :blogs, :path => 'blog', :as => 'blog', only: [:index, :show], concerns: [:commentable] do
resources :blog_votes, only: [:create, :destroy]
end
This will create nested comments resources for lectures and blogs.
Than you need to differentiate the path in a comments controller
# comments_controller
def create
Comment.create(commentable: commentable, other_params...) # assuming you have `commentable` polymorphic belongs_to
end
# a little more ugly than Ryan suggests
def commentable
if request.path.include?('blog') # be careful. any path with 'blog' in it will match
Blog.find(params[:id])
elsif params[:course_id] && request.path.include?('lecture')
Course.find(params[:course_id).leactures.find(params[:id]) # assuming Course has_many lectures
else
fail 'unnable to determine commentable type'
end
end
All 'magic' is in commentable method, where youare checking the path and determine which commentable object to pick. I use similar approach, but this exact code is written by memory without testing. Hopefully you've got the idea.

How do I make my UsersController work nicely with current_user?

Users can view and edit account information in my app using UsersController
This controller only ever shows information about the current user.
I want to adjust the routes so that:
get /account accesses UsersController#show, user_id is retrieved from a current_user variable
get /account/edit similarly accesses UsersController#edit
put /account/ will hit UsersController#update, again using current_user instead of an ID
Basically I want to refer to UsersController as 'account' in my URLs and I don't want to use IDs because I'm always just using the current user. I also don't want URLs like /users/1 to function at all.
How can I achieve this?
I think that you are talking about singular resources.
http://guides.rubyonrails.org/routing.html#singular-resources
# Not sure if you need this
resource :users, :only => [:index, :create, :destroy]
# This is what you are looking for
resource :user, :as => :account, :only => [:show, :edit, :update]
Update
Since you need "/account" instead of "/user", you should do
resource :account, :controller => :users, :only => [:show, :edit, :update]
Given your setup, you probably have something like this in your routes.rb:
resources :users
You should be able to just change it to this:
resources :users, :as => "account"
I haven't tested it but this should work. For more info, check the Rails guides on Routing.
Two ways to do it:
In your route.rb:
resources :users, :as=>'accounts'
In your route.rb, remove resources :users and add:
match '/account'=>'users#show'
match '/account/edit'=>'users#edit'
match '/account/'=>'users#update'

Resources