Set the scope based on parent resource while using concerns - ruby-on-rails

I am curious, is there any way to set the scope for nested resources based on parent resource while using concerns in Rails?
concern :commentable do
scope module: ??? do # either :posts or :messages
resources :comments
end
end
resources :messages, concerns: :commentable
resources :posts, concerns: :commentable
I want my routes to be like these:
Path Controller
/messages/:message_id/comments/:id messages/comments#show
/posts/:post_id/comments/:id posts/comments#show
but I also want to use concerns in order to reduce duplication.
Thanks!

Turns out method concerns can take a hash of options.
concern :commentable do |options|
scope module: options[:module] do
resources :comments
end
end
resources :messages do
concerns :commentable, module: :messages
end
resources :posts do
concerns :commentable, module: :posts
end

I started with your solution using an options hash but it turns out I really need this pattern a lot so I worked out another solution for that specific case :
concern :archivable do
scope module: parent_resource.plural do
resources :archiving, only: [:create, :destroy]
end
end
...
resources :messages , concerns: [ :archivable ]
resources :users , concerns: [ :archivable ]

You can use Rails Polymorphism to fit this situation where a comment can belong_to any other model as well...post,video,user etc
Wonderful Railscasts.....which is worth watching.

Related

How would I add /api to these routes

So I have bunch of routes that I can access through like localhost:3000/posts localhost:3000/users
config/routes.rb looks like this
resources :posts do
resources :comments, shallow: true do
delete :destroy_all, on: :collection
end
resources :images, shallow: true
end
resources :comments, only: [:new]
resources :users
root 'welcome#index'
How can I modify it so I also have normal access and also API access to them such as
http://localhost:3000/api/posts
http://localhost:3000/api/users/new and such
If you're building an API, you should consider versioning, thus separating your JSON API from your HTML interface; this means pulling your JSON API out into separate controllers that exist in a versioned API namespace.
namespace :api do
namespace :v1 do
resources :posts do
resource :comments, shallow: true do
delete :destroy_all, on: collection
end
end
resources :comments
resources :users
end
end
resources :posts do
resource :comments, shallow: true do
delete :destroy_all, on: collection
end
end
resources :comments
resources :users
These controllers would exist in app/controllers/api/v1.
Your route would now look like:
/api/v1/posts
Versioning your APIs is considered good practice because you want your API to remain consistent.
There's a great RailsCast on API versioning:
http://railscasts.com/episodes/350-rest-api-versioning?view=asciicast

Avoid deep routing in Rails yet still nest when needed

I've been deep nesting my resources and now discover that this should be avoided. Shallow nesting seems to be the answer but I'm struggling on how to properly correct the second level deep nesting. Let me show you my routes file as I think that will make it clearer(I'm using Rails 4):
OLD:
resources :members do
resources :emails
resources :events do
resources :items
end
end
NEW so far:
resources :members, shallow: true do
resources :emails
resources :events
end
My issue is I don't understand where to put the :items now? I thought it should be nested under the :events for the :index, :new, and :create actions?
What am I missing, I'm sure its something silly that I'm just not getting yet, please excuse my ignorance and I think you in advance for any help!!!
Mark
All you need to do is, update the routes as below:
resources :members, shallow: true do
resources :emails
resources :events, shallow: true do
resources :items
end
end
This will create shallow routes for items. Only for :index, :new, and :create actions you would get nested routes prefixed with /events/:event_id.

Appropriately nest resources in routes.rb

My application has deeply nested resources, but after reading http://guides.rubyonrails.org/routing.html#shallow-nesting, I've realized it's not wise to have these deeply nested resources. Here is the situation my routes are currently in.
resources :assortments do
resources :comments do
member do
post :like
post :unlike
end
end
member do
post :like
post :unlike
end
resources :designs do
resources :comments do
member do
post :like
post :unlike
end
end
member do
post :like
post :unlike
get :likes
end
end
end
I want to know the proper way to organize this structure to make it less confusing and "proper". Or is what I have ok?
Thanks.
you could just specify the shallow: true on your top resources :assortments and should build shallow routes for all the nested routes automatically.
I also would move the :comments resource into a concern, kind of like that
concern :commentable do
resources :comments do
member do
:like
:unlike
end
end
end
resources :assortments, shallow: true do
concerns :commentable
...
resources :designs do
concerns :commentable
end
end
And on an unrelated topic, i'd consider making the LikesController to have a centralized likes handling resource, might save one some headache when you have polymoriphic liking thing going on.

rails routing nested resources duplicate

I want to support:
POST images/1/comments/2/like
and
POST comments/2/like
They both point to same resources with same action. How can I do that in rails route file?
resources :images do
resources :comments do
member do
post 'like'
end
end
end
This will work for
POST images/1/comments/2/like
but how can I also for when I don't specify the images/1 part?
You can make it more beautiful actually. According to http://ruby-journal.com/how-to-dry-your-rails-routes/, this also works:
comments = Proc.new do
member do
post 'like'
end
end
resources :comments, &comments
resources :images do
comments.call
end
and in Rails 4 you could use concerns
concern :comments_concern do
member do
post 'like'
end
end
resources :comments, concerns: :comments_concern
resources :images, concerns: :comments_concern do
#do more stuff here
end
I didn't test this, but it might help. Have a look at the website mentioned. Good luck
-frbl
I would consider reworking which RESTful routes for Comment you're nesting, and which you're not. I'm assuming your models look something like this:
# app/models/image.rb
class Image < ActiveRecord::Base
has_many :comments
end
# app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :image
end
Because your Image and Comment models possess a one-to-many relationship, I can see why you'd think to nest the comments resource route within the images one. However, of all the CRUD actions in comments_controller.rb, only create actually requires that a parent image ID be explicitly passed in. From a RESTful perspective, only the new and create actions require that a image_id is passed to the action. The edit, update, delete, and like actions can all take place independently of the parent image.
Consider the alternative routing schematic instead:
# config/routes.rb
resources :images do
resources :comments, :only => [:index, :new, :create]
end
resources :comments, :only => [:show, :edit, :update, :destroy] do
member do
post 'like'
end
end
Now, only the comment actions that are explicitly depended on a parent ID are actually nested within the images routes. The remainder of the comment actions are directly routed to the comments controller without passing in the parent ID. Your routes are no longer duplicated, and each action will have exactly one route declared for it.
simply add resources :images it may work
Not sure there is a much more beautiful way than repeating this below:
resources :comments do
member do
post 'like'
end
end
Like so:
resources :images do
resources :comments do
member do
post 'like'
end
end
end
resources :comments do
member do
post 'like'
end
end

Is there any way to simplify nested, namespaced resources?

Is there any less redundant way to do this?
resources :tournaments do
resources :commitments, controller: "tournaments/commitments"
resources :constraints, controller: "tournaments/constraints"
resources :entries, controller: "tournaments/entries"
resources :buildings, controller: "tournaments/buildings" do
resources :rooms, controller: "tournaments/buildings/rooms"
end
end
This is the convention for nested resources. Here all of the controllers are still in the app/controllers directory.
resources :tournaments do
resources :commitments
resources :constraints
resources :entries
resources :buildings do
resources :rooms
end
end
You generally only use directories for your controllers when you need namespacing, like:
namespace :admin do
resources :users
root :to=>"dashboards#admin"
end
#/admin/users

Resources