Recursive Rails Nested Resources

How to render nested resources as json in rails if each nested resource could also have resource nested under it?

If you can use custom methods for preparing json, this is how you can do that:

class List
has_one :item

def custom_json
json = to_json
json[:item] = item.custom_json
json
end
end

class Item
has_many :items # add other options

def custom_json
json = to_json.merge(children: [])
items.each { |item| json[:children] << item.custom_json }
json
end
end

Note: here items refer to the relation you have in Item class for its child items.

And in your controller, you could do

format.json { render json: @list.custom_json }

This would result in json structure:

{ list_attr: value, list_attr_2: value, item: { item_attr: value, children: [{ child_item_attr: value, ... }] } }

Let me know if it helps.

Simple Acts_as_tree with nested_resources

A)

If you have a solution for the routing and the only problem with it is that you're concerned about duplicate content issues, you could consider adding <link rel="canonical" href="..."> to the pages generated from those requests. It's not bulletproof though, as Google considers it a suggestion.

Not sure if the route globbers solution would take care of generating the URLs with parent IDs though.

B)

You don't need the parent IDs to perform the routing, correct? You just want to include them in the URLs and route those requests the same as if using the URLs like example.com/chapter1, correct?

If you'd consider a solution that's not purely at the Rails level, what about rewriting the URLs on those requests so that /:parent_id/:parent_id/:id becomes /:id before Rails processes it? That would be easier if there was a static prefix, like /articles/:parent_id/:parent_id/:id.

I imagine you'd need to write some helpers to generate the URLs with parent IDs for linking to those resources.

Duplicate Content

Either way, you'll need to generate URLs that include the parent IDs, so duplicate content issues probably aren't too likely if you only link to those resources using those URLs.

Recursion for nested list generation

I am not too sure everything that your code is doing, but it seems you want something like this

def process_topics topics_list
topics_list.each do |t|
# do something
process_topics children_of_topic(topic_list, t)
# or do something
end
end

def children_of_topic(topic_list, topic)
topic_list.select(|t| t.id == topic.parent_id)
end

It might be good to simplify your example down to something like this then add stuff in as you go.

Your very first call

get_nested_list(topics_list, topics_list.first)

Is not making sense. You want to cycle through each topic in your list and get the children of that topic and then recurse on that.

Rails nested resources and :path = /

A couple ways of doing this...

1) Will give you routes like /:user_id/:id (which you wanted)

match '/:user_id/edit', :to => 'users#edit', :as => :edit_user
resources :users, :except => [:edit], :path => "/" do
resources :projects, :path => "/"
end

2) Will give you routes like /:user_id/projects/:id (which it seems like you're avoiding)

resources :users, :path => "/" do
resources :projects
end

I personally prefer #2 since it is cleaner and provides more knowledge about the route at a glance.

Rails 6 - Issue with nested resources in a namespace

If you do rails routes, you'll get (amongst other things):

                                 Prefix Verb   URI Pattern                                                        Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy

As you can see, user_profiles is not nested under the users namespace. Rails, therefore, is expecting:

module AccountManagementPages
class UserProfilesController < ApplicationController

...

end
end

If you do:

constraints(AccountManagement) do
namespace :account_management_pages, path: '' do
root to: 'users#new', as: :registration
resources :users, except: %w[index], path_names: { new: 'register' } do
scope module: :users do
resources :user_profiles
end
end
end
end

...and then rails routes, you get (amongst other things):

                                         Prefix Verb   URI Pattern                                                Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/users/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/users/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy

...and user_profiles will be nested under users. And you should be able to use:

module AccountManagementPages
module Users
class UserProfilesController < ApplicationController

...

end
end
end

Finding the parent object in a nested resource relationship?

Routing will not help you as this is only meant to be used the other way around.
What you can do is aliasing the relationship with :parent:


class Task
belongs_to :project
alias :project :parent
end

And then use this relationship to detect if a parent object is available:


if object.respond_to?(:parent)
# do something
end

Moreover, you can use polymorphic routes if the routes are set up correctly:


polymorphic_url([object.parent, object])


Related Topics



Leave a reply



Submit